| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  | import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/mobile/pages/chat_page.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/models/chat_model.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-08-11 18:59:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import '../../common.dart'; | 
					
						
							|  |  |  | import '../../models/platform_model.dart'; | 
					
						
							|  |  |  | import '../../models/server_model.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  | class DesktopServerPage extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   State<StatefulWidget> createState() => _DesktopServerPageState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-08-11 18:59:26 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |   void initState() { | 
					
						
							|  |  |  |     gFFI.ffiModel.updateEventListener(""); | 
					
						
							| 
									
										
										
										
											2022-08-23 21:28:44 +08:00
										 |  |  |     windowManager.addListener(this); | 
					
						
							| 
									
										
										
										
											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() { | 
					
						
							|  |  |  |     gFFI.serverModel.closeAll(); | 
					
						
							|  |  |  |     gFFI.close(); | 
					
						
							|  |  |  |     super.onWindowClose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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( | 
					
						
							|  |  |  |         providers: [ | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: gFFI.serverModel), | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: gFFI.chatModel), | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |         child: Consumer<ServerModel>( | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |             builder: (context, serverModel, child) => Container( | 
					
						
							|  |  |  |                   decoration: BoxDecoration( | 
					
						
							|  |  |  |                       border: | 
					
						
							|  |  |  |                           Border.all(color: MyTheme.color(context).border!)), | 
					
						
							|  |  |  |                   child: Scaffold( | 
					
						
							|  |  |  |                     backgroundColor: MyTheme.color(context).bg, | 
					
						
							|  |  |  |                     body: Center( | 
					
						
							|  |  |  |                       child: Column( | 
					
						
							|  |  |  |                         mainAxisAlignment: MainAxisAlignment.start, | 
					
						
							|  |  |  |                         children: [ | 
					
						
							|  |  |  |                           Expanded(child: ConnectionManager()), | 
					
						
							|  |  |  |                           SizedBox.fromSize(size: Size(0, 15.0)), | 
					
						
							|  |  |  |                         ], | 
					
						
							|  |  |  |                       ), | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08: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(); | 
					
						
							| 
									
										
										
										
											2022-08-24 21:52:21 +08:00
										 |  |  |     gFFI.serverModel.tabController.onSelected = (index) => | 
					
						
							|  |  |  |         gFFI.chatModel.changeCurrentID(gFFI.serverModel.clients[index].id); | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  |     // test
 | 
					
						
							|  |  |  |     // gFFI.serverModel.clients.forEach((client) {
 | 
					
						
							|  |  |  |     //   DesktopTabBar.onAdd(
 | 
					
						
							|  |  |  |     //       gFFI.serverModel.tabs,
 | 
					
						
							|  |  |  |     //       TabInfo(
 | 
					
						
							|  |  |  |     //           key: client.id.toString(), label: client.name, closable: false));
 | 
					
						
							|  |  |  |     // });
 | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     final serverModel = Provider.of<ServerModel>(context); | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |     return serverModel.clients.isEmpty | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |         ? Column( | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               buildTitleBar(Offstage()), | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: Center( | 
					
						
							|  |  |  |                   child: Text(translate("Waiting")), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ], | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |           ) | 
					
						
							| 
									
										
										
										
											2022-08-24 21:52:21 +08:00
										 |  |  |         : DesktopTab( | 
					
						
							|  |  |  |             theme: isDarkTheme() ? TarBarTheme.dark() : TarBarTheme.light(), | 
					
						
							|  |  |  |             showTitle: false, | 
					
						
							|  |  |  |             showMaximize: false, | 
					
						
							|  |  |  |             showMinimize: false, | 
					
						
							|  |  |  |             controller: serverModel.tabController, | 
					
						
							| 
									
										
										
										
											2022-08-30 16:50:25 +08:00
										 |  |  |             tabType: DesktopTabType.cm, | 
					
						
							| 
									
										
										
										
											2022-08-24 21:52:21 +08:00
										 |  |  |             pageViewBuilder: (pageView) => Row(children: [ | 
					
						
							|  |  |  |                   Expanded(child: pageView), | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  |                   Consumer<ChatModel>( | 
					
						
							|  |  |  |                       builder: (_, model, child) => model.isShowChatPage | 
					
						
							|  |  |  |                           ? Expanded(child: Scaffold(body: ChatPage())) | 
					
						
							|  |  |  |                           : Offstage()) | 
					
						
							| 
									
										
										
										
											2022-08-24 21:52:21 +08:00
										 |  |  |                 ])); | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget buildTitleBar(Widget middle) { | 
					
						
							|  |  |  |     return GestureDetector( | 
					
						
							|  |  |  |       onPanDown: (d) { | 
					
						
							|  |  |  |         windowManager.startDragging(); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       child: Row( | 
					
						
							|  |  |  |         crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |         children: [ | 
					
						
							|  |  |  |           _AppIcon(), | 
					
						
							|  |  |  |           Expanded(child: middle), | 
					
						
							|  |  |  |           const SizedBox( | 
					
						
							|  |  |  |             width: 4.0, | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-08-18 11:07:53 +08:00
										 |  |  |           _CloseButton() | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  |   Widget buildTab(Client client) { | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |     return Tab( | 
					
						
							|  |  |  |       child: Row( | 
					
						
							|  |  |  |         children: [ | 
					
						
							|  |  |  |           SizedBox( | 
					
						
							|  |  |  |               width: 80, | 
					
						
							|  |  |  |               child: Text( | 
					
						
							| 
									
										
										
										
											2022-08-22 20:18:31 +08:00
										 |  |  |                 "${client.name}", | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |                 maxLines: 1, | 
					
						
							|  |  |  |                 overflow: TextOverflow.ellipsis, | 
					
						
							|  |  |  |                 textAlign: TextAlign.center, | 
					
						
							|  |  |  |               )), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 21:52:21 +08:00
										 |  |  | Widget buildConnectionCard(Client client) { | 
					
						
							|  |  |  |   return Column( | 
					
						
							|  |  |  |     mainAxisAlignment: MainAxisAlignment.start, | 
					
						
							|  |  |  |     crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |     key: ValueKey(client.id), | 
					
						
							|  |  |  |     children: [ | 
					
						
							|  |  |  |       _CmHeader(client: client), | 
					
						
							|  |  |  |       client.isFileTransfer ? Offstage() : _PrivilegeBoard(client: client), | 
					
						
							|  |  |  |       Expanded( | 
					
						
							|  |  |  |           child: Align( | 
					
						
							|  |  |  |         alignment: Alignment.bottomCenter, | 
					
						
							|  |  |  |         child: _CmControlPanel(client: client), | 
					
						
							|  |  |  |       )) | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |   ).paddingSymmetric(vertical: 8.0, horizontal: 8.0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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), | 
					
						
							|  |  |  |       child: Image.asset( | 
					
						
							|  |  |  |         'assets/logo.ico', | 
					
						
							|  |  |  |         width: 30, | 
					
						
							|  |  |  |         height: 30, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _CloseButton extends StatelessWidget { | 
					
						
							|  |  |  |   const _CloseButton({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Ink( | 
					
						
							|  |  |  |       child: InkWell( | 
					
						
							|  |  |  |           onTap: () { | 
					
						
							|  |  |  |             windowManager.close(); | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           child: Icon( | 
					
						
							|  |  |  |             Icons.close, | 
					
						
							|  |  |  |             size: 30, | 
					
						
							|  |  |  |           )), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var _time = 0.obs; | 
					
						
							|  |  |  |   Timer? _timer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |     _timer = Timer.periodic(Duration(seconds: 1), (_) { | 
					
						
							|  |  |  |       _time.value = _time.value + 1; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @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); | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |     return Row( | 
					
						
							|  |  |  |       crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         // icon
 | 
					
						
							|  |  |  |         Container( | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |           width: 90, | 
					
						
							|  |  |  |           height: 90, | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |           alignment: Alignment.center, | 
					
						
							|  |  |  |           decoration: BoxDecoration(color: str2color(client.name)), | 
					
						
							|  |  |  |           child: Text( | 
					
						
							|  |  |  |             "${client.name[0]}", | 
					
						
							|  |  |  |             style: TextStyle( | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |                 fontWeight: FontWeight.bold, color: Colors.white, fontSize: 65), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ).marginOnly(left: 4.0, right: 8.0), | 
					
						
							|  |  |  |         Expanded( | 
					
						
							|  |  |  |           child: Column( | 
					
						
							|  |  |  |             mainAxisAlignment: MainAxisAlignment.start, | 
					
						
							|  |  |  |             crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |             children: [ | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |               FittedBox( | 
					
						
							|  |  |  |                   child: Text( | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |                 "${client.name}", | 
					
						
							|  |  |  |                 style: TextStyle( | 
					
						
							|  |  |  |                   color: MyTheme.cmIdColor, | 
					
						
							|  |  |  |                   fontWeight: FontWeight.bold, | 
					
						
							|  |  |  |                   fontSize: 20, | 
					
						
							|  |  |  |                   overflow: TextOverflow.ellipsis, | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 maxLines: 1, | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |               )), | 
					
						
							|  |  |  |               FittedBox( | 
					
						
							|  |  |  |                   child: Text("(${client.peerId})", | 
					
						
							|  |  |  |                       style: | 
					
						
							|  |  |  |                           TextStyle(color: MyTheme.cmIdColor, fontSize: 14))), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |               SizedBox( | 
					
						
							|  |  |  |                 height: 16.0, | 
					
						
							|  |  |  |               ), | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |               FittedBox( | 
					
						
							|  |  |  |                   child: Row( | 
					
						
							| 
									
										
										
										
											2022-08-18 00:34:04 +08:00
										 |  |  |                 children: [ | 
					
						
							|  |  |  |                   Text("${translate("Connected")}").marginOnly(right: 8.0), | 
					
						
							|  |  |  |                   Obx(() => Text( | 
					
						
							|  |  |  |                       "${formatDurationToTime(Duration(seconds: _time.value))}")) | 
					
						
							|  |  |  |                 ], | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |               )) | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |             ], | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         Offstage( | 
					
						
							|  |  |  |           offstage: client.isFileTransfer, | 
					
						
							|  |  |  |           child: IconButton( | 
					
						
							| 
									
										
										
										
											2022-08-30 16:50:25 +08:00
										 |  |  |             onPressed: () => checkClickTime( | 
					
						
							|  |  |  |                 client.id, () => gFFI.chatModel.toggleCMChatPage(client.id)), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |             icon: Icon(Icons.message_outlined), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   Widget buildPermissionIcon(bool enabled, ImageProvider icon, | 
					
						
							|  |  |  |       Function(bool)? onTap, String? tooltip) { | 
					
						
							|  |  |  |     return Tooltip( | 
					
						
							|  |  |  |       message: tooltip ?? "", | 
					
						
							|  |  |  |       child: Ink( | 
					
						
							|  |  |  |         decoration: | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |             BoxDecoration(color: enabled ? MyTheme.accent80 : Colors.grey), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         padding: EdgeInsets.all(4.0), | 
					
						
							|  |  |  |         child: InkWell( | 
					
						
							| 
									
										
										
										
											2022-08-30 16:50:25 +08:00
										 |  |  |           onTap: () => | 
					
						
							|  |  |  |               checkClickTime(widget.client.id, () => onTap?.call(!enabled)), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |           child: Image( | 
					
						
							|  |  |  |             image: icon, | 
					
						
							|  |  |  |             width: 50, | 
					
						
							|  |  |  |             height: 50, | 
					
						
							|  |  |  |             fit: BoxFit.scaleDown, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ).marginSymmetric(horizontal: 4.0), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Container( | 
					
						
							|  |  |  |       margin: EdgeInsets.only(top: 16.0, bottom: 8.0), | 
					
						
							|  |  |  |       child: Column( | 
					
						
							|  |  |  |         crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |         children: [ | 
					
						
							|  |  |  |           Text( | 
					
						
							|  |  |  |             translate("Permissions"), | 
					
						
							|  |  |  |             style: TextStyle(fontSize: 16), | 
					
						
							|  |  |  |           ).marginOnly(left: 4.0), | 
					
						
							|  |  |  |           SizedBox( | 
					
						
							|  |  |  |             height: 8.0, | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |           FittedBox( | 
					
						
							|  |  |  |               child: Row( | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |             children: [ | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |               buildPermissionIcon(client.keyboard, iconKeyboard, (enabled) { | 
					
						
							|  |  |  |                 bind.cmSwitchPermission( | 
					
						
							|  |  |  |                     connId: client.id, name: "keyboard", enabled: enabled); | 
					
						
							|  |  |  |                 setState(() { | 
					
						
							|  |  |  |                   client.keyboard = enabled; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }, null), | 
					
						
							|  |  |  |               buildPermissionIcon(client.clipboard, iconClipboard, (enabled) { | 
					
						
							|  |  |  |                 bind.cmSwitchPermission( | 
					
						
							|  |  |  |                     connId: client.id, name: "clipboard", enabled: enabled); | 
					
						
							|  |  |  |                 setState(() { | 
					
						
							|  |  |  |                   client.clipboard = enabled; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }, null), | 
					
						
							|  |  |  |               buildPermissionIcon(client.audio, iconAudio, (enabled) { | 
					
						
							|  |  |  |                 bind.cmSwitchPermission( | 
					
						
							|  |  |  |                     connId: client.id, name: "audio", enabled: enabled); | 
					
						
							|  |  |  |                 setState(() { | 
					
						
							|  |  |  |                   client.audio = enabled; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }, null), | 
					
						
							|  |  |  |               buildPermissionIcon(client.file, iconFile, (enabled) { | 
					
						
							|  |  |  |                 bind.cmSwitchPermission( | 
					
						
							|  |  |  |                     connId: client.id, name: "file", enabled: enabled); | 
					
						
							|  |  |  |                 setState(() { | 
					
						
							|  |  |  |                   client.file = enabled; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }, null), | 
					
						
							|  |  |  |               buildPermissionIcon(client.restart, iconRestart, (enabled) { | 
					
						
							|  |  |  |                 bind.cmSwitchPermission( | 
					
						
							|  |  |  |                     connId: client.id, name: "restart", enabled: enabled); | 
					
						
							|  |  |  |                 setState(() { | 
					
						
							|  |  |  |                   client.restart = enabled; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }, null), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |             ], | 
					
						
							| 
									
										
										
										
											2022-08-19 19:17:45 +08:00
										 |  |  |           )), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +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-08-24 21:52:21 +08:00
										 |  |  |     return Consumer<ServerModel>(builder: (_, model, child) { | 
					
						
							|  |  |  |       return client.authorized | 
					
						
							|  |  |  |           ? buildAuthorized(context) | 
					
						
							|  |  |  |           : buildUnAuthorized(context); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |   buildAuthorized(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |     return Row( | 
					
						
							|  |  |  |       mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         Ink( | 
					
						
							|  |  |  |           width: 200, | 
					
						
							|  |  |  |           height: 40, | 
					
						
							|  |  |  |           decoration: BoxDecoration( | 
					
						
							|  |  |  |               color: Colors.redAccent, borderRadius: BorderRadius.circular(10)), | 
					
						
							|  |  |  |           child: InkWell( | 
					
						
							| 
									
										
										
										
											2022-08-30 16:50:25 +08:00
										 |  |  |               onTap: () => | 
					
						
							|  |  |  |                   checkClickTime(client.id, () => handleDisconnect(context)), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |               child: Row( | 
					
						
							|  |  |  |                 mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Text( | 
					
						
							|  |  |  |                     translate("Disconnect"), | 
					
						
							|  |  |  |                     style: TextStyle(color: Colors.white), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               )), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |   buildUnAuthorized(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |     return Row( | 
					
						
							|  |  |  |       mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         Ink( | 
					
						
							|  |  |  |           width: 100, | 
					
						
							|  |  |  |           height: 40, | 
					
						
							|  |  |  |           decoration: BoxDecoration( | 
					
						
							|  |  |  |               color: MyTheme.accent, borderRadius: BorderRadius.circular(10)), | 
					
						
							|  |  |  |           child: InkWell( | 
					
						
							| 
									
										
										
										
											2022-08-30 16:50:25 +08:00
										 |  |  |               onTap: () => | 
					
						
							|  |  |  |                   checkClickTime(client.id, () => handleAccept(context)), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |               child: Row( | 
					
						
							|  |  |  |                 mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Text( | 
					
						
							|  |  |  |                     translate("Accept"), | 
					
						
							|  |  |  |                     style: TextStyle(color: Colors.white), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               )), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         SizedBox( | 
					
						
							|  |  |  |           width: 30, | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         Ink( | 
					
						
							|  |  |  |           width: 100, | 
					
						
							|  |  |  |           height: 40, | 
					
						
							|  |  |  |           decoration: BoxDecoration( | 
					
						
							|  |  |  |               color: Colors.transparent, | 
					
						
							|  |  |  |               borderRadius: BorderRadius.circular(10), | 
					
						
							|  |  |  |               border: Border.all(color: Colors.grey)), | 
					
						
							|  |  |  |           child: InkWell( | 
					
						
							| 
									
										
										
										
											2022-08-30 16:50:25 +08:00
										 |  |  |               onTap: () => | 
					
						
							|  |  |  |                   checkClickTime(client.id, () => handleDisconnect(context)), | 
					
						
							| 
									
										
										
										
											2022-08-17 21:28:36 +08:00
										 |  |  |               child: Row( | 
					
						
							|  |  |  |                 mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Text( | 
					
						
							|  |  |  |                     translate("Cancel"), | 
					
						
							|  |  |  |                     style: TextStyle(), | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               )), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 21:46:56 +08:00
										 |  |  |   void handleDisconnect(BuildContext context) { | 
					
						
							|  |  |  |     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-08-17 21:28:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  | class PaddingCard extends StatelessWidget { | 
					
						
							|  |  |  |   PaddingCard({required this.child, this.title, this.titleIcon}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   final String? title; | 
					
						
							|  |  |  |   final IconData? titleIcon; | 
					
						
							|  |  |  |   final Widget child; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     final children = [child]; | 
					
						
							|  |  |  |     if (title != null) { | 
					
						
							|  |  |  |       children.insert( | 
					
						
							|  |  |  |           0, | 
					
						
							|  |  |  |           Padding( | 
					
						
							|  |  |  |               padding: EdgeInsets.symmetric(vertical: 5.0), | 
					
						
							|  |  |  |               child: Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   titleIcon != null | 
					
						
							|  |  |  |                       ? Padding( | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |                           padding: EdgeInsets.only(right: 10), | 
					
						
							|  |  |  |                           child: Icon(titleIcon, | 
					
						
							|  |  |  |                               color: MyTheme.accent80, size: 30)) | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +08:00
										 |  |  |                       : SizedBox.shrink(), | 
					
						
							|  |  |  |                   Text( | 
					
						
							|  |  |  |                     title!, | 
					
						
							|  |  |  |                     style: TextStyle( | 
					
						
							|  |  |  |                       fontFamily: 'WorkSans', | 
					
						
							|  |  |  |                       fontWeight: FontWeight.bold, | 
					
						
							|  |  |  |                       fontSize: 20, | 
					
						
							|  |  |  |                       color: MyTheme.accent80, | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                   ) | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return Container( | 
					
						
							|  |  |  |         width: double.maxFinite, | 
					
						
							|  |  |  |         child: Card( | 
					
						
							|  |  |  |           margin: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 0), | 
					
						
							|  |  |  |           child: Padding( | 
					
						
							|  |  |  |             padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 30.0), | 
					
						
							|  |  |  |             child: Column( | 
					
						
							|  |  |  |               crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |               children: children, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         )); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Widget clientInfo(Client client) { | 
					
						
							|  |  |  |   return Padding( | 
					
						
							|  |  |  |       padding: EdgeInsets.symmetric(vertical: 8), | 
					
						
							|  |  |  |       child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ | 
					
						
							|  |  |  |         Row( | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Expanded( | 
					
						
							|  |  |  |                 flex: -1, | 
					
						
							|  |  |  |                 child: Padding( | 
					
						
							|  |  |  |                     padding: EdgeInsets.only(right: 12), | 
					
						
							|  |  |  |                     child: CircleAvatar( | 
					
						
							|  |  |  |                         child: Text(client.name[0]), | 
					
						
							|  |  |  |                         backgroundColor: MyTheme.border))), | 
					
						
							|  |  |  |             Expanded( | 
					
						
							|  |  |  |                 child: Column( | 
					
						
							|  |  |  |                     crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |                     mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |                     children: [ | 
					
						
							| 
									
										
										
										
											2022-08-18 19:49:41 +08:00
										 |  |  |                   Text(client.name, | 
					
						
							|  |  |  |                       style: TextStyle(color: MyTheme.idColor, fontSize: 18)), | 
					
						
							|  |  |  |                   SizedBox(width: 8), | 
					
						
							|  |  |  |                   Text(client.peerId, | 
					
						
							|  |  |  |                       style: TextStyle(color: MyTheme.idColor, fontSize: 10)) | 
					
						
							|  |  |  |                 ])) | 
					
						
							| 
									
										
										
										
											2022-08-11 18:59:26 +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(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } |