rustdesk/flutter/lib/desktop/pages/desktop_home_page.dart

345 lines
11 KiB
Dart
Raw Normal View History

import 'dart:io';
import 'package:flutter/material.dart' hide MenuItem;
2022-07-14 12:32:01 +08:00
import 'package:flutter/services.dart';
import 'package:flutter_hbb/common.dart';
2022-05-29 04:39:12 +08:00
import 'package:flutter_hbb/desktop/pages/connection_page.dart';
2022-05-29 19:55:50 +08:00
import 'package:flutter_hbb/desktop/widgets/titlebar_widget.dart';
import 'package:flutter_hbb/models/model.dart';
2022-07-14 12:32:01 +08:00
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:tray_manager/tray_manager.dart';
2022-05-23 16:44:23 +08:00
class DesktopHomePage extends StatefulWidget {
DesktopHomePage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _DesktopHomePageState();
}
2022-05-29 19:55:50 +08:00
const borderColor = Color(0xFF2F65BA);
class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener {
2022-05-23 16:44:23 +08:00
@override
Widget build(BuildContext context) {
return Scaffold(
2022-05-29 19:55:50 +08:00
body: Column(
children: [
DesktopTitleBar(
child: Center(
child: Text(
"RustDesk",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
2022-05-29 19:55:50 +08:00
),
Expanded(
child: Container(
child: Row(
children: [
Flexible(
child: buildServerInfo(context),
flex: 1,
),
Flexible(
child: buildServerBoard(context),
flex: 4,
),
],
),
),
2022-05-29 19:55:50 +08:00
),
],
),
);
}
buildServerInfo(BuildContext context) {
return ChangeNotifierProvider.value(
value: gFFI.serverModel,
2022-05-29 10:25:36 +08:00
child: Container(
decoration: BoxDecoration(color: MyTheme.white),
child: Column(
children: [
buildTip(context),
buildIDBoard(context),
buildPasswordBoard(context),
],
),
),
);
}
buildServerBoard(BuildContext context) {
2022-05-29 10:25:36 +08:00
return Column(
children: [
2022-07-14 12:32:01 +08:00
Expanded(child: ConnectionPage()),
2022-05-29 10:25:36 +08:00
],
);
}
buildIDBoard(BuildContext context) {
final model = gFFI.serverModel;
2022-05-29 10:25:36 +08:00
return Container(
margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Container(
width: 3,
height: 70,
decoration: BoxDecoration(color: MyTheme.accent),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
2022-07-14 12:32:01 +08:00
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
translate("ID"),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
PopupMenuButton(
padding: EdgeInsets.all(4.0),
itemBuilder: (context) => [
genEnablePopupMenuItem(translate("Enable Keyboard/Mouse"), 'enable-keyboard',),
genEnablePopupMenuItem(translate("Enable Clipboard"), 'enable-clipboard',),
genEnablePopupMenuItem(translate("Enable File Transfer"), 'enable-file-transfer',),
genEnablePopupMenuItem(translate("Enable TCP Tunneling"), 'enable-tunnel',),
genAudioInputPopupMenuItem(),
// TODO: Audio Input
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',),
// sep
genEnablePopupMenuItem(translate("Enable Service"), 'stop-service',),
// TODO: direct server
genEnablePopupMenuItem(translate("Always connected via relay"),'allow-always-relay',),
genEnablePopupMenuItem(translate("Start ID/relay service"),'stop-rendezvous-service',),
PopupMenuItem(child: Text(translate("Change ID")), value: 'change-id',),
genEnablePopupMenuItem(translate("Dark Theme"), 'allow-darktheme',),
PopupMenuItem(child: Text(translate("About")), value: 'about',),
], onSelected: onSelectMenu,)
],
2022-05-29 10:25:36 +08:00
),
TextFormField(
controller: model.serverId,
),
],
),
),
2022-05-29 10:25:36 +08:00
),
],
),
);
}
buildPasswordBoard(BuildContext context) {
final model = gFFI.serverModel;
2022-05-29 10:25:36 +08:00
return Container(
margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Container(
width: 3,
height: 70,
decoration: BoxDecoration(color: MyTheme.accent),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
translate("Password"),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
TextFormField(
controller: model.serverPasswd,
),
],
),
),
2022-05-29 10:25:36 +08:00
),
],
),
);
}
buildTip(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
translate("Your Desktop"),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
SizedBox(
height: 8.0,
),
Text(
translate("desk_tip"),
overflow: TextOverflow.clip,
style: TextStyle(fontSize: 14),
)
],
),
);
2022-05-23 16:44:23 +08:00
}
2022-05-29 10:25:36 +08:00
buildControlPanel(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), color: MyTheme.white),
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(translate("Control Remote Desktop")),
Form(
child: Column(
children: [
TextFormField(
controller: TextEditingController(),
2022-07-14 12:32:01 +08:00
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"[0-9]"))
],
2022-05-29 10:25:36 +08:00
)
],
))
],
),
);
}
buildRecentSession(BuildContext context) {
return Center(child: Text("waiting implementation"));
}
@override
void onTrayMenuItemClick(MenuItem menuItem) {
print("click ${menuItem.key}");
switch (menuItem.key) {
case "quit":
exit(0);
case "show":
// windowManager.show();
break;
default:
break;
}
}
@override
void initState() {
super.initState();
trayManager.addListener(this);
}
@override
void dispose() {
trayManager.removeListener(this);
super.dispose();
}
2022-07-14 12:32:01 +08:00
void onSelectMenu(String value) {
if (value.startsWith('enable-')) {
final option = gFFI.getOption(value);
gFFI.setOption(value, option == "N" ? "" : "N");
} else if (value.startsWith('allow-')) {
final option = gFFI.getOption(value);
gFFI.setOption(value, option == "Y" ? "" : "Y");
} else if (value == "stop-service") {
final option = gFFI.getOption(value);
gFFI.setOption(value, option == "Y" ? "" : "Y");
}
}
PopupMenuItem<String> genEnablePopupMenuItem(String label, String value) {
final isEnable =
label.startsWith('enable-') ? gFFI.getOption(value) != "N" : gFFI.getOption(value) != "Y";
return PopupMenuItem(child: Row(
children: [
Offstage(offstage: !isEnable, child: Icon(Icons.check)),
Text(label, style: genTextStyle(isEnable),),
],
), value: value,);
}
TextStyle genTextStyle(bool isPositive) {
return isPositive ? TextStyle() : TextStyle(
color: Colors.redAccent,
decoration: TextDecoration.lineThrough
);
}
PopupMenuItem<String> genAudioInputPopupMenuItem() {
final _enabledInput = gFFI.getOption('enable-audio');
var defaultInput = gFFI.getDefaultAudioInput().obs;
var enabled = (_enabledInput != "N").obs;
return PopupMenuItem(child: FutureBuilder<List<String>>(
future: gFFI.getAudioInputs(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final inputs = snapshot.data!;
if (Platform.isWindows) {
inputs.insert(0, translate("System Sound"));
}
var inputList = inputs.map((e) => PopupMenuItem(
child: Row(
children: [
Obx(()=> Offstage(offstage: defaultInput.value != e, child: Icon(Icons.check))),
Expanded(child: Tooltip(
message: e,
child: Text("$e",maxLines: 1, overflow: TextOverflow.ellipsis,))),
],
),
value: e,
)).toList();
inputList.insert(0, PopupMenuItem(
child: Row(
children: [
Obx(()=> Offstage(offstage: enabled.value, child: Icon(Icons.check))),
Expanded(child: Text(translate("Mute"))),
],
),
value: "Mute",
));
return PopupMenuButton<String>(
padding: EdgeInsets.zero,
child: Container(
alignment: Alignment.centerLeft,
child: Text(translate("Audio Input"))),
itemBuilder: (context) => inputList,
onSelected: (dev) {
if (dev == "Mute") {
gFFI.setOption('enable-audio', _enabledInput == 'N' ? '': 'N');
enabled.value = gFFI.getOption('enable-audio') != 'N';
} else if (dev != gFFI.getDefaultAudioInput()) {
gFFI.setDefaultAudioInput(dev);
defaultInput.value = dev;
}
},
);
} else {
return Text("...");
}
},
), value: 'audio-input',);
}
2022-05-23 16:44:23 +08:00
}