mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-04 01:01:28 +03:00
flutter_desktop: WOL & menu, mid commit
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
@@ -22,10 +22,10 @@ import '../../models/platform_model.dart';
|
||||
|
||||
/// Connection page for connecting to a remote peer.
|
||||
class ConnectionPage extends StatefulWidget {
|
||||
ConnectionPage({Key? key}) : super(key: key);
|
||||
const ConnectionPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ConnectionPageState createState() => _ConnectionPageState();
|
||||
State<ConnectionPage> createState() => _ConnectionPageState();
|
||||
}
|
||||
|
||||
/// State for the connection page.
|
||||
@@ -101,7 +101,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
],
|
||||
).marginSymmetric(horizontal: 22),
|
||||
),
|
||||
Divider(),
|
||||
const Divider(),
|
||||
SizedBox(height: 50, child: Obx(() => buildStatus()))
|
||||
.paddingSymmetric(horizontal: 12.0)
|
||||
]),
|
||||
|
||||
@@ -19,8 +19,15 @@ import 'package:tray_manager/tray_manager.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class _PopupMenuTheme {
|
||||
static const Color commonColor = MyTheme.accent;
|
||||
// kMinInteractiveDimension
|
||||
static const double height = 25.0;
|
||||
static const double dividerHeight = 3.0;
|
||||
}
|
||||
|
||||
class DesktopHomePage extends StatefulWidget {
|
||||
DesktopHomePage({Key? key}) : super(key: key);
|
||||
const DesktopHomePage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _DesktopHomePageState();
|
||||
@@ -86,7 +93,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
buildServerBoard(BuildContext context) {
|
||||
return Container(
|
||||
color: MyTheme.color(context).grayBg,
|
||||
child: ConnectionPage(),
|
||||
child: const ConnectionPage(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -154,8 +161,190 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
);
|
||||
}
|
||||
|
||||
// Future<MenuEntryBase<String>> _genSwitchEntry(
|
||||
// String label, String key) async {
|
||||
|
||||
// final v = await bind.mainGetOption(key: key);
|
||||
// bool enable;
|
||||
// if (key == "stop-service") {
|
||||
// enable = v != "Y";
|
||||
// } else if (key.startsWith("allow-")) {
|
||||
// enable = v == "Y";
|
||||
// } else {
|
||||
// enable = v != "N";
|
||||
// }
|
||||
|
||||
// return PopupMenuItem(
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Icon(Icons.check,
|
||||
// color: enable ? null : MyTheme.accent.withAlpha(00)),
|
||||
// Text(
|
||||
// label,
|
||||
// style: genTextStyle(enable),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// value: key,
|
||||
// );
|
||||
// }
|
||||
|
||||
_popupMenu(BuildContext context, RelativeRect position) async {
|
||||
TextStyle styleEnabled = const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal);
|
||||
TextStyle styleDisabled = const TextStyle(
|
||||
color: Colors.redAccent,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.lineThrough);
|
||||
|
||||
enabledEntry(String label, String key) {
|
||||
Rx<TextStyle> textStyle = styleEnabled.obs;
|
||||
return MenuEntrySwitch<String>(
|
||||
text: translate(label),
|
||||
textStyle: textStyle,
|
||||
getter: () async {
|
||||
final opt = await bind.mainGetOption(key: key);
|
||||
bool enabled;
|
||||
if (key == 'stop-service') {
|
||||
enabled = opt != 'Y';
|
||||
} else if (key.startsWith("allow-")) {
|
||||
enabled = opt == 'Y';
|
||||
} else {
|
||||
enabled = opt != 'N';
|
||||
}
|
||||
textStyle.value = enabled ? styleEnabled : styleDisabled;
|
||||
return enabled;
|
||||
},
|
||||
setter: (bool v) async {
|
||||
String opt;
|
||||
if (key == 'stop-service') {
|
||||
opt = v ? 'Y' : '';
|
||||
} else if (key.startsWith("allow-")) {
|
||||
opt = v ? 'Y' : '';
|
||||
} else {
|
||||
opt = v ? '' : 'N';
|
||||
}
|
||||
await bind.mainSetOption(key: key, value: opt);
|
||||
if (key == 'allow-darktheme') {
|
||||
changeTheme(opt);
|
||||
}
|
||||
},
|
||||
dismissOnClicked: false,
|
||||
);
|
||||
}
|
||||
|
||||
final userName = await gFFI.userModel.getUserName();
|
||||
final enabledInput = await bind.mainGetOption(key: 'enable-audio');
|
||||
final defaultInput = await gFFI.getDefaultAudioInput();
|
||||
|
||||
final List<MenuEntryBase<String>> menu = <MenuEntryBase<String>>[
|
||||
enabledEntry('Enable Keyboard/Mouse', 'enable-keyboard'),
|
||||
enabledEntry('Enable Clipboard', 'enable-clipboard'),
|
||||
enabledEntry('Enable File Transfer', 'enable-file-transfer'),
|
||||
enabledEntry('Enable TCP Tunneling', 'enable-tunnel'),
|
||||
// TODO: audio sub menu?
|
||||
// genAudioInputPopupMenuItem(enabledInput != "N", defaultInput),
|
||||
MenuEntryDivider(),
|
||||
MenuEntryButton(
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('ID/Relay Server'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
changeServer();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
),
|
||||
MenuEntryButton(
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('IP Whitelisting'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
changeWhiteList();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
),
|
||||
MenuEntryButton(
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('Socks5 Proxy'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
changeSocks5Proxy();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
),
|
||||
MenuEntryDivider(),
|
||||
enabledEntry('Enable Service', 'stop-service'),
|
||||
enabledEntry('Always connected via relay', 'allow-always-relay'),
|
||||
// FIXME: is this option correct?
|
||||
enabledEntry('Start ID/relay service', 'stop-rendezvous-service'),
|
||||
MenuEntryDivider(),
|
||||
userName.isEmpty
|
||||
? MenuEntryButton(
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('Login'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
login();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
)
|
||||
: MenuEntryButton(
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('Logout'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
logOut();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
),
|
||||
MenuEntryButton(
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('Change ID'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
changeId();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
),
|
||||
MenuEntryDivider(),
|
||||
enabledEntry('Dark Theme', 'allow-darktheme'),
|
||||
MenuEntryButton(
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('About'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
about();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
),
|
||||
];
|
||||
|
||||
await mod_menu.showMenu(
|
||||
context: context,
|
||||
position: position,
|
||||
items: menu
|
||||
.map((e) => e.build(
|
||||
context,
|
||||
const MenuConfig(
|
||||
commonColor: _PopupMenuTheme.commonColor,
|
||||
height: _PopupMenuTheme.height,
|
||||
dividerHeight: _PopupMenuTheme.dividerHeight)))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
}
|
||||
|
||||
Widget buildPopupMenu(BuildContext context) {
|
||||
var position;
|
||||
RelativeRect position = const RelativeRect.fromLTRB(0.0, 0.0, 0.0, 0.0);
|
||||
RxBool hover = false.obs;
|
||||
return InkWell(
|
||||
onTapDown: (detail) {
|
||||
@@ -164,83 +353,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
position = RelativeRect.fromLTRB(x, y, x, y);
|
||||
},
|
||||
onTap: () async {
|
||||
final userName = await gFFI.userModel.getUserName();
|
||||
final enabledInput = await bind.mainGetOption(key: 'enable-audio');
|
||||
final defaultInput = await gFFI.getDefaultAudioInput();
|
||||
var menu = <PopupMenuEntry>[
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable Keyboard/Mouse"),
|
||||
'enable-keyboard',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable Clipboard"),
|
||||
'enable-clipboard',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable File Transfer"),
|
||||
'enable-file-transfer',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable TCP Tunneling"),
|
||||
'enable-tunnel',
|
||||
),
|
||||
genAudioInputPopupMenuItem(enabledInput != "N", defaultInput),
|
||||
PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("ID/Relay Server")),
|
||||
value: 'custom-server',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("IP Whitelisting")),
|
||||
value: 'whitelist',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("Socks5 Proxy")),
|
||||
value: 'socks5-proxy',
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable Service"),
|
||||
'stop-service',
|
||||
),
|
||||
// TODO: direct server
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Always connected via relay"),
|
||||
'allow-always-relay',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Start ID/relay service"),
|
||||
'stop-rendezvous-service',
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
userName.isEmpty
|
||||
? PopupMenuItem(
|
||||
child: Text(translate("Login")),
|
||||
value: 'login',
|
||||
)
|
||||
: PopupMenuItem(
|
||||
child: Text("${translate("Logout")} $userName"),
|
||||
value: 'logout',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("Change ID")),
|
||||
value: 'change-id',
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Dark Theme"),
|
||||
'allow-darktheme',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("About")),
|
||||
value: 'about',
|
||||
),
|
||||
];
|
||||
final v =
|
||||
await showMenu(context: context, position: position, items: menu);
|
||||
if (v != null) {
|
||||
onSelectMenu(v);
|
||||
}
|
||||
await _popupMenu(context, position);
|
||||
},
|
||||
child: Obx(
|
||||
() => CircleAvatar(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
@@ -17,7 +17,7 @@ import '../../models/platform_model.dart';
|
||||
enum LocationStatus { bread, textField }
|
||||
|
||||
class FileManagerPage extends StatefulWidget {
|
||||
FileManagerPage({Key? key, required this.id}) : super(key: key);
|
||||
const FileManagerPage({Key? key, required this.id}) : super(key: key);
|
||||
final String id;
|
||||
|
||||
@override
|
||||
|
||||
@@ -21,8 +21,8 @@ class FileManagerTabPage extends StatefulWidget {
|
||||
class _FileManagerTabPageState extends State<FileManagerTabPage> {
|
||||
DesktopTabController get tabController => Get.find<DesktopTabController>();
|
||||
|
||||
static final IconData selectedIcon = Icons.file_copy_sharp;
|
||||
static final IconData unselectedIcon = Icons.file_copy_outlined;
|
||||
static const IconData selectedIcon = Icons.file_copy_sharp;
|
||||
static const IconData unselectedIcon = Icons.file_copy_outlined;
|
||||
|
||||
_FileManagerTabPageState(Map<String, dynamic> params) {
|
||||
Get.put(DesktopTabController(tabType: DesktopTabType.fileTransfer));
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
import 'package:flutter_custom_cursor/flutter_custom_cursor.dart';
|
||||
|
||||
// import 'package:window_manager/window_manager.dart';
|
||||
|
||||
@@ -22,7 +23,7 @@ import '../../common/shared_state.dart';
|
||||
final initText = '\1' * 1024;
|
||||
|
||||
class RemotePage extends StatefulWidget {
|
||||
RemotePage({
|
||||
const RemotePage({
|
||||
Key? key,
|
||||
required this.id,
|
||||
required this.tabBarHeight,
|
||||
@@ -32,7 +33,7 @@ class RemotePage extends StatefulWidget {
|
||||
final double tabBarHeight;
|
||||
|
||||
@override
|
||||
_RemotePageState createState() => _RemotePageState();
|
||||
State<RemotePage> createState() => _RemotePageState();
|
||||
}
|
||||
|
||||
class _RemotePageState extends State<RemotePage>
|
||||
@@ -483,6 +484,8 @@ class ImagePaint extends StatelessWidget {
|
||||
child: CustomPaint(
|
||||
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
||||
));
|
||||
|
||||
Rx<Offset> pos = Rx<Offset>(Offset(0.0, 0.0));
|
||||
return Center(
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
onNotification: (notification) {
|
||||
@@ -498,9 +501,15 @@ class ImagePaint extends StatelessWidget {
|
||||
return false;
|
||||
},
|
||||
child: Obx(() => MouseRegion(
|
||||
cursor: (keyboardEnabled.isTrue && cursorOverImage.isTrue)
|
||||
? SystemMouseCursors.none
|
||||
: MouseCursor.defer,
|
||||
// cursor: (keyboardEnabled.isTrue && cursorOverImage.isTrue)
|
||||
// ? SystemMouseCursors.none
|
||||
// : MouseCursor.defer,
|
||||
/// cursor: MouseCursor.defer,
|
||||
cursor: FlutterCustomCursor(
|
||||
path: "assets/pencil.png", x: 1.0, y: 8.0),
|
||||
onHover: (evt) {
|
||||
pos.value = evt.position;
|
||||
},
|
||||
child: _buildCrossScrollbar(_buildListener(imageWidget)))),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -13,8 +13,10 @@ import '../../models/platform_model.dart';
|
||||
import '../../models/server_model.dart';
|
||||
|
||||
class DesktopServerPage extends StatefulWidget {
|
||||
const DesktopServerPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _DesktopServerPageState();
|
||||
State<DesktopServerPage> createState() => _DesktopServerPageState();
|
||||
}
|
||||
|
||||
class _DesktopServerPageState extends State<DesktopServerPage>
|
||||
|
||||
Reference in New Issue
Block a user