| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  | import 'dart:ui' as ui; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import 'package:bot_toast/bot_toast.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  | import 'package:flutter_hbb/common/widgets/address_book.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | import 'package:flutter_hbb/common/widgets/my_group.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-22 15:35:46 +08:00
										 |  |  | import 'package:flutter_hbb/common/widgets/peers_view.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/common/widgets/peer_card.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import 'package:flutter_hbb/consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  | import 'package:flutter_hbb/desktop/widgets/popup_menu.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart' | 
					
						
							|  |  |  |     as mod_menu; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import '../../common.dart'; | 
					
						
							|  |  |  | import '../../models/platform_model.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | const int groupTabIndex = 4; | 
					
						
							| 
									
										
										
										
											2022-12-17 12:28:11 +08:00
										 |  |  | const String defaultGroupTabname = 'Group'; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class StatePeerTab { | 
					
						
							|  |  |  |   final RxInt currentTab = 0.obs; | 
					
						
							|  |  |  |   static const List<int> tabIndexs = [0, 1, 2, 3, 4]; | 
					
						
							|  |  |  |   List<int> tabOrder = List.empty(growable: true); | 
					
						
							|  |  |  |   final RxList<int> visibleTabOrder = RxList.empty(growable: true); | 
					
						
							|  |  |  |   int tabHiddenFlag = 0; | 
					
						
							|  |  |  |   final RxList<String> tabNames = [ | 
					
						
							| 
									
										
										
										
											2022-12-17 12:28:11 +08:00
										 |  |  |     'Recent Sessions', | 
					
						
							|  |  |  |     'Favorites', | 
					
						
							|  |  |  |     'Discovered', | 
					
						
							|  |  |  |     'Address Book', | 
					
						
							|  |  |  |     defaultGroupTabname, | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   ].obs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   StatePeerTab._() { | 
					
						
							|  |  |  |     tabHiddenFlag = (int.tryParse( | 
					
						
							|  |  |  |             bind.getLocalFlutterConfig(k: 'hidden-peer-card'), | 
					
						
							|  |  |  |             radix: 2) ?? | 
					
						
							|  |  |  |         0); | 
					
						
							|  |  |  |     currentTab.value = | 
					
						
							|  |  |  |         int.tryParse(bind.getLocalFlutterConfig(k: 'peer-tab-index')) ?? 0; | 
					
						
							|  |  |  |     if (!tabIndexs.contains(currentTab.value)) { | 
					
						
							|  |  |  |       currentTab.value = tabIndexs[0]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     tabOrder = tabIndexs.toList(); | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       final conf = bind.getLocalFlutterConfig(k: 'peer-tab-order'); | 
					
						
							|  |  |  |       if (conf.isNotEmpty) { | 
					
						
							|  |  |  |         final json = jsonDecode(conf); | 
					
						
							|  |  |  |         if (json is List) { | 
					
						
							|  |  |  |           final List<int> list = | 
					
						
							|  |  |  |               json.map((e) => int.tryParse(e.toString()) ?? -1).toList(); | 
					
						
							|  |  |  |           if (list.length == tabOrder.length && | 
					
						
							|  |  |  |               tabOrder.every((e) => list.contains(e))) { | 
					
						
							|  |  |  |             tabOrder = list; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrintStack(label: '$e'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     visibleTabOrder.value = tabOrder.where((e) => !isTabHidden(e)).toList(); | 
					
						
							|  |  |  |     visibleTabOrder.remove(groupTabIndex); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   static final StatePeerTab instance = StatePeerTab._(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   check() { | 
					
						
							|  |  |  |     List<int> oldOrder = visibleTabOrder; | 
					
						
							|  |  |  |     if (filterGroupCard()) { | 
					
						
							|  |  |  |       visibleTabOrder.remove(groupTabIndex); | 
					
						
							|  |  |  |       if (currentTab.value == groupTabIndex) { | 
					
						
							|  |  |  |         currentTab.value = | 
					
						
							|  |  |  |             visibleTabOrder.firstWhereOrNull((e) => e != groupTabIndex) ?? 0; | 
					
						
							|  |  |  |         bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |             k: 'peer-tab-index', v: currentTab.value.toString()); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       if (gFFI.userModel.isAdmin.isFalse && | 
					
						
							|  |  |  |           gFFI.userModel.groupName.isNotEmpty) { | 
					
						
							|  |  |  |         tabNames[groupTabIndex] = gFFI.userModel.groupName.value; | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-12-17 12:28:11 +08:00
										 |  |  |         tabNames[groupTabIndex] = defaultGroupTabname; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (isTabHidden(groupTabIndex)) { | 
					
						
							|  |  |  |         visibleTabOrder.remove(groupTabIndex); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (!visibleTabOrder.contains(groupTabIndex)) { | 
					
						
							|  |  |  |           addTabInOrder(visibleTabOrder, groupTabIndex); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (visibleTabOrder.contains(groupTabIndex) && | 
					
						
							|  |  |  |           int.tryParse(bind.getLocalFlutterConfig(k: 'peer-tab-index')) == | 
					
						
							|  |  |  |               groupTabIndex) { | 
					
						
							|  |  |  |         currentTab.value = groupTabIndex; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (oldOrder != visibleTabOrder) { | 
					
						
							|  |  |  |       saveTabOrder(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool isTabHidden(int tabindex) { | 
					
						
							|  |  |  |     return tabHiddenFlag & (1 << tabindex) != 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool filterGroupCard() { | 
					
						
							|  |  |  |     if (gFFI.groupModel.users.isEmpty || | 
					
						
							|  |  |  |         (gFFI.userModel.isAdmin.isFalse && gFFI.userModel.groupName.isEmpty)) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addTabInOrder(List<int> list, int tabIndex) { | 
					
						
							|  |  |  |     if (!tabOrder.contains(tabIndex) || list.contains(tabIndex)) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     bool sameOrder = true; | 
					
						
							|  |  |  |     int lastIndex = -1; | 
					
						
							|  |  |  |     for (int i = 0; i < list.length; i++) { | 
					
						
							|  |  |  |       var index = tabOrder.lastIndexOf(list[i]); | 
					
						
							|  |  |  |       if (index > lastIndex) { | 
					
						
							|  |  |  |         lastIndex = index; | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         sameOrder = false; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (sameOrder) { | 
					
						
							|  |  |  |       var indexInTabOrder = tabOrder.indexOf(tabIndex); | 
					
						
							|  |  |  |       var left = List.empty(growable: true); | 
					
						
							|  |  |  |       for (int i = 0; i < indexInTabOrder; i++) { | 
					
						
							|  |  |  |         left.add(tabOrder[i]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       int insertIndex = list.lastIndexWhere((e) => left.contains(e)); | 
					
						
							|  |  |  |       if (insertIndex < 0) { | 
					
						
							|  |  |  |         insertIndex = 0; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         insertIndex += 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       list.insert(insertIndex, tabIndex); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       list.add(tabIndex); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   saveTabOrder() { | 
					
						
							|  |  |  |     var list = statePeerTab.visibleTabOrder.toList(); | 
					
						
							|  |  |  |     var left = tabOrder | 
					
						
							|  |  |  |         .where((e) => !statePeerTab.visibleTabOrder.contains(e)) | 
					
						
							|  |  |  |         .toList(); | 
					
						
							|  |  |  |     for (var t in left) { | 
					
						
							|  |  |  |       addTabInOrder(list, t); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     statePeerTab.tabOrder = list; | 
					
						
							|  |  |  |     bind.setLocalFlutterConfig(k: 'peer-tab-order', v: jsonEncode(list)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | final statePeerTab = StatePeerTab.instance; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | class PeerTabPage extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |   const PeerTabPage({Key? key}) : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   State<PeerTabPage> createState() => _PeerTabPageState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  | class _TabEntry { | 
					
						
							|  |  |  |   final Widget widget; | 
					
						
							|  |  |  |   final Function() load; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   _TabEntry(this.widget, this.load); | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-05 09:33:01 +08:00
										 |  |  | EdgeInsets? _menuPadding() { | 
					
						
							|  |  |  |   return isDesktop ? kDesktopMenuPadding : null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | class _PeerTabPageState extends State<PeerTabPage> | 
					
						
							|  |  |  |     with SingleTickerProviderStateMixin { | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |   final List<_TabEntry> entries = [ | 
					
						
							|  |  |  |     _TabEntry( | 
					
						
							|  |  |  |         RecentPeersView( | 
					
						
							| 
									
										
										
										
											2022-12-05 09:33:01 +08:00
										 |  |  |           menuPadding: _menuPadding(), | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |         bind.mainLoadRecentPeers), | 
					
						
							|  |  |  |     _TabEntry( | 
					
						
							|  |  |  |         FavoritePeersView( | 
					
						
							| 
									
										
										
										
											2022-12-05 09:33:01 +08:00
										 |  |  |           menuPadding: _menuPadding(), | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |         bind.mainLoadFavPeers), | 
					
						
							|  |  |  |     _TabEntry( | 
					
						
							|  |  |  |         DiscoveredPeersView( | 
					
						
							| 
									
										
										
										
											2022-12-05 09:33:01 +08:00
										 |  |  |           menuPadding: _menuPadding(), | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |         bind.mainDiscover), | 
					
						
							|  |  |  |     _TabEntry( | 
					
						
							| 
									
										
										
										
											2022-12-05 09:33:01 +08:00
										 |  |  |         AddressBook( | 
					
						
							|  |  |  |           menuPadding: _menuPadding(), | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |         () => {}), | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     _TabEntry( | 
					
						
							|  |  |  |         MyGroup( | 
					
						
							|  |  |  |           menuPadding: _menuPadding(), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         () => {}), | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |   ]; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |     adjustTab(); | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     final uiType = bind.getLocalFlutterConfig(k: 'peer-card-ui-type'); | 
					
						
							| 
									
										
										
										
											2022-11-18 10:19:55 +08:00
										 |  |  |     if (uiType != '') { | 
					
						
							|  |  |  |       peerCardUiType.value = int.parse(uiType) == PeerUiType.list.index | 
					
						
							|  |  |  |           ? PeerUiType.list | 
					
						
							|  |  |  |           : PeerUiType.grid; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |     super.initState(); | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   Future<void> handleTabSelection(int tabIndex) async { | 
					
						
							|  |  |  |     if (tabIndex < entries.length) { | 
					
						
							|  |  |  |       statePeerTab.currentTab.value = tabIndex; | 
					
						
							|  |  |  |       entries[tabIndex].load(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Column( | 
					
						
							|  |  |  |       textBaseline: TextBaseline.ideographic, | 
					
						
							|  |  |  |       crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         SizedBox( | 
					
						
							|  |  |  |           height: 28, | 
					
						
							|  |  |  |           child: Container( | 
					
						
							| 
									
										
										
										
											2022-09-21 17:16:09 +08:00
										 |  |  |               padding: isDesktop ? null : EdgeInsets.symmetric(horizontal: 2), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |               constraints: isDesktop ? null : kMobilePageConstraints, | 
					
						
							|  |  |  |               child: Row( | 
					
						
							|  |  |  |                 crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |                 children: [ | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |                   Expanded( | 
					
						
							|  |  |  |                       child: visibleContextMenuListener( | 
					
						
							|  |  |  |                           _createSwitchBar(context))), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                   const PeerSearchBar(), | 
					
						
							|  |  |  |                   Offstage( | 
					
						
							|  |  |  |                       offstage: !isDesktop, | 
					
						
							|  |  |  |                       child: _createPeerViewTypeSwitch(context) | 
					
						
							|  |  |  |                           .marginOnly(left: 13)), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               )), | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-09-28 11:20:57 +08:00
										 |  |  |         _createPeersView(), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 11:20:57 +08:00
										 |  |  |   Widget _createSwitchBar(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |     final textColor = Theme.of(context).textTheme.titleLarge?.color; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     statePeerTab.visibleTabOrder | 
					
						
							|  |  |  |         .removeWhere((e) => !StatePeerTab.tabIndexs.contains(e)); | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |     return Obx(() { | 
					
						
							|  |  |  |       int indexCounter = -1; | 
					
						
							|  |  |  |       return ReorderableListView( | 
					
						
							|  |  |  |           buildDefaultDragHandles: false, | 
					
						
							|  |  |  |           onReorder: (oldIndex, newIndex) { | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |             var list = statePeerTab.visibleTabOrder.toList(); | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |             if (oldIndex < newIndex) { | 
					
						
							|  |  |  |               newIndex -= 1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |             final int item = list.removeAt(oldIndex); | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |             list.insert(newIndex, item); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |             statePeerTab.visibleTabOrder.value = list; | 
					
						
							|  |  |  |             statePeerTab.saveTabOrder(); | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |           }, | 
					
						
							|  |  |  |           scrollDirection: Axis.horizontal, | 
					
						
							|  |  |  |           shrinkWrap: true, | 
					
						
							|  |  |  |           scrollController: ScrollController(), | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |           children: statePeerTab.visibleTabOrder.map((t) { | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |             indexCounter++; | 
					
						
							|  |  |  |             return ReorderableDragStartListener( | 
					
						
							|  |  |  |               key: ValueKey(t), | 
					
						
							|  |  |  |               index: indexCounter, | 
					
						
							|  |  |  |               child: InkWell( | 
					
						
							|  |  |  |                 child: Container( | 
					
						
							|  |  |  |                     padding: const EdgeInsets.symmetric(horizontal: 8), | 
					
						
							|  |  |  |                     decoration: BoxDecoration( | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |                       color: statePeerTab.currentTab.value == t | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |                           ? Theme.of(context).backgroundColor | 
					
						
							|  |  |  |                           : null, | 
					
						
							|  |  |  |                       borderRadius: BorderRadius.circular(isDesktop ? 2 : 6), | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                     child: Align( | 
					
						
							|  |  |  |                       alignment: Alignment.center, | 
					
						
							|  |  |  |                       child: Text( | 
					
						
							| 
									
										
										
										
											2022-12-17 12:28:11 +08:00
										 |  |  |                         translatedTabname(t), | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |                         textAlign: TextAlign.center, | 
					
						
							|  |  |  |                         style: TextStyle( | 
					
						
							|  |  |  |                             height: 1, | 
					
						
							|  |  |  |                             fontSize: 14, | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |                             color: statePeerTab.currentTab.value == t | 
					
						
							|  |  |  |                                 ? textColor | 
					
						
							|  |  |  |                                 : textColor | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |                               ?..withOpacity(0.5)), | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |                       ), | 
					
						
							|  |  |  |                     )), | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |                 onTap: () async { | 
					
						
							|  |  |  |                   await handleTabSelection(t); | 
					
						
							|  |  |  |                   await bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |                       k: 'peer-tab-index', v: t.toString()); | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2022-12-04 17:44:33 +08:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           }).toList()); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-17 12:28:11 +08:00
										 |  |  |   translatedTabname(int index) { | 
					
						
							|  |  |  |     if (index < statePeerTab.tabNames.length) { | 
					
						
							|  |  |  |       final name = statePeerTab.tabNames[index]; | 
					
						
							|  |  |  |       if (index == groupTabIndex) { | 
					
						
							|  |  |  |         if (name == defaultGroupTabname) { | 
					
						
							|  |  |  |           return translate(name); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           return name; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         return translate(name); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(false); | 
					
						
							|  |  |  |     return index.toString(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 11:20:57 +08:00
										 |  |  |   Widget _createPeersView() { | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     final verticalMargin = isDesktop ? 12.0 : 6.0; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     statePeerTab.visibleTabOrder | 
					
						
							|  |  |  |         .removeWhere((e) => !StatePeerTab.tabIndexs.contains(e)); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     return Expanded( | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |         child: Obx(() { | 
					
						
							|  |  |  |       if (statePeerTab.visibleTabOrder.isEmpty) { | 
					
						
							|  |  |  |         return visibleContextMenuListener(Center( | 
					
						
							|  |  |  |           child: Text(translate('Right click to select tabs')), | 
					
						
							|  |  |  |         )); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (statePeerTab.visibleTabOrder | 
					
						
							|  |  |  |             .contains(statePeerTab.currentTab.value)) { | 
					
						
							|  |  |  |           return entries[statePeerTab.currentTab.value].widget; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           statePeerTab.currentTab.value = statePeerTab.visibleTabOrder[0]; | 
					
						
							|  |  |  |           return entries[statePeerTab.currentTab.value].widget; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }).marginSymmetric(vertical: verticalMargin)); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _createPeerViewTypeSwitch(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |     final textColor = Theme.of(context).textTheme.titleLarge?.color; | 
					
						
							|  |  |  |     final activeDeco = BoxDecoration(color: Theme.of(context).backgroundColor); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     return Row( | 
					
						
							| 
									
										
										
										
											2022-09-21 14:56:01 +08:00
										 |  |  |       children: [PeerUiType.grid, PeerUiType.list] | 
					
						
							|  |  |  |           .map((type) => Obx( | 
					
						
							|  |  |  |                 () => Container( | 
					
						
							|  |  |  |                   padding: EdgeInsets.all(4.0), | 
					
						
							|  |  |  |                   decoration: peerCardUiType.value == type ? activeDeco : null, | 
					
						
							|  |  |  |                   child: InkWell( | 
					
						
							|  |  |  |                       onTap: () async { | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |                         await bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |                             k: 'peer-card-ui-type', v: type.index.toString()); | 
					
						
							| 
									
										
										
										
											2022-09-21 14:56:01 +08:00
										 |  |  |                         peerCardUiType.value = type; | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                       child: Icon( | 
					
						
							|  |  |  |                         type == PeerUiType.grid | 
					
						
							|  |  |  |                             ? Icons.grid_view_rounded | 
					
						
							|  |  |  |                             : Icons.list, | 
					
						
							|  |  |  |                         size: 18, | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |                         color: | 
					
						
							|  |  |  |                             peerCardUiType.value == type ? textColor : textColor | 
					
						
							|  |  |  |                               ?..withOpacity(0.5), | 
					
						
							| 
									
										
										
										
											2022-09-21 14:56:01 +08:00
										 |  |  |                       )), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               )) | 
					
						
							|  |  |  |           .toList(), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   adjustTab() { | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     if (statePeerTab.visibleTabOrder.isNotEmpty) { | 
					
						
							|  |  |  |       if (!statePeerTab.visibleTabOrder | 
					
						
							|  |  |  |           .contains(statePeerTab.currentTab.value)) { | 
					
						
							|  |  |  |         handleTabSelection(statePeerTab.visibleTabOrder[0]); | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       statePeerTab.currentTab.value = 0; | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget visibleContextMenuListener(Widget child) { | 
					
						
							|  |  |  |     return Listener( | 
					
						
							|  |  |  |         onPointerDown: (e) { | 
					
						
							|  |  |  |           if (e.kind != ui.PointerDeviceKind.mouse) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (e.buttons == 2) { | 
					
						
							|  |  |  |             showRightMenu( | 
					
						
							|  |  |  |               (CancelFunc cancelFunc) { | 
					
						
							|  |  |  |                 return visibleContextMenu(cancelFunc); | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |               target: e.position, | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         child: child); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget visibleContextMenu(CancelFunc cancelFunc) { | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     return Obx(() { | 
					
						
							|  |  |  |       final List<MenuEntryBase> menu = List.empty(growable: true); | 
					
						
							|  |  |  |       for (int i = 0; i < statePeerTab.tabNames.length; i++) { | 
					
						
							|  |  |  |         if (i == groupTabIndex && statePeerTab.filterGroupCard()) { | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         int bitMask = 1 << i; | 
					
						
							|  |  |  |         menu.add(MenuEntrySwitch( | 
					
						
							|  |  |  |             switchType: SwitchType.scheckbox, | 
					
						
							| 
									
										
										
										
											2022-12-17 12:28:11 +08:00
										 |  |  |             text: translatedTabname(i), | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |             getter: () async { | 
					
						
							|  |  |  |               return statePeerTab.tabHiddenFlag & bitMask == 0; | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             setter: (show) async { | 
					
						
							|  |  |  |               if (show) { | 
					
						
							|  |  |  |                 statePeerTab.tabHiddenFlag &= ~bitMask; | 
					
						
							|  |  |  |               } else { | 
					
						
							|  |  |  |                 statePeerTab.tabHiddenFlag |= bitMask; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               await bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |                   k: 'hidden-peer-card', | 
					
						
							|  |  |  |                   v: statePeerTab.tabHiddenFlag.toRadixString(2)); | 
					
						
							|  |  |  |               statePeerTab.visibleTabOrder | 
					
						
							|  |  |  |                   .removeWhere((e) => statePeerTab.isTabHidden(e)); | 
					
						
							|  |  |  |               for (int j = 0; j < statePeerTab.tabNames.length; j++) { | 
					
						
							| 
									
										
										
										
											2022-12-17 12:28:11 +08:00
										 |  |  |                 if (!statePeerTab.isTabHidden(j) && | 
					
						
							|  |  |  |                     !(j == groupTabIndex && statePeerTab.filterGroupCard())) { | 
					
						
							|  |  |  |                   statePeerTab.addTabInOrder(statePeerTab.visibleTabOrder, j); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |                 } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               statePeerTab.saveTabOrder(); | 
					
						
							|  |  |  |               cancelFunc(); | 
					
						
							|  |  |  |               adjustTab(); | 
					
						
							|  |  |  |             })); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return mod_menu.PopupMenu( | 
					
						
							|  |  |  |           items: menu | 
					
						
							|  |  |  |               .map((entry) => entry.build( | 
					
						
							|  |  |  |                   context, | 
					
						
							|  |  |  |                   const MenuConfig( | 
					
						
							|  |  |  |                     commonColor: MyTheme.accent, | 
					
						
							|  |  |  |                     height: 20.0, | 
					
						
							|  |  |  |                     dividerHeight: 12.0, | 
					
						
							|  |  |  |                   ))) | 
					
						
							|  |  |  |               .expand((i) => i) | 
					
						
							|  |  |  |               .toList()); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PeerSearchBar extends StatefulWidget { | 
					
						
							|  |  |  |   const PeerSearchBar({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<StatefulWidget> createState() => _PeerSearchBarState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _PeerSearchBarState extends State<PeerSearchBar> { | 
					
						
							|  |  |  |   var drawer = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return drawer | 
					
						
							|  |  |  |         ? _buildSearchBar() | 
					
						
							|  |  |  |         : IconButton( | 
					
						
							|  |  |  |             alignment: Alignment.centerRight, | 
					
						
							|  |  |  |             padding: const EdgeInsets.only(right: 2), | 
					
						
							|  |  |  |             onPressed: () { | 
					
						
							|  |  |  |               setState(() { | 
					
						
							|  |  |  |                 drawer = true; | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2022-09-23 17:16:25 +08:00
										 |  |  |             icon: Icon( | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |               Icons.search_rounded, | 
					
						
							| 
									
										
										
										
											2022-09-23 17:16:25 +08:00
										 |  |  |               color: Theme.of(context).hintColor, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |             )); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildSearchBar() { | 
					
						
							|  |  |  |     RxBool focused = false.obs; | 
					
						
							|  |  |  |     FocusNode focusNode = FocusNode(); | 
					
						
							|  |  |  |     focusNode.addListener(() => focused.value = focusNode.hasFocus); | 
					
						
							|  |  |  |     return Container( | 
					
						
							|  |  |  |       width: 120, | 
					
						
							|  |  |  |       decoration: BoxDecoration( | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |         color: Theme.of(context).backgroundColor, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |         borderRadius: BorderRadius.circular(6), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       child: Obx(() => Row( | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: Row( | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     Icon( | 
					
						
							|  |  |  |                       Icons.search_rounded, | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |                       color: Theme.of(context).hintColor, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                     ).marginSymmetric(horizontal: 4), | 
					
						
							|  |  |  |                     Expanded( | 
					
						
							|  |  |  |                       child: TextField( | 
					
						
							|  |  |  |                         autofocus: true, | 
					
						
							|  |  |  |                         controller: peerSearchTextController, | 
					
						
							|  |  |  |                         onChanged: (searchText) { | 
					
						
							|  |  |  |                           peerSearchText.value = searchText; | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         focusNode: focusNode, | 
					
						
							|  |  |  |                         textAlign: TextAlign.start, | 
					
						
							|  |  |  |                         maxLines: 1, | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |                         cursorColor: Theme.of(context) | 
					
						
							|  |  |  |                             .textTheme | 
					
						
							|  |  |  |                             .titleLarge | 
					
						
							|  |  |  |                             ?.color | 
					
						
							|  |  |  |                             ?.withOpacity(0.5), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                         cursorHeight: 18, | 
					
						
							|  |  |  |                         cursorWidth: 1, | 
					
						
							|  |  |  |                         style: const TextStyle(fontSize: 14), | 
					
						
							|  |  |  |                         decoration: InputDecoration( | 
					
						
							|  |  |  |                           contentPadding: | 
					
						
							|  |  |  |                               const EdgeInsets.symmetric(vertical: 6), | 
					
						
							|  |  |  |                           hintText: | 
					
						
							|  |  |  |                               focused.value ? null : translate("Search ID"), | 
					
						
							|  |  |  |                           hintStyle: TextStyle( | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |                               fontSize: 14, color: Theme.of(context).hintColor), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                           border: InputBorder.none, | 
					
						
							|  |  |  |                           isDense: true, | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                     // Icon(Icons.close),
 | 
					
						
							|  |  |  |                     IconButton( | 
					
						
							|  |  |  |                         alignment: Alignment.centerRight, | 
					
						
							|  |  |  |                         padding: const EdgeInsets.only(right: 2), | 
					
						
							|  |  |  |                         onPressed: () { | 
					
						
							|  |  |  |                           setState(() { | 
					
						
							|  |  |  |                             peerSearchTextController.clear(); | 
					
						
							|  |  |  |                             peerSearchText.value = ""; | 
					
						
							|  |  |  |                             drawer = false; | 
					
						
							|  |  |  |                           }); | 
					
						
							|  |  |  |                         }, | 
					
						
							| 
									
										
										
										
											2022-09-23 17:16:25 +08:00
										 |  |  |                         icon: Icon( | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                           Icons.close, | 
					
						
							| 
									
										
										
										
											2022-09-23 17:16:25 +08:00
										 |  |  |                           color: Theme.of(context).hintColor, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                         )), | 
					
						
							|  |  |  |                   ], | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           )), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |