| 
									
										
										
										
											2022-07-14 17:44:37 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-26 11:21:40 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import 'package:provider/provider.dart'; | 
					
						
							|  |  |  | import 'package:settings_ui/settings_ui.dart'; | 
					
						
							|  |  |  | import 'package:url_launcher/url_launcher.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-24 23:33:00 +08:00
										 |  |  | import '../../common.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-26 11:21:40 +08:00
										 |  |  | import '../../common/widgets/dialog.dart'; | 
					
						
							| 
									
										
										
										
											2023-01-08 23:30:34 +09:00
										 |  |  | import '../../common/widgets/login.dart'; | 
					
						
							| 
									
										
										
										
											2023-02-28 00:41:09 +09:00
										 |  |  | import '../../consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-24 23:33:00 +08:00
										 |  |  | import '../../models/model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-05 20:29:43 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import '../widgets/dialog.dart'; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | import 'home_page.dart'; | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  | import 'scan_page.dart'; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  | class SettingsPage extends StatefulWidget implements PageShape { | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-03-23 15:28:21 +08:00
										 |  |  |   final title = translate("Settings"); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   final icon = Icon(Icons.settings); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |   final appBarActions = [ScanButton()]; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |   State<SettingsPage> createState() => _SettingsState(); | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  | const url = 'https://rustdesk.com/'; | 
					
						
							| 
									
										
										
										
											2022-07-14 17:44:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  | class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver { | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |   final _hasIgnoreBattery = androidVersion >= 26; | 
					
						
							|  |  |  |   var _ignoreBatteryOpt = false; | 
					
						
							|  |  |  |   var _enableStartOnBoot = false; | 
					
						
							|  |  |  |   var _enableAbr = false; | 
					
						
							|  |  |  |   var _denyLANDiscovery = false; | 
					
						
							|  |  |  |   var _onlyWhiteList = false; | 
					
						
							|  |  |  |   var _enableDirectIPAccess = false; | 
					
						
							|  |  |  |   var _enableRecordSession = false; | 
					
						
							|  |  |  |   var _autoRecordIncomingSession = false; | 
					
						
							|  |  |  |   var _localIP = ""; | 
					
						
							|  |  |  |   var _directAccessPort = ""; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-14 17:44:37 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |     WidgetsBinding.instance.addObserver(this); | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     () async { | 
					
						
							|  |  |  |       var update = false; | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |       if (_hasIgnoreBattery) { | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |         if (await checkAndUpdateIgnoreBatteryStatus()) { | 
					
						
							|  |  |  |           update = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 22:26:47 +09:00
										 |  |  |       if (await checkAndUpdateStartOnBoot()) { | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |         update = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW
 | 
					
						
							|  |  |  |       var enableStartOnBoot = | 
					
						
							|  |  |  |           await gFFI.invokeMethod(AndroidChannel.kGetStartOnBootOpt); | 
					
						
							|  |  |  |       if (enableStartOnBoot) { | 
					
						
							| 
									
										
										
										
											2023-02-28 22:26:47 +09:00
										 |  |  |         if (!await canStartOnBoot()) { | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |           enableStartOnBoot = false; | 
					
						
							|  |  |  |           gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |       if (enableStartOnBoot != _enableStartOnBoot) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _enableStartOnBoot = enableStartOnBoot; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       final enableAbrRes = option2bool( | 
					
						
							|  |  |  |           "enable-abr", await bind.mainGetOption(key: "enable-abr")); | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |       if (enableAbrRes != _enableAbr) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _enableAbr = enableAbrRes; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-26 11:21:40 +08:00
										 |  |  |       final denyLanDiscovery = !option2bool('enable-lan-discovery', | 
					
						
							|  |  |  |           await bind.mainGetOption(key: 'enable-lan-discovery')); | 
					
						
							|  |  |  |       if (denyLanDiscovery != _denyLANDiscovery) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _denyLANDiscovery = denyLanDiscovery; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       final onlyWhiteList = | 
					
						
							|  |  |  |           (await bind.mainGetOption(key: 'whitelist')).isNotEmpty; | 
					
						
							|  |  |  |       if (onlyWhiteList != _onlyWhiteList) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _onlyWhiteList = onlyWhiteList; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-29 13:07:20 +08:00
										 |  |  |       final enableDirectIPAccess = option2bool( | 
					
						
							|  |  |  |           'direct-server', await bind.mainGetOption(key: 'direct-server')); | 
					
						
							|  |  |  |       if (enableDirectIPAccess != _enableDirectIPAccess) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _enableDirectIPAccess = enableDirectIPAccess; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-25 10:16:11 +09:00
										 |  |  |       final enableRecordSession = option2bool('enable-record-session', | 
					
						
							|  |  |  |           await bind.mainGetOption(key: 'enable-record-session')); | 
					
						
							|  |  |  |       if (enableRecordSession != _enableRecordSession) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _enableRecordSession = enableRecordSession; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       final autoRecordIncomingSession = option2bool( | 
					
						
							|  |  |  |           'allow-auto-record-incoming', | 
					
						
							|  |  |  |           await bind.mainGetOption(key: 'allow-auto-record-incoming')); | 
					
						
							|  |  |  |       if (autoRecordIncomingSession != _autoRecordIncomingSession) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _autoRecordIncomingSession = autoRecordIncomingSession; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-29 13:07:20 +08:00
										 |  |  |       final localIP = await bind.mainGetOption(key: 'local-ip-addr'); | 
					
						
							|  |  |  |       if (localIP != _localIP) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _localIP = localIP; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       final directAccessPort = | 
					
						
							|  |  |  |           await bind.mainGetOption(key: 'direct-access-port'); | 
					
						
							|  |  |  |       if (directAccessPort != _directAccessPort) { | 
					
						
							|  |  |  |         update = true; | 
					
						
							|  |  |  |         _directAccessPort = directAccessPort; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |       if (update) { | 
					
						
							|  |  |  |         setState(() {}); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }(); | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     WidgetsBinding.instance.removeObserver(this); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void didChangeAppLifecycleState(AppLifecycleState state) { | 
					
						
							|  |  |  |     if (state == AppLifecycleState.resumed) { | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |       () async { | 
					
						
							| 
									
										
										
										
											2023-02-28 22:26:47 +09:00
										 |  |  |         final ibs = await checkAndUpdateIgnoreBatteryStatus(); | 
					
						
							|  |  |  |         final sob = await checkAndUpdateStartOnBoot(); | 
					
						
							|  |  |  |         if (ibs || sob) { | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |           setState(() {}); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }(); | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |   Future<bool> checkAndUpdateIgnoreBatteryStatus() async { | 
					
						
							| 
									
										
										
										
											2023-02-28 21:02:42 +09:00
										 |  |  |     final res = await AndroidPermissionManager.check( | 
					
						
							|  |  |  |         kRequestIgnoreBatteryOptimizations); | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |     if (_ignoreBatteryOpt != res) { | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |       _ignoreBatteryOpt = res; | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2022-07-14 17:44:37 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 22:26:47 +09:00
										 |  |  |   Future<bool> checkAndUpdateStartOnBoot() async { | 
					
						
							|  |  |  |     if (!await canStartOnBoot() && _enableStartOnBoot) { | 
					
						
							|  |  |  |       _enableStartOnBoot = false; | 
					
						
							|  |  |  |       debugPrint( | 
					
						
							|  |  |  |           "checkAndUpdateStartOnBoot and set _enableStartOnBoot -> false"); | 
					
						
							|  |  |  |       gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false); | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |     Provider.of<FfiModel>(context); | 
					
						
							| 
									
										
										
										
											2022-09-29 13:07:20 +08:00
										 |  |  |     final List<AbstractSettingsTile> enhancementsTiles = []; | 
					
						
							|  |  |  |     final List<AbstractSettingsTile> shareScreenTiles = [ | 
					
						
							| 
									
										
										
										
											2022-09-26 11:21:40 +08:00
										 |  |  |       SettingsTile.switchTile( | 
					
						
							|  |  |  |         title: Text(translate('Deny LAN Discovery')), | 
					
						
							|  |  |  |         initialValue: _denyLANDiscovery, | 
					
						
							|  |  |  |         onToggle: (v) async { | 
					
						
							|  |  |  |           await bind.mainSetOption( | 
					
						
							|  |  |  |               key: "enable-lan-discovery", | 
					
						
							|  |  |  |               value: bool2option("enable-lan-discovery", !v)); | 
					
						
							|  |  |  |           final newValue = !option2bool('enable-lan-discovery', | 
					
						
							|  |  |  |               await bind.mainGetOption(key: 'enable-lan-discovery')); | 
					
						
							|  |  |  |           setState(() { | 
					
						
							|  |  |  |             _denyLANDiscovery = newValue; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       SettingsTile.switchTile( | 
					
						
							|  |  |  |         title: Row(children: [ | 
					
						
							| 
									
										
										
										
											2022-09-29 13:07:20 +08:00
										 |  |  |           Expanded(child: Text(translate('Use IP Whitelisting'))), | 
					
						
							| 
									
										
										
										
											2022-09-26 11:21:40 +08:00
										 |  |  |           Offstage( | 
					
						
							|  |  |  |                   offstage: !_onlyWhiteList, | 
					
						
							|  |  |  |                   child: const Icon(Icons.warning_amber_rounded, | 
					
						
							|  |  |  |                       color: Color.fromARGB(255, 255, 204, 0))) | 
					
						
							|  |  |  |               .marginOnly(left: 5) | 
					
						
							|  |  |  |         ]), | 
					
						
							|  |  |  |         initialValue: _onlyWhiteList, | 
					
						
							|  |  |  |         onToggle: (_) async { | 
					
						
							|  |  |  |           update() async { | 
					
						
							|  |  |  |             final onlyWhiteList = | 
					
						
							|  |  |  |                 (await bind.mainGetOption(key: 'whitelist')).isNotEmpty; | 
					
						
							|  |  |  |             if (onlyWhiteList != _onlyWhiteList) { | 
					
						
							|  |  |  |               setState(() { | 
					
						
							|  |  |  |                 _onlyWhiteList = onlyWhiteList; | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           changeWhiteList(callback: update); | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-09-29 13:07:20 +08:00
										 |  |  |       ), | 
					
						
							|  |  |  |       SettingsTile.switchTile( | 
					
						
							|  |  |  |         title: Text('${translate('Adaptive Bitrate')} (beta)'), | 
					
						
							|  |  |  |         initialValue: _enableAbr, | 
					
						
							|  |  |  |         onToggle: (v) async { | 
					
						
							|  |  |  |           await bind.mainSetOption(key: "enable-abr", value: v ? "" : "N"); | 
					
						
							|  |  |  |           final newValue = await bind.mainGetOption(key: "enable-abr") != "N"; | 
					
						
							|  |  |  |           setState(() { | 
					
						
							|  |  |  |             _enableAbr = newValue; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-10-25 10:16:11 +09:00
										 |  |  |       SettingsTile.switchTile( | 
					
						
							|  |  |  |         title: Text(translate('Enable Recording Session')), | 
					
						
							|  |  |  |         initialValue: _enableRecordSession, | 
					
						
							|  |  |  |         onToggle: (v) async { | 
					
						
							|  |  |  |           await bind.mainSetOption( | 
					
						
							|  |  |  |               key: "enable-record-session", value: v ? "" : "N"); | 
					
						
							|  |  |  |           final newValue = | 
					
						
							|  |  |  |               await bind.mainGetOption(key: "enable-record-session") != "N"; | 
					
						
							|  |  |  |           setState(() { | 
					
						
							|  |  |  |             _enableRecordSession = newValue; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-09-29 13:07:20 +08:00
										 |  |  |       SettingsTile.switchTile( | 
					
						
							|  |  |  |         title: Row( | 
					
						
							|  |  |  |             mainAxisAlignment: MainAxisAlignment.spaceBetween, | 
					
						
							|  |  |  |             crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                   child: Column( | 
					
						
							|  |  |  |                       crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |                       children: [ | 
					
						
							|  |  |  |                     Text(translate("Direct IP Access")), | 
					
						
							|  |  |  |                     Offstage( | 
					
						
							|  |  |  |                         offstage: !_enableDirectIPAccess, | 
					
						
							|  |  |  |                         child: Text( | 
					
						
							|  |  |  |                           '${translate("Local Address")}: $_localIP${_directAccessPort.isEmpty ? "" : ":$_directAccessPort"}', | 
					
						
							|  |  |  |                           style: Theme.of(context).textTheme.bodySmall, | 
					
						
							|  |  |  |                         )), | 
					
						
							|  |  |  |                   ])), | 
					
						
							|  |  |  |               Offstage( | 
					
						
							|  |  |  |                   offstage: !_enableDirectIPAccess, | 
					
						
							|  |  |  |                   child: IconButton( | 
					
						
							|  |  |  |                       padding: EdgeInsets.zero, | 
					
						
							|  |  |  |                       icon: Icon( | 
					
						
							|  |  |  |                         Icons.edit, | 
					
						
							|  |  |  |                         size: 20, | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                       onPressed: () async { | 
					
						
							|  |  |  |                         final port = await changeDirectAccessPort( | 
					
						
							|  |  |  |                             _localIP, _directAccessPort); | 
					
						
							|  |  |  |                         setState(() { | 
					
						
							|  |  |  |                           _directAccessPort = port; | 
					
						
							|  |  |  |                         }); | 
					
						
							|  |  |  |                       })) | 
					
						
							|  |  |  |             ]), | 
					
						
							|  |  |  |         initialValue: _enableDirectIPAccess, | 
					
						
							|  |  |  |         onToggle: (_) async { | 
					
						
							|  |  |  |           _enableDirectIPAccess = !_enableDirectIPAccess; | 
					
						
							|  |  |  |           String value = bool2option('direct-server', _enableDirectIPAccess); | 
					
						
							|  |  |  |           await bind.mainSetOption(key: 'direct-server', value: value); | 
					
						
							|  |  |  |           setState(() {}); | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-09-26 11:21:40 +08:00
										 |  |  |       ) | 
					
						
							|  |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |     if (_hasIgnoreBattery) { | 
					
						
							| 
									
										
										
										
											2022-07-14 18:33:41 +08:00
										 |  |  |       enhancementsTiles.insert( | 
					
						
							|  |  |  |           0, | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |           SettingsTile.switchTile( | 
					
						
							|  |  |  |               initialValue: _ignoreBatteryOpt, | 
					
						
							| 
									
										
										
										
											2022-09-29 13:07:20 +08:00
										 |  |  |               title: Column( | 
					
						
							|  |  |  |                   crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     Text(translate('Keep RustDesk background service')), | 
					
						
							|  |  |  |                     Text('* ${translate('Ignore Battery Optimizations')}', | 
					
						
							|  |  |  |                         style: Theme.of(context).textTheme.bodySmall), | 
					
						
							|  |  |  |                   ]), | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |               onToggle: (v) async { | 
					
						
							|  |  |  |                 if (v) { | 
					
						
							| 
									
										
										
										
											2023-02-28 21:02:42 +09:00
										 |  |  |                   await AndroidPermissionManager.request( | 
					
						
							|  |  |  |                       kRequestIgnoreBatteryOptimizations); | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |                   final res = await gFFI.dialogManager | 
					
						
							|  |  |  |                       .show<bool>((setState, close) => CustomAlertDialog( | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |                             title: Text(translate("Open System Setting")), | 
					
						
							|  |  |  |                             content: Text(translate( | 
					
						
							|  |  |  |                                 "android_open_battery_optimizations_tip")), | 
					
						
							|  |  |  |                             actions: [ | 
					
						
							| 
									
										
										
										
											2023-01-15 19:46:16 +08:00
										 |  |  |                               dialogButton("Cancel", | 
					
						
							|  |  |  |                                   onPressed: () => close(), isOutline: true), | 
					
						
							|  |  |  |                               dialogButton( | 
					
						
							|  |  |  |                                 "Open System Setting", | 
					
						
							|  |  |  |                                 onPressed: () => close(true), | 
					
						
							|  |  |  |                               ), | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |                             ], | 
					
						
							|  |  |  |                           )); | 
					
						
							|  |  |  |                   if (res == true) { | 
					
						
							| 
									
										
										
										
											2023-02-28 19:46:41 +09:00
										 |  |  |                     AndroidPermissionManager.startAction( | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |                         kActionApplicationDetailsSettings); | 
					
						
							| 
									
										
										
										
											2022-07-14 18:33:41 +08:00
										 |  |  |                   } | 
					
						
							| 
									
										
										
										
											2022-07-16 22:31:44 +08:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-07-14 18:33:41 +08:00
										 |  |  |               })); | 
					
						
							| 
									
										
										
										
											2022-07-14 17:44:37 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |     enhancementsTiles.add(SettingsTile.switchTile( | 
					
						
							|  |  |  |         initialValue: _enableStartOnBoot, | 
					
						
							|  |  |  |         title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ | 
					
						
							| 
									
										
										
										
											2023-02-28 21:02:42 +09:00
										 |  |  |           Text("${translate('Start on Boot')} (beta)"), | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |           Text( | 
					
						
							| 
									
										
										
										
											2023-03-01 00:14:37 +09:00
										 |  |  |               '* ${translate('Start the screen sharing service on boot, requires special permissions')}', | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |               style: Theme.of(context).textTheme.bodySmall), | 
					
						
							|  |  |  |         ]), | 
					
						
							| 
									
										
										
										
											2023-02-28 21:02:42 +09:00
										 |  |  |         onToggle: (toValue) async { | 
					
						
							|  |  |  |           if (toValue) { | 
					
						
							|  |  |  |             // 1. request kIgnoreBatteryOptimizations
 | 
					
						
							|  |  |  |             if (!await AndroidPermissionManager.check( | 
					
						
							|  |  |  |                 kRequestIgnoreBatteryOptimizations)) { | 
					
						
							|  |  |  |               if (!await AndroidPermissionManager.request( | 
					
						
							|  |  |  |                   kRequestIgnoreBatteryOptimizations)) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // 2. request kSystemAlertWindow
 | 
					
						
							|  |  |  |             if (!await AndroidPermissionManager.check(kSystemAlertWindow)) { | 
					
						
							|  |  |  |               if (!await AndroidPermissionManager.request(kSystemAlertWindow)) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // (Optional) 3. request input permission
 | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2023-02-28 21:02:42 +09:00
										 |  |  |           setState(() => _enableStartOnBoot = toValue); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, toValue); | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |         })); | 
					
						
							| 
									
										
										
										
											2022-07-14 17:44:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |     return SettingsList( | 
					
						
							|  |  |  |       sections: [ | 
					
						
							|  |  |  |         SettingsSection( | 
					
						
							| 
									
										
										
										
											2022-10-22 22:19:14 +08:00
										 |  |  |           title: Text(translate('Account')), | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |           tiles: [ | 
					
						
							|  |  |  |             SettingsTile.navigation( | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |               title: Obx(() => Text(gFFI.userModel.userName.value.isEmpty | 
					
						
							| 
									
										
										
										
											2022-10-22 22:19:14 +08:00
										 |  |  |                   ? translate('Login') | 
					
						
							|  |  |  |                   : '${translate('Logout')} (${gFFI.userModel.userName.value})')), | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |               leading: Icon(Icons.person), | 
					
						
							|  |  |  |               onPressed: (context) { | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |                 if (gFFI.userModel.userName.value.isEmpty) { | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |                   loginDialog(); | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |                   gFFI.userModel.logOut(); | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |                 } | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-07-14 18:33:41 +08:00
										 |  |  |         SettingsSection(title: Text(translate("Settings")), tiles: [ | 
					
						
							|  |  |  |           SettingsTile.navigation( | 
					
						
							| 
									
										
										
										
											2022-03-24 21:31:47 +08:00
										 |  |  |               title: Text(translate('ID/Relay Server')), | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |               leading: Icon(Icons.cloud), | 
					
						
							|  |  |  |               onPressed: (context) { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |                 showServerSettings(gFFI.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |               }), | 
					
						
							|  |  |  |           SettingsTile.navigation( | 
					
						
							|  |  |  |               title: Text(translate('Language')), | 
					
						
							|  |  |  |               leading: Icon(Icons.translate), | 
					
						
							|  |  |  |               onPressed: (context) { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |                 showLanguageSettings(gFFI.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |               }), | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |           SettingsTile.navigation( | 
					
						
							| 
									
										
										
										
											2023-03-03 18:38:37 +01:00
										 |  |  |             title: Text(translate( | 
					
						
							|  |  |  |                 Theme.of(context).brightness == Brightness.light | 
					
						
							|  |  |  |                     ? 'Dark Theme' | 
					
						
							|  |  |  |                     : 'Light Theme')), | 
					
						
							|  |  |  |             leading: Icon(Theme.of(context).brightness == Brightness.light | 
					
						
							|  |  |  |                 ? Icons.dark_mode | 
					
						
							|  |  |  |                 : Icons.light_mode), | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |             onPressed: (context) { | 
					
						
							|  |  |  |               showThemeSettings(gFFI.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |             }, | 
					
						
							|  |  |  |           ) | 
					
						
							| 
									
										
										
										
											2022-07-14 18:33:41 +08:00
										 |  |  |         ]), | 
					
						
							| 
									
										
										
										
											2022-10-25 10:16:11 +09:00
										 |  |  |         SettingsSection( | 
					
						
							|  |  |  |           title: Text(translate("Recording")), | 
					
						
							|  |  |  |           tiles: [ | 
					
						
							|  |  |  |             SettingsTile.switchTile( | 
					
						
							|  |  |  |               title: Text(translate('Automatically record incoming sessions')), | 
					
						
							|  |  |  |               leading: Icon(Icons.videocam), | 
					
						
							|  |  |  |               description: FutureBuilder( | 
					
						
							|  |  |  |                   builder: (ctx, data) => Offstage( | 
					
						
							|  |  |  |                       offstage: !data.hasData, | 
					
						
							|  |  |  |                       child: Text("${translate("Directory")}: ${data.data}")), | 
					
						
							|  |  |  |                   future: bind.mainDefaultVideoSaveDirectory()), | 
					
						
							|  |  |  |               initialValue: _autoRecordIncomingSession, | 
					
						
							|  |  |  |               onToggle: (v) async { | 
					
						
							|  |  |  |                 await bind.mainSetOption( | 
					
						
							|  |  |  |                     key: "allow-auto-record-incoming", | 
					
						
							|  |  |  |                     value: bool2option("allow-auto-record-incoming", v)); | 
					
						
							|  |  |  |                 final newValue = option2bool( | 
					
						
							|  |  |  |                     'allow-auto-record-incoming', | 
					
						
							|  |  |  |                     await bind.mainGetOption( | 
					
						
							|  |  |  |                         key: 'allow-auto-record-incoming')); | 
					
						
							|  |  |  |                 setState(() { | 
					
						
							|  |  |  |                   _autoRecordIncomingSession = newValue; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-09-26 11:21:40 +08:00
										 |  |  |         SettingsSection( | 
					
						
							|  |  |  |           title: Text(translate("Share Screen")), | 
					
						
							|  |  |  |           tiles: shareScreenTiles, | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |         SettingsSection( | 
					
						
							| 
									
										
										
										
											2022-07-14 18:33:41 +08:00
										 |  |  |           title: Text(translate("Enhancements")), | 
					
						
							|  |  |  |           tiles: enhancementsTiles, | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |         SettingsSection( | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |           title: Text(translate("About")), | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |           tiles: [ | 
					
						
							|  |  |  |             SettingsTile.navigation( | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |                 onPressed: (context) async { | 
					
						
							| 
									
										
										
										
											2022-06-19 17:15:37 +01:00
										 |  |  |                   if (await canLaunchUrl(Uri.parse(url))) { | 
					
						
							|  |  |  |                     await launchUrl(Uri.parse(url)); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |                   } | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |                 title: Text(translate("Version: ") + version), | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |                 value: Padding( | 
					
						
							|  |  |  |                   padding: EdgeInsets.symmetric(vertical: 8), | 
					
						
							|  |  |  |                   child: Text('rustdesk.com', | 
					
						
							|  |  |  |                       style: TextStyle( | 
					
						
							|  |  |  |                         decoration: TextDecoration.underline, | 
					
						
							|  |  |  |                       )), | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |                 ), | 
					
						
							|  |  |  |                 leading: Icon(Icons.info)), | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 22:26:47 +09:00
										 |  |  |   Future<bool> canStartOnBoot() async { | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |     // start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW
 | 
					
						
							|  |  |  |     if (_hasIgnoreBattery && !_ignoreBatteryOpt) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-28 22:26:47 +09:00
										 |  |  |     if (!await AndroidPermissionManager.check(kSystemAlertWindow)) { | 
					
						
							| 
									
										
										
										
											2023-02-28 11:31:30 +09:00
										 |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  | void showServerSettings(OverlayDialogManager dialogManager) async { | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |   Map<String, dynamic> options = jsonDecode(await bind.mainGetOptions()); | 
					
						
							| 
									
										
										
										
											2022-12-21 16:24:01 +09:00
										 |  |  |   showServerSettingsWithValue(ServerConfig.fromOptions(options), dialogManager); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-24 20:57:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  | void showLanguageSettings(OverlayDialogManager dialogManager) async { | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |   try { | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |     final langs = json.decode(await bind.mainGetLangs()) as List<dynamic>; | 
					
						
							| 
									
										
										
										
											2023-01-08 23:30:34 +09:00
										 |  |  |     var lang = bind.mainGetLocalOption(key: "lang"); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |       setLang(v) { | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |         if (lang != v) { | 
					
						
							|  |  |  |           setState(() { | 
					
						
							|  |  |  |             lang = v; | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2022-08-05 20:29:43 +08:00
										 |  |  |           bind.mainSetLocalOption(key: "lang", value: v); | 
					
						
							|  |  |  |           HomePage.homeKey.currentState?.refreshPages(); | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |           Future.delayed(Duration(milliseconds: 200), close); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |       return CustomAlertDialog( | 
					
						
							| 
									
										
										
										
											2023-03-30 01:51:29 +02:00
										 |  |  |         content: Column( | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |                 getRadio('Default', '', lang, setLang), | 
					
						
							|  |  |  |                 Divider(color: MyTheme.border), | 
					
						
							|  |  |  |               ] + | 
					
						
							|  |  |  |               langs.map((e) { | 
					
						
							|  |  |  |                 final key = e[0] as String; | 
					
						
							|  |  |  |                 final name = e[1] as String; | 
					
						
							|  |  |  |                 return getRadio(name, key, lang, setLang); | 
					
						
							|  |  |  |               }).toList(), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |     }, backDismiss: true, clickMaskDismiss: true); | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |   } catch (e) { | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void showThemeSettings(OverlayDialogManager dialogManager) async { | 
					
						
							|  |  |  |   var themeMode = MyTheme.getThemeModePreference(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dialogManager.show((setState, close) { | 
					
						
							|  |  |  |     setTheme(v) { | 
					
						
							|  |  |  |       if (themeMode != v) { | 
					
						
							|  |  |  |         setState(() { | 
					
						
							|  |  |  |           themeMode = v; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         MyTheme.changeDarkMode(themeMode); | 
					
						
							|  |  |  |         Future.delayed(Duration(milliseconds: 200), close); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return CustomAlertDialog( | 
					
						
							| 
									
										
										
										
											2023-03-30 01:51:29 +02:00
										 |  |  |       content: Column(children: [ | 
					
						
							|  |  |  |         getRadio('Light', ThemeMode.light, themeMode, setTheme), | 
					
						
							|  |  |  |         getRadio('Dark', ThemeMode.dark, themeMode, setTheme), | 
					
						
							|  |  |  |         getRadio('Follow System', ThemeMode.system, themeMode, setTheme) | 
					
						
							|  |  |  |       ]), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |   }, backDismiss: true, clickMaskDismiss: true); | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  | void showAbout(OverlayDialogManager dialogManager) { | 
					
						
							|  |  |  |   dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-03-24 20:57:30 +08:00
										 |  |  |     return CustomAlertDialog( | 
					
						
							| 
									
										
										
										
											2022-09-22 15:12:23 +08:00
										 |  |  |       title: Text('${translate('About')} RustDesk'), | 
					
						
							| 
									
										
										
										
											2022-03-24 20:57:30 +08:00
										 |  |  |       content: Wrap(direction: Axis.vertical, spacing: 12, children: [ | 
					
						
							|  |  |  |         Text('Version: $version'), | 
					
						
							|  |  |  |         InkWell( | 
					
						
							|  |  |  |             onTap: () async { | 
					
						
							|  |  |  |               const url = 'https://rustdesk.com/'; | 
					
						
							| 
									
										
										
										
											2022-06-19 17:15:37 +01:00
										 |  |  |               if (await canLaunchUrl(Uri.parse(url))) { | 
					
						
							|  |  |  |                 await launchUrl(Uri.parse(url)); | 
					
						
							| 
									
										
										
										
											2022-03-24 20:57:30 +08:00
										 |  |  |               } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             child: Padding( | 
					
						
							|  |  |  |               padding: EdgeInsets.symmetric(vertical: 8), | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |               child: Text('rustdesk.com', | 
					
						
							| 
									
										
										
										
											2022-03-24 20:57:30 +08:00
										 |  |  |                   style: TextStyle( | 
					
						
							|  |  |  |                     decoration: TextDecoration.underline, | 
					
						
							|  |  |  |                   )), | 
					
						
							|  |  |  |             )), | 
					
						
							|  |  |  |       ]), | 
					
						
							| 
									
										
										
										
											2022-03-24 21:23:22 +08:00
										 |  |  |       actions: [], | 
					
						
							| 
									
										
										
										
											2022-03-24 20:57:30 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-04-21 10:02:47 +08:00
										 |  |  |   }, clickMaskDismiss: true, backDismiss: true); | 
					
						
							| 
									
										
										
										
											2022-03-24 20:57:30 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  | class ScanButton extends StatelessWidget { | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return IconButton( | 
					
						
							|  |  |  |       icon: Icon(Icons.qr_code_scanner), | 
					
						
							|  |  |  |       onPressed: () { | 
					
						
							|  |  |  |         Navigator.push( | 
					
						
							|  |  |  |           context, | 
					
						
							|  |  |  |           MaterialPageRoute( | 
					
						
							|  |  |  |             builder: (BuildContext context) => ScanPage(), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |