Merge pull request #1236 from Heap-Hop/flutter_desktop

Update UI
This commit is contained in:
RustDesk 2022-08-10 10:53:50 +08:00 committed by GitHub
commit 522c865096
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 104 deletions

View File

@ -118,7 +118,9 @@ void window_on_top(int? id) {
windowManager.show(); windowManager.show();
windowManager.focus(); windowManager.focus();
} else { } else {
WindowController.fromWindowId(id)..focus()..show(); WindowController.fromWindowId(id)
..focus()
..show();
} }
} }

View File

@ -8,11 +8,9 @@ import 'package:flutter_hbb/desktop/widgets/peer_widget.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
import '../../common.dart'; import '../../common.dart';
import '../../mobile/pages/home_page.dart';
import '../../mobile/pages/scan_page.dart'; import '../../mobile/pages/scan_page.dart';
import '../../mobile/pages/settings_page.dart'; import '../../mobile/pages/settings_page.dart';
import '../../models/model.dart'; import '../../models/model.dart';
@ -21,18 +19,9 @@ import '../../models/platform_model.dart';
// enum RemoteType { recently, favorite, discovered, addressBook } // enum RemoteType { recently, favorite, discovered, addressBook }
/// Connection page for connecting to a remote peer. /// Connection page for connecting to a remote peer.
class ConnectionPage extends StatefulWidget implements PageShape { class ConnectionPage extends StatefulWidget {
ConnectionPage({Key? key}) : super(key: key); ConnectionPage({Key? key}) : super(key: key);
@override
final icon = Icon(Icons.connected_tv);
@override
final title = translate("Connection");
@override
final appBarActions = !isAndroid ? <Widget>[WebMenu()] : <Widget>[];
@override @override
_ConnectionPageState createState() => _ConnectionPageState(); _ConnectionPageState createState() => _ConnectionPageState();
} }
@ -174,8 +163,8 @@ class _ConnectionPageState extends State<ConnectionPage> {
: InkWell( : InkWell(
onTap: () async { onTap: () async {
final url = _updateUrl + '.apk'; final url = _updateUrl + '.apk';
if (await canLaunch(url)) { if (await canLaunchUrlString(url)) {
await launch(url); await launchUrlString(url);
} }
}, },
child: Container( child: Container(
@ -387,13 +376,20 @@ class _ConnectionPageState extends State<ConnectionPage> {
width: 8, width: 8,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
color: Colors.green, color: svcStopped.value ? Colors.redAccent : Colors.green,
), ),
).paddingSymmetric(horizontal: 8.0); ).paddingSymmetric(horizontal: 10.0);
if (svcStopped.value) { if (svcStopped.value) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [light, Text(translate("Service is not running"))], children: [
light,
Text(translate("Service is not running")),
TextButton(
onPressed: () =>
bind.mainSetOption(key: "stop-service", value: ""),
child: Text(translate("Start Service")))
],
); );
} else { } else {
if (svcStatusCode.value == 0) { if (svcStatusCode.value == 0) {
@ -436,7 +432,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
} }
updateStatus() async { updateStatus() async {
svcStopped.value = bind.mainGetOption(key: "stop-service") == "Y"; svcStopped.value = await bind.mainGetOption(key: "stop-service") == "Y";
final status = final status =
jsonDecode(await bind.mainGetConnectStatus()) as Map<String, dynamic>; jsonDecode(await bind.mainGetConnectStatus()) as Map<String, dynamic>;
svcStatusCode.value = status["status_num"]; svcStatusCode.value = status["status_num"];

View File

@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart' hide MenuItem; import 'package:flutter/material.dart' hide MenuItem;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
@ -27,8 +26,8 @@ class DesktopHomePage extends StatefulWidget {
const borderColor = Color(0xFF2F65BA); const borderColor = Color(0xFF2F65BA);
class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, WindowListener { class _DesktopHomePageState extends State<DesktopHomePage>
with TrayListener, WindowListener {
@override @override
void onWindowClose() async { void onWindowClose() async {
super.onWindowClose(); super.onWindowClose();
@ -132,18 +131,7 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
style: TextStyle( style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w500), fontSize: 18, fontWeight: FontWeight.w500),
), ),
FutureBuilder<Widget>( buildPopupMenu(context)
future: buildPopupMenu(context),
builder: (context, snapshot) {
if (snapshot.hasError) {
print("${snapshot.error}");
}
if (snapshot.hasData) {
return snapshot.data!;
} else {
return Offstage();
}
})
], ],
), ),
GestureDetector( GestureDetector(
@ -165,7 +153,7 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
); );
} }
Future<Widget> buildPopupMenu(BuildContext context) async { Widget buildPopupMenu(BuildContext context) {
var position; var position;
return GestureDetector( return GestureDetector(
onTapDown: (detail) { onTapDown: (detail) {
@ -178,19 +166,19 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
final enabledInput = await bind.mainGetOption(key: 'enable-audio'); final enabledInput = await bind.mainGetOption(key: 'enable-audio');
final defaultInput = await gFFI.getDefaultAudioInput(); final defaultInput = await gFFI.getDefaultAudioInput();
var menu = <PopupMenuEntry>[ var menu = <PopupMenuEntry>[
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Enable Keyboard/Mouse"), translate("Enable Keyboard/Mouse"),
'enable-keyboard', 'enable-keyboard',
), ),
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Enable Clipboard"), translate("Enable Clipboard"),
'enable-clipboard', 'enable-clipboard',
), ),
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Enable File Transfer"), translate("Enable File Transfer"),
'enable-file-transfer', 'enable-file-transfer',
), ),
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Enable TCP Tunneling"), translate("Enable TCP Tunneling"),
'enable-tunnel', 'enable-tunnel',
), ),
@ -209,16 +197,16 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
value: 'socks5-proxy', value: 'socks5-proxy',
), ),
PopupMenuDivider(), PopupMenuDivider(),
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Enable Service"), translate("Enable Service"),
'stop-service', 'stop-service',
), ),
// TODO: direct server // TODO: direct server
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Always connected via relay"), translate("Always connected via relay"),
'allow-always-relay', 'allow-always-relay',
), ),
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Start ID/relay service"), translate("Start ID/relay service"),
'stop-rendezvous-service', 'stop-rendezvous-service',
), ),
@ -237,7 +225,7 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
value: 'change-id', value: 'change-id',
), ),
PopupMenuDivider(), PopupMenuDivider(),
genEnablePopupMenuItem( await genEnablePopupMenuItem(
translate("Dark Theme"), translate("Dark Theme"),
'allow-darktheme', 'allow-darktheme',
), ),
@ -491,6 +479,7 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
Get.changeTheme(MyTheme.lightTheme); Get.changeTheme(MyTheme.lightTheme);
} }
Get.find<SharedPreferences>().setString("darkTheme", choice); Get.find<SharedPreferences>().setString("darkTheme", choice);
Get.forceAppUpdate();
} }
void onSelectMenu(String key) async { void onSelectMenu(String key) async {
@ -501,7 +490,7 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
final option = await bind.mainGetOption(key: key); final option = await bind.mainGetOption(key: key);
final choice = option == "Y" ? "" : "Y"; final choice = option == "Y" ? "" : "Y";
bind.mainSetOption(key: key, value: choice); bind.mainSetOption(key: key, value: choice);
changeTheme(choice); if (key == "allow-darktheme") changeTheme(choice);
} else if (key == "stop-service") { } else if (key == "stop-service") {
final option = await bind.mainGetOption(key: key); final option = await bind.mainGetOption(key: key);
bind.mainSetOption(key: key, value: option == "Y" ? "" : "Y"); bind.mainSetOption(key: key, value: option == "Y" ? "" : "Y");
@ -522,30 +511,29 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener, Wi
} }
} }
PopupMenuItem<String> genEnablePopupMenuItem(String label, String key) { Future<PopupMenuItem<String>> genEnablePopupMenuItem(
Future<bool> getOptionEnable(String key) async { String label, String key) async {
final v = await bind.mainGetOption(key: key); final v = await bind.mainGetOption(key: key);
return key.startsWith('enable-') ? v != "N" : v == "Y"; bool enable;
if (key == "stop-service") {
enable = v != "Y";
} else if (key.startsWith("allow-")) {
enable = v == "Y";
} else {
enable = v != "N";
} }
return PopupMenuItem( return PopupMenuItem(
child: FutureBuilder<bool>( child: Row(
future: getOptionEnable(key),
builder: (context, snapshot) {
var enable = false;
if (snapshot.hasData && snapshot.data!) {
enable = true;
}
return Row(
children: [ children: [
Offstage(offstage: !enable, child: Icon(Icons.check)), Icon(Icons.check,
color: enable ? null : MyTheme.accent.withAlpha(00)),
Text( Text(
label, label,
style: genTextStyle(enable), style: genTextStyle(enable),
), ),
], ],
); ),
}),
value: key, value: key,
); );
} }

View File

@ -187,10 +187,9 @@ class _PeerCardState extends State<_PeerCard>
elevation: 8, elevation: 8,
); );
if (value == 'remove') { if (value == 'remove') {
setState(() => bind.mainRemovePeer(id: id)); await bind.mainRemovePeer(id: id);
() async {
removePreference(id); removePreference(id);
}(); Get.forceAppUpdate(); // TODO use inner model / state
} else if (value == 'file') { } else if (value == 'file') {
_connect(id, isFileTransfer: true); _connect(id, isFileTransfer: true);
} else if (value == 'add-fav') { } else if (value == 'add-fav') {

View File

@ -8,7 +8,7 @@ import '../../models/platform_model.dart';
import '../../models/server_model.dart'; import '../../models/server_model.dart';
import 'home_page.dart'; import 'home_page.dart';
class ServerPage extends StatelessWidget implements PageShape { class ServerPage extends StatefulWidget implements PageShape {
@override @override
final title = translate("Share Screen"); final title = translate("Share Screen");
@ -102,6 +102,17 @@ class ServerPage extends StatelessWidget implements PageShape {
}) })
]; ];
@override
State<StatefulWidget> createState() => _ServerPageState();
}
class _ServerPageState extends State<ServerPage> {
@override
void initState() {
super.initState();
gFFI.serverModel.checkAndroidPermission();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
checkService(); checkService();

View File

@ -85,40 +85,8 @@ class ServerModel with ChangeNotifier {
WeakReference<FFI> parent; WeakReference<FFI> parent;
ServerModel(this.parent) { ServerModel(this.parent) {
() async {
_emptyIdShow = translate("Generating ..."); _emptyIdShow = translate("Generating ...");
_serverId = TextEditingController(text: this._emptyIdShow); _serverId = TextEditingController(text: this._emptyIdShow);
/**
* 1. check android permission
* 2. check config
* audio true by default (if permission on) (false default < Android 10)
* file true by default (if permission on)
*/
await Future.delayed(Duration(seconds: 1));
// audio
if (androidVersion < 30 || !await PermissionManager.check("audio")) {
_audioOk = false;
bind.mainSetOption(key: "enable-audio", value: "N");
} else {
final audioOption = await bind.mainGetOption(key: 'enable-audio');
_audioOk = audioOption.isEmpty;
}
// file
if (!await PermissionManager.check("file")) {
_fileOk = false;
bind.mainSetOption(key: "enable-file-transfer", value: "N");
} else {
final fileOption =
await bind.mainGetOption(key: 'enable-file-transfer');
_fileOk = fileOption.isEmpty;
}
// input (mouse control) false by default
bind.mainSetOption(key: "enable-keyboard", value: "N");
notifyListeners();
}();
Timer.periodic(Duration(seconds: 1), (timer) async { Timer.periodic(Duration(seconds: 1), (timer) async {
var status = await bind.mainGetOnlineStatue(); var status = await bind.mainGetOnlineStatue();
@ -139,6 +107,34 @@ class ServerModel with ChangeNotifier {
}); });
} }
/// 1. check android permission
/// 2. check config
/// audio true by default (if permission on) (false default < Android 10)
/// file true by default (if permission on)
checkAndroidPermission() async {
// audio
if (androidVersion < 30 || !await PermissionManager.check("audio")) {
_audioOk = false;
bind.mainSetOption(key: "enable-audio", value: "N");
} else {
final audioOption = await bind.mainGetOption(key: 'enable-audio');
_audioOk = audioOption.isEmpty;
}
// file
if (!await PermissionManager.check("file")) {
_fileOk = false;
bind.mainSetOption(key: "enable-file-transfer", value: "N");
} else {
final fileOption = await bind.mainGetOption(key: 'enable-file-transfer');
_fileOk = fileOption.isEmpty;
}
// input (mouse control) false by default
bind.mainSetOption(key: "enable-keyboard", value: "N");
notifyListeners();
}
updatePasswordModel() async { updatePasswordModel() async {
var update = false; var update = false;
final temporaryPassword = await bind.mainGetTemporaryPassword(); final temporaryPassword = await bind.mainGetTemporaryPassword();