| 
									
										
										
										
											2022-09-15 17:41:10 +08:00
										 |  |  | // original cm window in Sciter version.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							| 
									
										
										
										
											2023-02-10 21:18:55 +08:00
										 |  |  | import 'dart:io'; | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-06 11:18:12 +08:00
										 |  |  | import 'package:flutter_hbb/consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  | import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/models/chat_model.dart'; | 
					
						
							| 
									
										
										
										
											2023-02-10 21:18:55 +08:00
										 |  |  | import 'package:flutter_hbb/utils/platform_channel.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | import 'package:provider/provider.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  | import 'package:window_manager/window_manager.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 18:34:05 +08:00
										 |  |  | import 'package:flutter_svg/flutter_svg.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import '../../common.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-25 21:36:01 +09:00
										 |  |  | import '../../common/widgets/chat_page.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							|  |  |  | import '../../models/server_model.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  | class DesktopServerPage extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |   const DesktopServerPage({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |   State<DesktopServerPage> createState() => _DesktopServerPageState(); | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  | class _DesktopServerPageState extends State<DesktopServerPage> | 
					
						
							| 
									
										
										
										
											2022-08-23 21:28:44 +08:00
										 |  |  |     with WindowListener, AutomaticKeepAliveClientMixin { | 
					
						
							| 
									
										
										
										
											2022-09-01 21:18:53 +08:00
										 |  |  |   final tabController = gFFI.serverModel.tabController; | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |   void initState() { | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |     gFFI.ffiModel.updateEventListener(gFFI.sessionId, ""); | 
					
						
							| 
									
										
										
										
											2022-08-23 21:28:44 +08:00
										 |  |  |     windowManager.addListener(this); | 
					
						
							| 
									
										
										
										
											2023-01-23 22:07:50 +08:00
										 |  |  |     tabController.onRemoved = (_, id) { | 
					
						
							|  |  |  |       onRemoveId(id); | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |     super.initState(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 21:28:44 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     windowManager.removeListener(this); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void onWindowClose() { | 
					
						
							| 
									
										
										
										
											2023-02-23 16:49:31 +01:00
										 |  |  |     Future.wait([gFFI.serverModel.closeAll(), gFFI.close()]).then((_) { | 
					
						
							| 
									
										
										
										
											2023-02-10 21:18:55 +08:00
										 |  |  |       if (Platform.isMacOS) { | 
					
						
							|  |  |  |         RdPlatformChannel.instance.terminate(); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         windowManager.setPreventClose(false); | 
					
						
							|  |  |  |         windowManager.close(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-08-23 21:28:44 +08:00
										 |  |  |     super.onWindowClose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 21:18:53 +08:00
										 |  |  |   void onRemoveId(String id) { | 
					
						
							|  |  |  |     if (tabController.state.value.tabs.isEmpty) { | 
					
						
							|  |  |  |       windowManager.close(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |     super.build(context); | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  |     return MultiProvider( | 
					
						
							| 
									
										
										
										
											2023-05-18 22:10:49 +02:00
										 |  |  |       providers: [ | 
					
						
							|  |  |  |         ChangeNotifierProvider.value(value: gFFI.serverModel), | 
					
						
							|  |  |  |         ChangeNotifierProvider.value(value: gFFI.chatModel), | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |       child: Consumer<ServerModel>( | 
					
						
							|  |  |  |         builder: (context, serverModel, child) => Container( | 
					
						
							|  |  |  |           decoration: BoxDecoration( | 
					
						
							|  |  |  |               border: Border.all(color: MyTheme.color(context).border!)), | 
					
						
							|  |  |  |           child: Scaffold( | 
					
						
							|  |  |  |             backgroundColor: Theme.of(context).scaffoldBackgroundColor, | 
					
						
							| 
									
										
										
										
											2023-05-21 10:20:40 +02:00
										 |  |  |             body: ConnectionManager(), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:10:49 +02:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   bool get wantKeepAlive => true; | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  | class ConnectionManager extends StatefulWidget { | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<StatefulWidget> createState() => ConnectionManagerState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ConnectionManagerState extends State<ConnectionManager> { | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     gFFI.serverModel.updateClientState(); | 
					
						
							| 
									
										
										
										
											2023-06-07 20:31:54 +08:00
										 |  |  |     gFFI.serverModel.tabController.onSelected = (client_id_str) { | 
					
						
							|  |  |  |       final client_id = int.tryParse(client_id_str); | 
					
						
							|  |  |  |       if (client_id != null) { | 
					
						
							| 
									
										
										
										
											2023-07-05 10:56:54 +08:00
										 |  |  |         final client = | 
					
						
							|  |  |  |             gFFI.serverModel.clients.firstWhereOrNull((e) => e.id == client_id); | 
					
						
							|  |  |  |         if (client != null) { | 
					
						
							| 
									
										
										
										
											2023-07-10 16:02:47 +08:00
										 |  |  |           gFFI.chatModel.changeCurrentKey(MessageKey(client.peerId, client.id)); | 
					
						
							| 
									
										
										
										
											2023-07-08 11:09:50 +08:00
										 |  |  |           if (client.unreadChatMessageCount.value > 0) { | 
					
						
							|  |  |  |             Future.delayed(Duration.zero, () { | 
					
						
							|  |  |  |               client.unreadChatMessageCount.value = 0; | 
					
						
							| 
									
										
										
										
											2023-07-09 19:14:57 +08:00
										 |  |  |               gFFI.chatModel.showChatPage(MessageKey(client.peerId, client.id)); | 
					
						
							| 
									
										
										
										
											2023-07-08 11:09:50 +08:00
										 |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2023-07-05 10:56:54 +08:00
										 |  |  |           windowManager.setTitle(getWindowNameWithId(client.peerId)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-06-07 20:31:54 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2022-11-04 21:43:51 +08:00
										 |  |  |     gFFI.chatModel.isConnManager = true; | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  |     super.initState(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     final serverModel = Provider.of<ServerModel>(context); | 
					
						
							| 
									
										
										
										
											2022-11-23 14:23:57 +08:00
										 |  |  |     pointerHandler(PointerEvent e) { | 
					
						
							|  |  |  |       if (serverModel.cmHiddenTimer != null) { | 
					
						
							|  |  |  |         serverModel.cmHiddenTimer!.cancel(); | 
					
						
							|  |  |  |         serverModel.cmHiddenTimer = null; | 
					
						
							|  |  |  |         debugPrint("CM hidden timer has been canceled"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |     return serverModel.clients.isEmpty | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |         ? Column( | 
					
						
							|  |  |  |             children: [ | 
					
						
							| 
									
										
										
										
											2022-09-06 11:18:12 +08:00
										 |  |  |               buildTitleBar(), | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: Center( | 
					
						
							|  |  |  |                   child: Text(translate("Waiting")), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ], | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |           ) | 
					
						
							| 
									
										
										
										
											2022-10-26 21:39:28 +09:00
										 |  |  |         : Listener( | 
					
						
							|  |  |  |             onPointerDown: pointerHandler, | 
					
						
							|  |  |  |             onPointerMove: pointerHandler, | 
					
						
							|  |  |  |             child: DesktopTab( | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |               showTitle: false, | 
					
						
							|  |  |  |               showMaximize: false, | 
					
						
							|  |  |  |               showMinimize: true, | 
					
						
							|  |  |  |               showClose: true, | 
					
						
							|  |  |  |               onWindowCloseButton: handleWindowCloseButton, | 
					
						
							|  |  |  |               controller: serverModel.tabController, | 
					
						
							| 
									
										
										
										
											2023-07-08 17:55:55 +08:00
										 |  |  |               selectedBorderColor: MyTheme.accent, | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |               maxLabelWidth: 100, | 
					
						
							|  |  |  |               tail: buildScrollJumper(), | 
					
						
							|  |  |  |               selectedTabBackgroundColor: | 
					
						
							| 
									
										
										
										
											2023-07-08 17:55:55 +08:00
										 |  |  |                   Theme.of(context).hintColor.withOpacity(0), | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |               tabBuilder: (key, icon, label, themeConf) { | 
					
						
							|  |  |  |                 final client = serverModel.clients | 
					
						
							|  |  |  |                     .firstWhereOrNull((client) => client.id.toString() == key); | 
					
						
							|  |  |  |                 return Row( | 
					
						
							|  |  |  |                   mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     Tooltip( | 
					
						
							|  |  |  |                         message: key, | 
					
						
							|  |  |  |                         waitDuration: Duration(seconds: 1), | 
					
						
							|  |  |  |                         child: label), | 
					
						
							| 
									
										
										
										
											2023-07-10 21:03:35 +08:00
										 |  |  |                     unreadMessageCountBuilder(client?.unreadChatMessageCount) | 
					
						
							|  |  |  |                         .marginOnly(left: 4), | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |                   ], | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |               pageViewBuilder: (pageView) => Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Consumer<ChatModel>( | 
					
						
							| 
									
										
										
										
											2023-05-21 10:20:40 +02:00
										 |  |  |                     builder: (_, model, child) => model.isShowCMChatPage | 
					
						
							|  |  |  |                         ? Expanded( | 
					
						
							| 
									
										
										
										
											2023-07-05 17:35:37 +08:00
										 |  |  |                             child: buildRemoteBlock( | 
					
						
							| 
									
										
										
										
											2023-07-08 11:09:50 +08:00
										 |  |  |                               child: Container( | 
					
						
							|  |  |  |                                   decoration: BoxDecoration( | 
					
						
							|  |  |  |                                       border: Border( | 
					
						
							|  |  |  |                                           right: BorderSide( | 
					
						
							|  |  |  |                                               color: Theme.of(context) | 
					
						
							|  |  |  |                                                   .dividerColor))), | 
					
						
							| 
									
										
										
										
											2023-07-10 16:02:47 +08:00
										 |  |  |                                   child: | 
					
						
							|  |  |  |                                       ChatPage(type: ChatPageType.desktopCM)), | 
					
						
							| 
									
										
										
										
											2023-07-05 17:35:37 +08:00
										 |  |  |                             ), | 
					
						
							| 
									
										
										
										
											2023-07-11 10:05:31 +08:00
										 |  |  |                             flex: (kConnectionManagerWindowSizeOpenChat.width - | 
					
						
							|  |  |  |                                     kConnectionManagerWindowSizeClosedChat | 
					
						
							|  |  |  |                                         .width) | 
					
						
							|  |  |  |                                 .toInt(), | 
					
						
							| 
									
										
										
										
											2023-05-21 10:20:40 +02:00
										 |  |  |                           ) | 
					
						
							| 
									
										
										
										
											2023-07-11 10:01:56 +08:00
										 |  |  |                         : Offstage(), | 
					
						
							| 
									
										
										
										
											2023-05-21 10:20:40 +02:00
										 |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2023-07-11 10:05:31 +08:00
										 |  |  |                   Expanded( | 
					
						
							|  |  |  |                       child: pageView, | 
					
						
							|  |  |  |                       flex: kConnectionManagerWindowSizeClosedChat.width | 
					
						
							|  |  |  |                               .toInt() - | 
					
						
							|  |  |  |                           4 // prevent stretch of the page view when chat is open,
 | 
					
						
							|  |  |  |                       ), | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ); | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 11:18:12 +08:00
										 |  |  |   Widget buildTitleBar() { | 
					
						
							|  |  |  |     return SizedBox( | 
					
						
							|  |  |  |       height: kDesktopRemoteTabBarHeight, | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |       child: Row( | 
					
						
							|  |  |  |         crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |         children: [ | 
					
						
							| 
									
										
										
										
											2022-09-06 11:18:12 +08:00
										 |  |  |           const _AppIcon(), | 
					
						
							|  |  |  |           Expanded( | 
					
						
							|  |  |  |             child: GestureDetector( | 
					
						
							|  |  |  |               onPanStart: (d) { | 
					
						
							|  |  |  |                 windowManager.startDragging(); | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |               child: Container( | 
					
						
							| 
									
										
										
										
											2023-02-23 16:49:31 +01:00
										 |  |  |                 color: Theme.of(context).colorScheme.background, | 
					
						
							| 
									
										
										
										
											2022-09-06 11:18:12 +08:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |           const SizedBox( | 
					
						
							|  |  |  |             width: 4.0, | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-09-06 11:18:12 +08:00
										 |  |  |           const _CloseButton() | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-10-20 23:22:02 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Widget buildScrollJumper() { | 
					
						
							|  |  |  |     final offstage = gFFI.serverModel.clients.length < 2; | 
					
						
							|  |  |  |     final sc = gFFI.serverModel.tabController.state.value.scrollController; | 
					
						
							|  |  |  |     return Offstage( | 
					
						
							|  |  |  |         offstage: offstage, | 
					
						
							|  |  |  |         child: Row( | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             ActionIcon( | 
					
						
							|  |  |  |                 icon: Icons.arrow_left, iconSize: 22, onTap: sc.backward), | 
					
						
							|  |  |  |             ActionIcon( | 
					
						
							|  |  |  |                 icon: Icons.arrow_right, iconSize: 22, onTap: sc.forward), | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         )); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-11-06 21:21:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Future<bool> handleWindowCloseButton() async { | 
					
						
							|  |  |  |     var tabController = gFFI.serverModel.tabController; | 
					
						
							|  |  |  |     final connLength = tabController.length; | 
					
						
							|  |  |  |     if (connLength <= 1) { | 
					
						
							|  |  |  |       windowManager.close(); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       final opt = "enable-confirm-closing-tabs"; | 
					
						
							|  |  |  |       final bool res; | 
					
						
							| 
									
										
										
										
											2023-08-06 16:42:13 +08:00
										 |  |  |       if (!option2bool(opt, bind.mainGetLocalOption(key: opt))) { | 
					
						
							| 
									
										
										
										
											2022-11-06 21:21:57 +08:00
										 |  |  |         res = true; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         res = await closeConfirmDialog(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (res) { | 
					
						
							|  |  |  |         windowManager.close(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return res; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 21:52:21 +08:00
										 |  |  | Widget buildConnectionCard(Client client) { | 
					
						
							| 
									
										
										
										
											2022-10-08 20:15:02 +08:00
										 |  |  |   return Consumer<ServerModel>( | 
					
						
							| 
									
										
										
										
											2023-05-21 10:20:40 +02:00
										 |  |  |     builder: (context, value, child) => Column( | 
					
						
							|  |  |  |       mainAxisAlignment: MainAxisAlignment.start, | 
					
						
							|  |  |  |       crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |       key: ValueKey(client.id), | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         _CmHeader(client: client), | 
					
						
							|  |  |  |         client.type_() != ClientType.remote || client.disconnected | 
					
						
							|  |  |  |             ? Offstage() | 
					
						
							|  |  |  |             : _PrivilegeBoard(client: client), | 
					
						
							|  |  |  |         Expanded( | 
					
						
							|  |  |  |           child: Align( | 
					
						
							|  |  |  |             alignment: Alignment.bottomCenter, | 
					
						
							|  |  |  |             child: _CmControlPanel(client: client), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ).paddingSymmetric(vertical: 4.0, horizontal: 8.0), | 
					
						
							|  |  |  |   ); | 
					
						
							| 
									
										
										
										
											2022-08-24 21:52:21 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  | class _AppIcon extends StatelessWidget { | 
					
						
							|  |  |  |   const _AppIcon({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Container( | 
					
						
							|  |  |  |       margin: EdgeInsets.symmetric(horizontal: 4.0), | 
					
						
							| 
									
										
										
										
											2022-09-27 18:34:05 +08:00
										 |  |  |       child: SvgPicture.asset( | 
					
						
							|  |  |  |         'assets/logo.svg', | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |         width: 30, | 
					
						
							|  |  |  |         height: 30, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _CloseButton extends StatelessWidget { | 
					
						
							|  |  |  |   const _CloseButton({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-09-06 11:18:12 +08:00
										 |  |  |     return IconButton( | 
					
						
							|  |  |  |       onPressed: () { | 
					
						
							|  |  |  |         windowManager.close(); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       icon: const Icon( | 
					
						
							|  |  |  |         IconFont.close, | 
					
						
							|  |  |  |         size: 18, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       splashColor: Colors.transparent, | 
					
						
							|  |  |  |       hoverColor: Colors.transparent, | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  | class _CmHeader extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   final Client client; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const _CmHeader({Key? key, required this.client}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   State<_CmHeader> createState() => _CmHeaderState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _CmHeaderState extends State<_CmHeader> | 
					
						
							|  |  |  |     with AutomaticKeepAliveClientMixin { | 
					
						
							|  |  |  |   Client get client => widget.client; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-04 18:20:23 +08:00
										 |  |  |   final _time = 0.obs; | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  |   Timer? _timer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     _timer = Timer.periodic(Duration(seconds: 1), (_) { | 
					
						
							| 
									
										
										
										
											2022-11-21 18:45:36 +08:00
										 |  |  |       if (client.authorized && !client.disconnected) { | 
					
						
							|  |  |  |         _time.value = _time.value + 1; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-06-07 20:31:54 +08:00
										 |  |  |     gFFI.serverModel.tabController.onSelected?.call(client.id.toString()); | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _timer?.cancel(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  |     super.build(context); | 
					
						
							| 
									
										
										
										
											2023-05-18 22:59:07 +02:00
										 |  |  |     return Container( | 
					
						
							|  |  |  |       decoration: BoxDecoration( | 
					
						
							|  |  |  |         borderRadius: BorderRadius.circular(10.0), | 
					
						
							|  |  |  |         gradient: LinearGradient( | 
					
						
							|  |  |  |           begin: Alignment.topRight, | 
					
						
							|  |  |  |           end: Alignment.bottomLeft, | 
					
						
							|  |  |  |           colors: [ | 
					
						
							|  |  |  |             Color(0xff00bfe1), | 
					
						
							|  |  |  |             Color(0xff0071ff), | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |       margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 10.0), | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |       padding: EdgeInsets.only( | 
					
						
							|  |  |  |         top: 10.0, | 
					
						
							|  |  |  |         bottom: 10.0, | 
					
						
							|  |  |  |         left: 10.0, | 
					
						
							|  |  |  |         right: 5.0, | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:59:07 +02:00
										 |  |  |       child: Row( | 
					
						
							|  |  |  |         crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |         children: [ | 
					
						
							|  |  |  |           Container( | 
					
						
							|  |  |  |             width: 70, | 
					
						
							|  |  |  |             height: 70, | 
					
						
							|  |  |  |             alignment: Alignment.center, | 
					
						
							|  |  |  |             decoration: BoxDecoration( | 
					
						
							|  |  |  |               color: str2color(client.name), | 
					
						
							|  |  |  |               borderRadius: BorderRadius.circular(15.0), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             child: Text( | 
					
						
							|  |  |  |               client.name[0], | 
					
						
							|  |  |  |               style: TextStyle( | 
					
						
							|  |  |  |                 fontWeight: FontWeight.bold, | 
					
						
							|  |  |  |                 color: Colors.white, | 
					
						
							|  |  |  |                 fontSize: 55, | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:59:07 +02:00
										 |  |  |             ), | 
					
						
							|  |  |  |           ).marginOnly(right: 10.0), | 
					
						
							|  |  |  |           Expanded( | 
					
						
							|  |  |  |             child: Column( | 
					
						
							|  |  |  |               mainAxisAlignment: MainAxisAlignment.start, | 
					
						
							|  |  |  |               crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 FittedBox( | 
					
						
							|  |  |  |                     child: Text( | 
					
						
							|  |  |  |                   client.name, | 
					
						
							|  |  |  |                   style: TextStyle( | 
					
						
							|  |  |  |                     color: Colors.white, | 
					
						
							|  |  |  |                     fontWeight: FontWeight.bold, | 
					
						
							|  |  |  |                     fontSize: 20, | 
					
						
							|  |  |  |                     overflow: TextOverflow.ellipsis, | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                   maxLines: 1, | 
					
						
							|  |  |  |                 )), | 
					
						
							|  |  |  |                 FittedBox( | 
					
						
							|  |  |  |                   child: Text( | 
					
						
							|  |  |  |                     "(${client.peerId})", | 
					
						
							|  |  |  |                     style: TextStyle(color: Colors.white, fontSize: 14), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ).marginOnly(bottom: 10.0), | 
					
						
							|  |  |  |                 FittedBox( | 
					
						
							|  |  |  |                     child: Row( | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     Text( | 
					
						
							|  |  |  |                       client.authorized | 
					
						
							| 
									
										
										
										
											2022-11-21 18:45:36 +08:00
										 |  |  |                           ? client.disconnected | 
					
						
							|  |  |  |                               ? translate("Disconnected") | 
					
						
							|  |  |  |                               : translate("Connected") | 
					
						
							| 
									
										
										
										
											2023-05-18 22:59:07 +02:00
										 |  |  |                           : "${translate("Request access to your device")}...", | 
					
						
							|  |  |  |                       style: TextStyle(color: Colors.white), | 
					
						
							|  |  |  |                     ).marginOnly(right: 8.0), | 
					
						
							|  |  |  |                     if (client.authorized) | 
					
						
							|  |  |  |                       Obx( | 
					
						
							|  |  |  |                         () => Text( | 
					
						
							|  |  |  |                           formatDurationToTime( | 
					
						
							|  |  |  |                             Duration(seconds: _time.value), | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                           style: TextStyle(color: Colors.white), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                       ) | 
					
						
							|  |  |  |                   ], | 
					
						
							|  |  |  |                 )) | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |           ), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:59:07 +02:00
										 |  |  |           Offstage( | 
					
						
							|  |  |  |             offstage: !client.authorized || client.type_() != ClientType.remote, | 
					
						
							|  |  |  |             child: IconButton( | 
					
						
							| 
									
										
										
										
											2022-10-26 21:13:32 +09:00
										 |  |  |               onPressed: () => checkClickTime( | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                 client.id, | 
					
						
							| 
									
										
										
										
											2023-07-09 19:14:57 +08:00
										 |  |  |                 () => gFFI.chatModel | 
					
						
							|  |  |  |                     .toggleCMChatPage(MessageKey(client.peerId, client.id)), | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |               icon: SvgPicture.asset('assets/chat2.svg'), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:59:07 +02:00
										 |  |  |               splashRadius: kDesktopIconButtonSplashRadius, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   bool get wantKeepAlive => true; | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  | class _PrivilegeBoard extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   final Client client; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const _PrivilegeBoard({Key? key, required this.client}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   State<StatefulWidget> createState() => _PrivilegeBoardState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _PrivilegeBoardState extends State<_PrivilegeBoard> { | 
					
						
							|  |  |  |   late final client = widget.client; | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |   Widget buildPermissionIcon(bool enabled, IconData iconData, | 
					
						
							| 
									
										
										
										
											2023-05-20 18:33:40 +02:00
										 |  |  |       Function(bool)? onTap, String tooltipText) { | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |     return Tooltip( | 
					
						
							| 
									
										
										
										
											2023-06-03 22:19:39 +08:00
										 |  |  |       message: "$tooltipText: ${enabled ? "ON" : "OFF"}", | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |       child: Container( | 
					
						
							|  |  |  |         decoration: BoxDecoration( | 
					
						
							| 
									
										
										
										
											2023-05-20 18:30:13 +02:00
										 |  |  |           color: enabled ? MyTheme.accent : Colors.grey[700], | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |           borderRadius: BorderRadius.circular(10.0), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-05-21 14:24:51 +02:00
										 |  |  |         padding: EdgeInsets.all(8.0), | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |         child: InkWell( | 
					
						
							|  |  |  |           onTap: () => | 
					
						
							|  |  |  |               checkClickTime(widget.client.id, () => onTap?.call(!enabled)), | 
					
						
							| 
									
										
										
										
											2023-05-21 14:24:51 +02:00
										 |  |  |           child: Column( | 
					
						
							|  |  |  |             mainAxisAlignment: MainAxisAlignment.spaceAround, | 
					
						
							|  |  |  |             children: [ | 
					
						
							| 
									
										
										
										
											2023-05-29 16:09:23 +08:00
										 |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: Icon( | 
					
						
							|  |  |  |                   iconData, | 
					
						
							|  |  |  |                   color: Colors.white, | 
					
						
							| 
									
										
										
										
											2023-06-03 22:19:39 +08:00
										 |  |  |                   size: 32, | 
					
						
							| 
									
										
										
										
											2023-05-29 16:09:23 +08:00
										 |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2023-05-21 14:24:51 +02:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ], | 
					
						
							| 
									
										
										
										
											2023-05-18 22:10:49 +02:00
										 |  |  |           ), | 
					
						
							| 
									
										
										
										
											2023-05-18 11:41:16 +02:00
										 |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Container( | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |       width: double.infinity, | 
					
						
							|  |  |  |       height: 200.0, | 
					
						
							| 
									
										
										
										
											2023-05-18 22:59:07 +02:00
										 |  |  |       margin: EdgeInsets.all(5.0), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:10:49 +02:00
										 |  |  |       padding: EdgeInsets.all(5.0), | 
					
						
							|  |  |  |       decoration: BoxDecoration( | 
					
						
							|  |  |  |         borderRadius: BorderRadius.circular(10.0), | 
					
						
							|  |  |  |         color: Theme.of(context).colorScheme.background, | 
					
						
							|  |  |  |         boxShadow: [ | 
					
						
							|  |  |  |           BoxShadow( | 
					
						
							|  |  |  |             color: Colors.black.withOpacity(0.2), | 
					
						
							|  |  |  |             spreadRadius: 1, | 
					
						
							|  |  |  |             blurRadius: 1, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |             offset: Offset(0, 1.5), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:10:49 +02:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |       child: Column( | 
					
						
							| 
									
										
										
										
											2023-05-18 22:10:49 +02:00
										 |  |  |         crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         children: [ | 
					
						
							|  |  |  |           Text( | 
					
						
							|  |  |  |             translate("Permissions"), | 
					
						
							| 
									
										
										
										
											2023-05-18 22:10:49 +02:00
										 |  |  |             style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), | 
					
						
							|  |  |  |             textAlign: TextAlign.center, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |           ).marginOnly(left: 4.0, bottom: 8.0), | 
					
						
							|  |  |  |           Expanded( | 
					
						
							|  |  |  |             child: GridView.count( | 
					
						
							|  |  |  |               crossAxisCount: 3, | 
					
						
							|  |  |  |               padding: EdgeInsets.symmetric(horizontal: 20.0), | 
					
						
							|  |  |  |               mainAxisSpacing: 20.0, | 
					
						
							|  |  |  |               crossAxisSpacing: 20.0, | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 buildPermissionIcon( | 
					
						
							|  |  |  |                   client.keyboard, | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                   Icons.keyboard, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                   (enabled) { | 
					
						
							|  |  |  |                     bind.cmSwitchPermission( | 
					
						
							|  |  |  |                         connId: client.id, name: "keyboard", enabled: enabled); | 
					
						
							|  |  |  |                     setState(() { | 
					
						
							|  |  |  |                       client.keyboard = enabled; | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                   }, | 
					
						
							|  |  |  |                   translate('Allow using keyboard and mouse'), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 buildPermissionIcon( | 
					
						
							|  |  |  |                   client.clipboard, | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                   Icons.assignment_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                   (enabled) { | 
					
						
							|  |  |  |                     bind.cmSwitchPermission( | 
					
						
							|  |  |  |                         connId: client.id, name: "clipboard", enabled: enabled); | 
					
						
							|  |  |  |                     setState(() { | 
					
						
							|  |  |  |                       client.clipboard = enabled; | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                   }, | 
					
						
							|  |  |  |                   translate('Allow using clipboard'), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 buildPermissionIcon( | 
					
						
							|  |  |  |                   client.audio, | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                   Icons.volume_up_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                   (enabled) { | 
					
						
							|  |  |  |                     bind.cmSwitchPermission( | 
					
						
							|  |  |  |                         connId: client.id, name: "audio", enabled: enabled); | 
					
						
							|  |  |  |                     setState(() { | 
					
						
							|  |  |  |                       client.audio = enabled; | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                   }, | 
					
						
							|  |  |  |                   translate('Allow hearing sound'), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 buildPermissionIcon( | 
					
						
							|  |  |  |                   client.file, | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                   Icons.upload_file_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                   (enabled) { | 
					
						
							|  |  |  |                     bind.cmSwitchPermission( | 
					
						
							|  |  |  |                         connId: client.id, name: "file", enabled: enabled); | 
					
						
							|  |  |  |                     setState(() { | 
					
						
							|  |  |  |                       client.file = enabled; | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                   }, | 
					
						
							|  |  |  |                   translate('Allow file copy and paste'), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 buildPermissionIcon( | 
					
						
							|  |  |  |                   client.restart, | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                   Icons.restart_alt_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                   (enabled) { | 
					
						
							|  |  |  |                     bind.cmSwitchPermission( | 
					
						
							|  |  |  |                         connId: client.id, name: "restart", enabled: enabled); | 
					
						
							|  |  |  |                     setState(() { | 
					
						
							|  |  |  |                       client.restart = enabled; | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                   }, | 
					
						
							|  |  |  |                   translate('Allow remote restart'), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 buildPermissionIcon( | 
					
						
							|  |  |  |                   client.recording, | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                   Icons.videocam_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                   (enabled) { | 
					
						
							|  |  |  |                     bind.cmSwitchPermission( | 
					
						
							|  |  |  |                         connId: client.id, name: "recording", enabled: enabled); | 
					
						
							|  |  |  |                     setState(() { | 
					
						
							|  |  |  |                       client.recording = enabled; | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                   }, | 
					
						
							|  |  |  |                   translate('Allow recording session'), | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  | const double buttonBottomMargin = 8; | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  | class _CmControlPanel extends StatelessWidget { | 
					
						
							|  |  |  |   final Client client; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const _CmControlPanel({Key? key, required this.client}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-10-08 20:15:02 +08:00
										 |  |  |     return client.authorized | 
					
						
							|  |  |  |         ? client.disconnected | 
					
						
							|  |  |  |             ? buildDisconnected(context) | 
					
						
							|  |  |  |             : buildAuthorized(context) | 
					
						
							|  |  |  |         : buildUnAuthorized(context); | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |   buildAuthorized(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-11-10 10:27:13 +08:00
										 |  |  |     final bool canElevate = bind.cmCanElevate(); | 
					
						
							|  |  |  |     final model = Provider.of<ServerModel>(context); | 
					
						
							| 
									
										
										
										
											2022-12-04 18:47:02 +08:00
										 |  |  |     final showElevation = canElevate && | 
					
						
							|  |  |  |         model.showElevation && | 
					
						
							|  |  |  |         client.type_() == ClientType.remote; | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |     return Column( | 
					
						
							|  |  |  |       mainAxisAlignment: MainAxisAlignment.end, | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |       children: [ | 
					
						
							| 
									
										
										
										
											2023-02-07 16:11:55 +08:00
										 |  |  |         Offstage( | 
					
						
							|  |  |  |           offstage: !client.inVoiceCall, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |           child: buildButton( | 
					
						
							|  |  |  |             context, | 
					
						
							|  |  |  |             color: Colors.red, | 
					
						
							|  |  |  |             onClick: () => closeVoiceCall(), | 
					
						
							|  |  |  |             icon: Icon( | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |               Icons.call_end_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |               color: Colors.white, | 
					
						
							|  |  |  |               size: 14, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             text: "Stop voice call", | 
					
						
							|  |  |  |             textColor: Colors.white, | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2023-02-07 16:11:55 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |         Offstage( | 
					
						
							|  |  |  |           offstage: !client.incomingVoiceCall, | 
					
						
							|  |  |  |           child: Row( | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: buildButton(context, | 
					
						
							|  |  |  |                     color: MyTheme.accent, | 
					
						
							|  |  |  |                     onClick: () => handleVoiceCall(true), | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                     icon: Icon( | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                       Icons.call_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                       color: Colors.white, | 
					
						
							|  |  |  |                       size: 14, | 
					
						
							|  |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2023-02-07 16:11:55 +08:00
										 |  |  |                     text: "Accept", | 
					
						
							|  |  |  |                     textColor: Colors.white), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               Expanded( | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                 child: buildButton( | 
					
						
							|  |  |  |                   context, | 
					
						
							|  |  |  |                   color: Colors.red, | 
					
						
							|  |  |  |                   onClick: () => handleVoiceCall(false), | 
					
						
							|  |  |  |                   icon: Icon( | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                     Icons.phone_disabled_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                     color: Colors.white, | 
					
						
							|  |  |  |                     size: 14, | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                   text: "Dismiss", | 
					
						
							|  |  |  |                   textColor: Colors.white, | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2023-02-07 16:11:55 +08:00
										 |  |  |               ) | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-01-17 13:28:33 +08:00
										 |  |  |         Offstage( | 
					
						
							|  |  |  |           offstage: !client.fromSwitch, | 
					
						
							|  |  |  |           child: buildButton(context, | 
					
						
							|  |  |  |               color: Colors.purple, | 
					
						
							|  |  |  |               onClick: () => handleSwitchBack(context), | 
					
						
							|  |  |  |               icon: Icon(Icons.reply, color: Colors.white), | 
					
						
							|  |  |  |               text: "Switch Sides", | 
					
						
							|  |  |  |               textColor: Colors.white), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-11-10 10:27:13 +08:00
										 |  |  |         Offstage( | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |           offstage: !showElevation, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |           child: buildButton( | 
					
						
							|  |  |  |             context, | 
					
						
							|  |  |  |             color: MyTheme.accent, | 
					
						
							|  |  |  |             onClick: () { | 
					
						
							|  |  |  |               handleElevate(context); | 
					
						
							|  |  |  |               windowManager.minimize(); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             icon: Icon( | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |               Icons.security_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |               color: Colors.white, | 
					
						
							|  |  |  |               size: 14, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             text: 'Elevate', | 
					
						
							|  |  |  |             textColor: Colors.white, | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-11-10 10:27:13 +08:00
										 |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |         Row( | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Expanded( | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |               child: buildButton(context, | 
					
						
							|  |  |  |                   color: Colors.redAccent, | 
					
						
							|  |  |  |                   onClick: handleDisconnect, | 
					
						
							|  |  |  |                   text: 'Disconnect', | 
					
						
							|  |  |  |                   icon: Icon( | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                     Icons.link_off_rounded, | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |                     color: Colors.white, | 
					
						
							|  |  |  |                     size: 14, | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                   textColor: Colors.white), | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |           ], | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |     ).marginOnly(bottom: buttonBottomMargin); | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-08 20:15:02 +08:00
										 |  |  |   buildDisconnected(BuildContext context) { | 
					
						
							|  |  |  |     return Row( | 
					
						
							|  |  |  |       mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |       children: [ | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |         Expanded( | 
					
						
							|  |  |  |             child: buildButton(context, | 
					
						
							|  |  |  |                 color: MyTheme.accent, | 
					
						
							|  |  |  |                 onClick: handleClose, | 
					
						
							|  |  |  |                 text: 'Close', | 
					
						
							|  |  |  |                 textColor: Colors.white)), | 
					
						
							| 
									
										
										
										
											2022-10-08 20:15:02 +08:00
										 |  |  |       ], | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |     ).marginOnly(bottom: buttonBottomMargin); | 
					
						
							| 
									
										
										
										
											2022-10-08 20:15:02 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |   buildUnAuthorized(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-11-10 10:27:13 +08:00
										 |  |  |     final bool canElevate = bind.cmCanElevate(); | 
					
						
							|  |  |  |     final model = Provider.of<ServerModel>(context); | 
					
						
							| 
									
										
										
										
											2022-12-04 18:47:02 +08:00
										 |  |  |     final showElevation = canElevate && | 
					
						
							|  |  |  |         model.showElevation && | 
					
						
							|  |  |  |         client.type_() == ClientType.remote; | 
					
						
							| 
									
										
										
										
											2022-11-20 15:53:08 +08:00
										 |  |  |     final showAccept = model.approveMode != 'password'; | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |     return Column( | 
					
						
							|  |  |  |       mainAxisAlignment: MainAxisAlignment.end, | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |       children: [ | 
					
						
							| 
									
										
										
										
											2022-11-10 10:27:13 +08:00
										 |  |  |         Offstage( | 
					
						
							| 
									
										
										
										
											2022-11-20 15:53:08 +08:00
										 |  |  |           offstage: !showElevation || !showAccept, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |           child: buildButton(context, color: Colors.green[700], onClick: () { | 
					
						
							|  |  |  |             handleAccept(context); | 
					
						
							|  |  |  |             handleElevate(context); | 
					
						
							|  |  |  |             windowManager.minimize(); | 
					
						
							|  |  |  |           }, | 
					
						
							| 
									
										
										
										
											2023-06-14 21:30:05 +08:00
										 |  |  |               text: 'Accept and Elevate', | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |               icon: Icon( | 
					
						
							| 
									
										
										
										
											2023-05-24 14:18:42 +08:00
										 |  |  |                 Icons.security_rounded, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |                 color: Colors.white, | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                 size: 14, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2023-06-14 21:30:05 +08:00
										 |  |  |               textColor: Colors.white, | 
					
						
							|  |  |  |               tooltip: 'accept_and_elevate_btn_tooltip'), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |         Row( | 
					
						
							|  |  |  |           mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |           children: [ | 
					
						
							| 
									
										
										
										
											2022-11-20 15:53:08 +08:00
										 |  |  |             if (showAccept) | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: Column( | 
					
						
							|  |  |  |                   children: [ | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |                     buildButton( | 
					
						
							|  |  |  |                       context, | 
					
						
							|  |  |  |                       color: MyTheme.accent, | 
					
						
							|  |  |  |                       onClick: () { | 
					
						
							|  |  |  |                         handleAccept(context); | 
					
						
							|  |  |  |                         windowManager.minimize(); | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                       text: 'Accept', | 
					
						
							|  |  |  |                       textColor: Colors.white, | 
					
						
							|  |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2022-11-20 15:53:08 +08:00
										 |  |  |                   ], | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |             Expanded( | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |               child: buildButton( | 
					
						
							|  |  |  |                 context, | 
					
						
							|  |  |  |                 color: Colors.transparent, | 
					
						
							|  |  |  |                 border: Border.all(color: Colors.grey), | 
					
						
							|  |  |  |                 onClick: handleDisconnect, | 
					
						
							|  |  |  |                 text: 'Cancel', | 
					
						
							|  |  |  |                 textColor: null, | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |           ], | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |       ], | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |     ).marginOnly(bottom: buttonBottomMargin); | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-14 21:30:05 +08:00
										 |  |  |   Widget buildButton(BuildContext context, | 
					
						
							|  |  |  |       {required Color? color, | 
					
						
							|  |  |  |       required Function() onClick, | 
					
						
							|  |  |  |       Icon? icon, | 
					
						
							|  |  |  |       BoxBorder? border, | 
					
						
							|  |  |  |       required String text, | 
					
						
							|  |  |  |       required Color? textColor, | 
					
						
							|  |  |  |       String? tooltip}) { | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |     Widget textWidget; | 
					
						
							|  |  |  |     if (icon != null) { | 
					
						
							|  |  |  |       textWidget = Text( | 
					
						
							|  |  |  |         translate(text), | 
					
						
							|  |  |  |         style: TextStyle(color: textColor), | 
					
						
							|  |  |  |         textAlign: TextAlign.center, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       textWidget = Expanded( | 
					
						
							|  |  |  |         child: Text( | 
					
						
							|  |  |  |           translate(text), | 
					
						
							|  |  |  |           style: TextStyle(color: textColor), | 
					
						
							|  |  |  |           textAlign: TextAlign.center, | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-03 22:19:39 +08:00
										 |  |  |     final borderRadius = BorderRadius.circular(10.0); | 
					
						
							| 
									
										
										
										
											2023-06-14 21:30:05 +08:00
										 |  |  |     final btn = Container( | 
					
						
							| 
									
										
										
										
											2023-05-20 15:12:52 +02:00
										 |  |  |       height: 28, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |       decoration: BoxDecoration( | 
					
						
							| 
									
										
										
										
											2023-06-03 22:19:39 +08:00
										 |  |  |           color: color, borderRadius: borderRadius, border: border), | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |       child: InkWell( | 
					
						
							| 
									
										
										
										
											2023-06-03 22:19:39 +08:00
										 |  |  |         borderRadius: borderRadius, | 
					
						
							| 
									
										
										
										
											2023-05-19 23:21:13 +02:00
										 |  |  |         onTap: () => checkClickTime(client.id, onClick), | 
					
						
							|  |  |  |         child: Row( | 
					
						
							|  |  |  |           mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Offstage(offstage: icon == null, child: icon).marginOnly(right: 5), | 
					
						
							|  |  |  |             textWidget, | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2023-06-14 21:30:05 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |     return (tooltip != null | 
					
						
							|  |  |  |             ? Tooltip( | 
					
						
							|  |  |  |                 message: translate(tooltip), | 
					
						
							|  |  |  |                 child: btn, | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             : btn) | 
					
						
							|  |  |  |         .marginAll(4); | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |   void handleDisconnect() { | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |     bind.cmCloseConnection(connId: client.id); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |   void handleAccept(BuildContext context) { | 
					
						
							|  |  |  |     final model = Provider.of<ServerModel>(context, listen: false); | 
					
						
							|  |  |  |     model.sendLoginResponse(client, true); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-10-08 20:15:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 10:27:13 +08:00
										 |  |  |   void handleElevate(BuildContext context) { | 
					
						
							|  |  |  |     final model = Provider.of<ServerModel>(context, listen: false); | 
					
						
							|  |  |  |     model.setShowElevation(false); | 
					
						
							|  |  |  |     bind.cmElevatePortable(connId: client.id); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 17:06:27 +08:00
										 |  |  |   void handleClose() async { | 
					
						
							| 
									
										
										
										
											2022-10-08 20:15:02 +08:00
										 |  |  |     await bind.cmRemoveDisconnectedConnection(connId: client.id); | 
					
						
							|  |  |  |     if (await bind.cmGetClientsLength() == 0) { | 
					
						
							|  |  |  |       windowManager.close(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-01-17 13:28:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void handleSwitchBack(BuildContext context) { | 
					
						
							|  |  |  |     bind.cmSwitchBack(connId: client.id); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-07 16:11:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void handleVoiceCall(bool accept) { | 
					
						
							|  |  |  |     bind.cmHandleIncomingVoiceCall(id: client.id, accept: accept); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void closeVoiceCall() { | 
					
						
							|  |  |  |     bind.cmCloseVoiceCall(id: client.id); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-30 16:50:25 +08:00
										 |  |  | void checkClickTime(int id, Function() callback) async { | 
					
						
							|  |  |  |   var clickCallbackTime = DateTime.now().millisecondsSinceEpoch; | 
					
						
							|  |  |  |   await bind.cmCheckClickTime(connId: id); | 
					
						
							|  |  |  |   Timer(const Duration(milliseconds: 120), () async { | 
					
						
							|  |  |  |     var d = clickCallbackTime - await bind.cmGetClickTime(); | 
					
						
							|  |  |  |     if (d > 120) callback(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } |