| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  | import 'package:file_picker/file_picker.dart'; | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/common.dart'; | 
					
						
							| 
									
										
										
										
											2023-03-01 14:18:46 +08:00
										 |  |  | import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  | import 'package:flutter_hbb/models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2023-03-01 14:18:46 +08:00
										 |  |  | import 'package:flutter_hbb/models/state_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							|  |  |  | import 'package:url_launcher/url_launcher_string.dart'; | 
					
						
							|  |  |  | import 'package:window_manager/window_manager.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class InstallPage extends StatefulWidget { | 
					
						
							|  |  |  |   const InstallPage({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<InstallPage> createState() => _InstallPageState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 14:18:46 +08:00
										 |  |  | class _InstallPageState extends State<InstallPage> { | 
					
						
							|  |  |  |   final tabController = DesktopTabController(tabType: DesktopTabType.main); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     Get.put<DesktopTabController>(tabController); | 
					
						
							|  |  |  |     const lable = "install"; | 
					
						
							|  |  |  |     tabController.add(TabInfo( | 
					
						
							|  |  |  |         key: lable, | 
					
						
							|  |  |  |         label: lable, | 
					
						
							|  |  |  |         closable: false, | 
					
						
							|  |  |  |         page: _InstallPageBody( | 
					
						
							|  |  |  |           key: const ValueKey(lable), | 
					
						
							|  |  |  |         ))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |     Get.delete<DesktopTabController>(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return DragToResizeArea( | 
					
						
							|  |  |  |       resizeEdgeSize: stateGlobal.resizeEdgeSize.value, | 
					
						
							|  |  |  |       child: Container( | 
					
						
							|  |  |  |         child: Scaffold( | 
					
						
							|  |  |  |             backgroundColor: Theme.of(context).colorScheme.background, | 
					
						
							|  |  |  |             body: DesktopTab(controller: tabController)), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _InstallPageBody extends StatefulWidget { | 
					
						
							|  |  |  |   const _InstallPageBody({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<_InstallPageBody> createState() => _InstallPageBodyState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _InstallPageBodyState extends State<_InstallPageBody> | 
					
						
							|  |  |  |     with WindowListener { | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |   late final TextEditingController controller; | 
					
						
							|  |  |  |   final RxBool startmenu = true.obs; | 
					
						
							|  |  |  |   final RxBool desktopicon = true.obs; | 
					
						
							|  |  |  |   final RxBool showProgress = false.obs; | 
					
						
							|  |  |  |   final RxBool btnEnabled = true.obs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     windowManager.addListener(this); | 
					
						
							|  |  |  |     controller = TextEditingController(text: bind.installInstallPath()); | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     windowManager.removeListener(this); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void onWindowClose() { | 
					
						
							|  |  |  |     gFFI.close(); | 
					
						
							|  |  |  |     super.onWindowClose(); | 
					
						
							|  |  |  |     windowManager.setPreventClose(false); | 
					
						
							|  |  |  |     windowManager.close(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     final double em = 13; | 
					
						
							|  |  |  |     final btnFontSize = 0.9 * em; | 
					
						
							|  |  |  |     final double button_radius = 6; | 
					
						
							| 
									
										
										
										
											2023-02-27 17:54:18 +08:00
										 |  |  |     final isDarkTheme = MyTheme.currentThemeMode() == ThemeMode.dark; | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |     final buttonStyle = OutlinedButton.styleFrom( | 
					
						
							|  |  |  |         shape: RoundedRectangleBorder( | 
					
						
							|  |  |  |       borderRadius: BorderRadius.all(Radius.circular(button_radius)), | 
					
						
							|  |  |  |     )); | 
					
						
							|  |  |  |     final inputBorder = OutlineInputBorder( | 
					
						
							|  |  |  |         borderRadius: BorderRadius.zero, | 
					
						
							| 
									
										
										
										
											2023-02-27 17:54:18 +08:00
										 |  |  |         borderSide: | 
					
						
							|  |  |  |             BorderSide(color: isDarkTheme ? Colors.white70 : Colors.black12)); | 
					
						
							|  |  |  |     final textColor = isDarkTheme ? null : Colors.black87; | 
					
						
							|  |  |  |     final dividerColor = isDarkTheme ? Colors.white70 : Colors.black87; | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |     return Scaffold( | 
					
						
							| 
									
										
										
										
											2023-02-27 17:54:18 +08:00
										 |  |  |         backgroundColor: null, | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |         body: SingleChildScrollView( | 
					
						
							|  |  |  |           child: Column( | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Text( | 
					
						
							|  |  |  |                     translate('Installation'), | 
					
						
							|  |  |  |                     style: TextStyle( | 
					
						
							|  |  |  |                         fontSize: 2 * em, fontWeight: FontWeight.w500), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Text('${translate('Installation Path')}: '), | 
					
						
							|  |  |  |                   Expanded( | 
					
						
							|  |  |  |                       child: TextField( | 
					
						
							|  |  |  |                     controller: controller, | 
					
						
							|  |  |  |                     readOnly: true, | 
					
						
							|  |  |  |                     style: TextStyle( | 
					
						
							|  |  |  |                         fontSize: 1.5 * em, fontWeight: FontWeight.w400), | 
					
						
							|  |  |  |                     decoration: InputDecoration( | 
					
						
							|  |  |  |                       isDense: true, | 
					
						
							|  |  |  |                       contentPadding: EdgeInsets.all(0.75 * em), | 
					
						
							|  |  |  |                       enabledBorder: inputBorder, | 
					
						
							|  |  |  |                       border: inputBorder, | 
					
						
							|  |  |  |                       focusedBorder: inputBorder, | 
					
						
							|  |  |  |                       constraints: BoxConstraints(maxHeight: 3 * em), | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                   )), | 
					
						
							|  |  |  |                   Obx(() => OutlinedButton( | 
					
						
							|  |  |  |                           onPressed: | 
					
						
							|  |  |  |                               btnEnabled.value ? selectInstallPath : null, | 
					
						
							|  |  |  |                           style: buttonStyle, | 
					
						
							|  |  |  |                           child: Text(translate('Change Path'), | 
					
						
							|  |  |  |                               style: TextStyle( | 
					
						
							| 
									
										
										
										
											2023-02-27 17:54:18 +08:00
										 |  |  |                                   color: textColor, fontSize: btnFontSize))) | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |                       .marginOnly(left: em)) | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ).marginSymmetric(vertical: 2 * em), | 
					
						
							|  |  |  |               Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Obx(() => Checkbox( | 
					
						
							|  |  |  |                       value: startmenu.value, | 
					
						
							|  |  |  |                       onChanged: (b) { | 
					
						
							|  |  |  |                         if (b != null) startmenu.value = b; | 
					
						
							|  |  |  |                       })), | 
					
						
							|  |  |  |                   Text(translate('Create start menu shortcuts')) | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Obx(() => Checkbox( | 
					
						
							|  |  |  |                       value: desktopicon.value, | 
					
						
							|  |  |  |                       onChanged: (b) { | 
					
						
							|  |  |  |                         if (b != null) desktopicon.value = b; | 
					
						
							|  |  |  |                       })), | 
					
						
							|  |  |  |                   Text(translate('Create desktop icon')) | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               GestureDetector( | 
					
						
							|  |  |  |                   onTap: () => launchUrlString('http://rustdesk.com/privacy'), | 
					
						
							|  |  |  |                   child: Row( | 
					
						
							|  |  |  |                     children: [ | 
					
						
							|  |  |  |                       Text(translate('End-user license agreement'), | 
					
						
							|  |  |  |                           style: const TextStyle( | 
					
						
							|  |  |  |                               decoration: TextDecoration.underline)) | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                   )).marginOnly(top: 2 * em), | 
					
						
							|  |  |  |               Row(children: [Text(translate('agreement_tip'))]) | 
					
						
							|  |  |  |                   .marginOnly(top: em), | 
					
						
							| 
									
										
										
										
											2023-02-27 17:54:18 +08:00
										 |  |  |               Divider(color: dividerColor).marginSymmetric(vertical: 0.5 * em), | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |               Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Expanded( | 
					
						
							|  |  |  |                       child: Obx(() => Offstage( | 
					
						
							|  |  |  |                             offstage: !showProgress.value, | 
					
						
							|  |  |  |                             child: LinearProgressIndicator(), | 
					
						
							|  |  |  |                           ))), | 
					
						
							|  |  |  |                   Obx(() => OutlinedButton( | 
					
						
							|  |  |  |                           onPressed: btnEnabled.value | 
					
						
							|  |  |  |                               ? () => windowManager.close() | 
					
						
							|  |  |  |                               : null, | 
					
						
							|  |  |  |                           style: buttonStyle, | 
					
						
							|  |  |  |                           child: Text(translate('Cancel'), | 
					
						
							|  |  |  |                               style: TextStyle( | 
					
						
							| 
									
										
										
										
											2023-02-27 17:54:18 +08:00
										 |  |  |                                   color: textColor, fontSize: btnFontSize))) | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |                       .marginOnly(right: 2 * em)), | 
					
						
							|  |  |  |                   Obx(() => ElevatedButton( | 
					
						
							|  |  |  |                       onPressed: btnEnabled.value ? install : null, | 
					
						
							|  |  |  |                       style: ElevatedButton.styleFrom( | 
					
						
							|  |  |  |                           primary: MyTheme.button, | 
					
						
							|  |  |  |                           shape: RoundedRectangleBorder( | 
					
						
							|  |  |  |                             borderRadius: BorderRadius.all( | 
					
						
							|  |  |  |                                 Radius.circular(button_radius)), | 
					
						
							|  |  |  |                           )), | 
					
						
							|  |  |  |                       child: Text( | 
					
						
							|  |  |  |                         translate('Accept and Install'), | 
					
						
							|  |  |  |                         style: TextStyle(fontSize: btnFontSize), | 
					
						
							|  |  |  |                       ))), | 
					
						
							|  |  |  |                   Offstage( | 
					
						
							|  |  |  |                     offstage: bind.installShowRunWithoutInstall(), | 
					
						
							|  |  |  |                     child: Obx(() => OutlinedButton( | 
					
						
							|  |  |  |                             onPressed: btnEnabled.value | 
					
						
							|  |  |  |                                 ? () => bind.installRunWithoutInstall() | 
					
						
							|  |  |  |                                 : null, | 
					
						
							|  |  |  |                             style: buttonStyle, | 
					
						
							|  |  |  |                             child: Text(translate('Run without install'), | 
					
						
							|  |  |  |                                 style: TextStyle( | 
					
						
							| 
									
										
										
										
											2023-02-27 17:54:18 +08:00
										 |  |  |                                     color: textColor, fontSize: btnFontSize))) | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |                         .marginOnly(left: 2 * em)), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           ).paddingSymmetric(horizontal: 8 * em, vertical: 2 * em), | 
					
						
							|  |  |  |         )); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void install() { | 
					
						
							|  |  |  |     btnEnabled.value = false; | 
					
						
							|  |  |  |     showProgress.value = true; | 
					
						
							| 
									
										
										
										
											2022-10-23 19:52:30 +08:00
										 |  |  |     String args = ''; | 
					
						
							| 
									
										
										
										
											2022-10-11 14:52:46 +08:00
										 |  |  |     if (startmenu.value) args += ' startmenu'; | 
					
						
							|  |  |  |     if (desktopicon.value) args += ' desktopicon'; | 
					
						
							| 
									
										
										
										
											2022-10-09 20:32:28 +08:00
										 |  |  |     bind.installInstallMe(options: args, path: controller.text); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void selectInstallPath() async { | 
					
						
							|  |  |  |     String? install_path = await FilePicker.platform | 
					
						
							|  |  |  |         .getDirectoryPath(initialDirectory: controller.text); | 
					
						
							|  |  |  |     if (install_path != null) { | 
					
						
							|  |  |  |       install_path = '$install_path\\${await bind.mainGetAppName()}'; | 
					
						
							|  |  |  |       controller.text = install_path; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |