mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-11-04 00:33:12 +00:00
223 lines
7.6 KiB
Dart
223 lines
7.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter_hbb/common/widgets/request_approval_menu.dart';
|
|
import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart'
|
|
as mod_menu;
|
|
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
|
|
|
const connectionTypes = [
|
|
'Connect',
|
|
'Transfer file',
|
|
'View camera',
|
|
'Terminal',
|
|
'Terminal (Run as administrator)',
|
|
'TCP tunneling',
|
|
'RDP',
|
|
];
|
|
|
|
Future<void> openMenu(WidgetTester tester, List<String> actions,
|
|
{ThemeData? theme, EdgeInsets? padding, bool includeRelay = false}) async {
|
|
MenuEntryButton<String> entry(String title, {bool requestApproval = false}) =>
|
|
MenuEntryButton<String>(
|
|
childBuilder: (style) => Text(title, style: style),
|
|
proc: () =>
|
|
actions.add(requestApproval ? '$title:request-approval' : title),
|
|
padding: padding,
|
|
dismissOnClicked: true,
|
|
);
|
|
|
|
await tester.pumpWidget(MaterialApp(
|
|
theme: theme,
|
|
home: Scaffold(
|
|
body: Builder(builder: (context) {
|
|
return TextButton(
|
|
onPressed: () => mod_menu.showMenu<String>(
|
|
context: context,
|
|
position: const RelativeRect.fromLTRB(20, 20, 780, 580),
|
|
items: [
|
|
entry('Connect'),
|
|
entry('Transfer file'),
|
|
entry('View camera'),
|
|
MenuEntryButton<String>(
|
|
childBuilder: (style) => Row(children: [
|
|
Text('RDP', style: style),
|
|
const Spacer(),
|
|
IconButton(
|
|
icon: const Icon(Icons.edit),
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
actions.add('Edit RDP');
|
|
},
|
|
),
|
|
]),
|
|
proc: () => actions.add('RDP'),
|
|
padding: padding,
|
|
dismissOnClicked: true,
|
|
),
|
|
RequestApprovalMenu(
|
|
title: 'Request approval',
|
|
padding: padding,
|
|
entries: [
|
|
for (final title in connectionTypes)
|
|
entry(title, requestApproval: true),
|
|
],
|
|
),
|
|
if (includeRelay)
|
|
MenuEntrySwitchSync<String>(
|
|
switchType: SwitchType.scheckbox,
|
|
text: 'Always connect via relay',
|
|
currentValue: false,
|
|
setter: (_) async {},
|
|
padding: padding,
|
|
dismissOnClicked: true,
|
|
),
|
|
entry('Rename'),
|
|
]
|
|
.expand((entry) => entry.build(context,
|
|
const MenuConfig(commonColor: Colors.black, height: 20)))
|
|
.toList(),
|
|
),
|
|
child: const Text('Open menu'),
|
|
);
|
|
}),
|
|
),
|
|
));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.text('Open menu'));
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('tapping outside the approval submenu closes both menus',
|
|
(tester) async {
|
|
final actions = <String>[];
|
|
await openMenu(tester, actions);
|
|
await tester.tap(find.text('Request approval'));
|
|
await tester.pumpAndSettle();
|
|
await tester.tapAt(const Offset(2, 2));
|
|
await tester.pumpAndSettle();
|
|
expect(actions, isEmpty);
|
|
expect(find.text('Request approval'), findsNothing);
|
|
expect(find.text('Rename'), findsNothing);
|
|
expect(find.text('Open menu'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('approval text and arrow align with normal menu items',
|
|
(tester) async {
|
|
for (final (theme, padding) in [
|
|
(ThemeData(), null),
|
|
(
|
|
ThemeData(
|
|
useMaterial3: false,
|
|
platform: TargetPlatform.windows,
|
|
visualDensity: VisualDensity.compact),
|
|
const EdgeInsets.only(left: 12, right: 3)
|
|
),
|
|
(
|
|
ThemeData(useMaterial3: false),
|
|
const EdgeInsets.symmetric(horizontal: 12)
|
|
),
|
|
(
|
|
ThemeData(
|
|
useMaterial3: false,
|
|
textButtonTheme: TextButtonThemeData(
|
|
style: TextButton.styleFrom(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20)),
|
|
)),
|
|
null
|
|
),
|
|
]) {
|
|
await openMenu(tester, [],
|
|
theme: theme, padding: padding, includeRelay: true);
|
|
expect(tester.getTopLeft(find.text('Request approval')).dx,
|
|
tester.getTopLeft(find.text('Connect')).dx);
|
|
expect(tester.getCenter(find.byIcon(Icons.keyboard_arrow_right)).dx,
|
|
closeTo(tester.getCenter(find.byType(Checkbox)).dx, 0.01));
|
|
await tester.tap(find.text('Rename'));
|
|
await tester.pumpAndSettle();
|
|
}
|
|
});
|
|
|
|
testWidgets('normal connections and RDP editing remain direct actions',
|
|
(tester) async {
|
|
for (final title in [
|
|
'Connect',
|
|
'Transfer file',
|
|
'View camera',
|
|
'RDP',
|
|
'Edit RDP'
|
|
]) {
|
|
final actions = <String>[];
|
|
await openMenu(tester, actions);
|
|
expect(find.byIcon(Icons.keyboard_arrow_right), findsOneWidget);
|
|
final left = tester.getTopLeft(find.text('Rename')).dx;
|
|
for (final row in ['Connect', 'Transfer file', 'View camera', 'RDP']) {
|
|
expect(tester.getTopLeft(find.text(row)).dx, left);
|
|
}
|
|
await tester.tap(
|
|
title == 'Edit RDP' ? find.byIcon(Icons.edit) : find.text(title));
|
|
await tester.pumpAndSettle();
|
|
expect(actions, [title]);
|
|
expect(find.text('Request approval'), findsNothing);
|
|
expect(find.text('Rename'), findsNothing);
|
|
}
|
|
});
|
|
|
|
testWidgets(
|
|
'one approval menu offers all connection types and closes both menus',
|
|
(tester) async {
|
|
for (var i = 0; i < connectionTypes.length; i++) {
|
|
final actions = <String>[];
|
|
await openMenu(tester, actions);
|
|
await tester.tap(i.isEven
|
|
? find.text('Request approval')
|
|
: find.byIcon(Icons.keyboard_arrow_right));
|
|
await tester.pumpAndSettle();
|
|
expect(actions, isEmpty);
|
|
for (final title in connectionTypes) {
|
|
expect(find.text(title), findsWidgets);
|
|
}
|
|
await tester.tap(find.text(connectionTypes[i]).last);
|
|
await tester.pumpAndSettle();
|
|
expect(actions, ['${connectionTypes[i]}:request-approval']);
|
|
expect(find.text('Request approval'), findsNothing);
|
|
expect(find.text('Rename'), findsNothing);
|
|
}
|
|
},
|
|
variant: TargetPlatformVariant({
|
|
TargetPlatform.android,
|
|
TargetPlatform.iOS,
|
|
TargetPlatform.linux,
|
|
TargetPlatform.macOS,
|
|
TargetPlatform.windows,
|
|
}));
|
|
|
|
testWidgets('the whole approval row opens the submenu on a narrow screen',
|
|
(tester) async {
|
|
tester.view.physicalSize = const Size(360, 640);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
for (final corner in [
|
|
Alignment.topLeft,
|
|
Alignment.topRight,
|
|
Alignment.bottomLeft,
|
|
Alignment.bottomRight,
|
|
]) {
|
|
final actions = <String>[];
|
|
await openMenu(tester, actions);
|
|
final row = tester.getRect(find.byType(PopupMenuChildrenItem<String>));
|
|
await tester.tapAt(corner.withinRect(row.deflate(2)));
|
|
await tester.pumpAndSettle();
|
|
expect(actions, isEmpty);
|
|
expect(find.text('Terminal (Run as administrator)'), findsOneWidget);
|
|
await tester.tap(find.text('Connect').last);
|
|
await tester.pumpAndSettle();
|
|
expect(actions, ['Connect:request-approval']);
|
|
expect(find.text('Rename'), findsNothing);
|
|
}
|
|
},
|
|
variant:
|
|
TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
|
|
}
|