| 
									
										
										
										
											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'; | 
					
						
							| 
									
										
										
										
											2023-06-21 11:51:35 +08:00
										 |  |  | import 'package:flutter_hbb/common/widgets/animated_rotation_widget.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'; | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | import 'package:flutter_hbb/models/peer_tab_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | import 'package:provider/provider.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import '../../common.dart'; | 
					
						
							|  |  |  | import '../../models/platform_model.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2023-06-23 15:10:10 +08:00
										 |  |  |   final Function({dynamic hint}) 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
										 |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-06-23 15:10:10 +08:00
										 |  |  |         ({dynamic hint}) => gFFI.abModel.pullAb(force: hint == null)), | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     _TabEntry( | 
					
						
							| 
									
										
										
										
											2023-06-21 11:51:35 +08:00
										 |  |  |       MyGroup( | 
					
						
							|  |  |  |         menuPadding: _menuPadding(), | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2023-06-23 15:10:10 +08:00
										 |  |  |       ({dynamic hint}) => gFFI.groupModel.pull(force: hint == null), | 
					
						
							| 
									
										
										
										
											2023-06-21 11:51:35 +08:00
										 |  |  |     ), | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |   ]; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-29 15:18:35 +08:00
										 |  |  |     hideAbTagsPanel.value = | 
					
						
							|  |  |  |         bind.mainGetLocalOption(key: "hideAbTagsPanel").isNotEmpty; | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |       gFFI.peerTabModel.setCurrentTab(tabIndex); | 
					
						
							| 
									
										
										
										
											2023-06-23 15:10:10 +08:00
										 |  |  |       entries[tabIndex].load(hint: false); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Column( | 
					
						
							|  |  |  |       textBaseline: TextBaseline.ideographic, | 
					
						
							|  |  |  |       crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         SizedBox( | 
					
						
							| 
									
										
										
										
											2023-06-24 18:27:47 +08:00
										 |  |  |           height: 32, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |           child: Container( | 
					
						
							| 
									
										
										
										
											2023-03-03 20:53:42 +01:00
										 |  |  |             padding: isDesktop ? null : EdgeInsets.symmetric(horizontal: 2), | 
					
						
							|  |  |  |             child: Row( | 
					
						
							|  |  |  |               crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |               children: [ | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |                 Expanded(child: _createSwitchBar(context)), | 
					
						
							|  |  |  |                 const PeerSearchBar().marginOnly(right: isMobile ? 0 : 13), | 
					
						
							| 
									
										
										
										
											2023-06-21 11:51:35 +08:00
										 |  |  |                 _createRefresh(), | 
					
						
							| 
									
										
										
										
											2023-03-03 20:53:42 +01:00
										 |  |  |                 Offstage( | 
					
						
							|  |  |  |                     offstage: !isDesktop, | 
					
						
							| 
									
										
										
										
											2023-06-21 11:51:35 +08:00
										 |  |  |                     child: _createPeerViewTypeSwitch(context)), | 
					
						
							| 
									
										
										
										
											2023-03-08 16:40:35 +01:00
										 |  |  |                 Offstage( | 
					
						
							| 
									
										
										
										
											2023-06-21 01:33:52 +08:00
										 |  |  |                   offstage: gFFI.peerTabModel.currentTab == 0, | 
					
						
							| 
									
										
										
										
											2023-03-08 16:40:35 +01:00
										 |  |  |                   child: PeerSortDropdown().marginOnly(left: 8), | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2023-06-29 15:18:35 +08:00
										 |  |  |                 Offstage( | 
					
						
							|  |  |  |                   offstage: gFFI.peerTabModel.currentTab != 3, | 
					
						
							|  |  |  |                   child: InkWell( | 
					
						
							|  |  |  |                     child: Obx(() => Container( | 
					
						
							|  |  |  |                         padding: EdgeInsets.all(4.0), | 
					
						
							|  |  |  |                         decoration: hideAbTagsPanel.value | 
					
						
							|  |  |  |                             ? null | 
					
						
							|  |  |  |                             : BoxDecoration( | 
					
						
							|  |  |  |                                 color: Theme.of(context).colorScheme.background, | 
					
						
							|  |  |  |                                 borderRadius: BorderRadius.circular(6)), | 
					
						
							|  |  |  |                         child: Icon( | 
					
						
							|  |  |  |                           Icons.tag_rounded, | 
					
						
							|  |  |  |                           size: 18, | 
					
						
							|  |  |  |                         ))), | 
					
						
							|  |  |  |                     onTap: () async { | 
					
						
							|  |  |  |                       await bind.mainSetLocalOption( | 
					
						
							|  |  |  |                           key: "hideAbTagsPanel", | 
					
						
							|  |  |  |                           value: hideAbTagsPanel.value ? "" : "Y"); | 
					
						
							|  |  |  |                       hideAbTagsPanel.value = !hideAbTagsPanel.value; | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                   ).marginOnly(left: 8), | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2023-03-03 20:53:42 +01:00
										 |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |         ), | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |     final model = Provider.of<PeerTabModel>(context); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ListView( | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |         scrollDirection: Axis.horizontal, | 
					
						
							|  |  |  |         physics: NeverScrollableScrollPhysics(), | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |         children: model.indexs.map((t) { | 
					
						
							| 
									
										
										
										
											2023-06-24 18:27:47 +08:00
										 |  |  |           final selected = model.currentTab == t; | 
					
						
							|  |  |  |           final color = selected | 
					
						
							|  |  |  |               ? MyTheme.tabbar(context).selectedTextColor | 
					
						
							|  |  |  |               : MyTheme.tabbar(context).unSelectedTextColor | 
					
						
							|  |  |  |             ?..withOpacity(0.5); | 
					
						
							|  |  |  |           final hover = false.obs; | 
					
						
							|  |  |  |           final deco = BoxDecoration( | 
					
						
							|  |  |  |               color: Theme.of(context).colorScheme.background, | 
					
						
							|  |  |  |               borderRadius: BorderRadius.circular(6)); | 
					
						
							|  |  |  |           final decoBorder = BoxDecoration( | 
					
						
							|  |  |  |               border: Border( | 
					
						
							|  |  |  |             bottom: BorderSide(width: 2, color: color!), | 
					
						
							|  |  |  |           )); | 
					
						
							|  |  |  |           return Obx(() => InkWell( | 
					
						
							|  |  |  |                 child: Container( | 
					
						
							|  |  |  |                   decoration: | 
					
						
							|  |  |  |                       selected ? decoBorder : (hover.value ? deco : null), | 
					
						
							|  |  |  |                   child: Tooltip( | 
					
						
							|  |  |  |                     message: | 
					
						
							|  |  |  |                         model.tabTooltip(t, gFFI.groupModel.groupName.value), | 
					
						
							|  |  |  |                     child: Icon(model.tabIcon(t), color: color), | 
					
						
							|  |  |  |                   ).paddingSymmetric(horizontal: 4), | 
					
						
							|  |  |  |                 ).paddingSymmetric(horizontal: 4), | 
					
						
							|  |  |  |                 onTap: () async { | 
					
						
							|  |  |  |                   await handleTabSelection(t); | 
					
						
							|  |  |  |                   await bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |                       k: 'peer-tab-index', v: t.toString()); | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 onHover: (value) => hover.value = value, | 
					
						
							|  |  |  |               )); | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |         }).toList()); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 11:20:57 +08:00
										 |  |  |   Widget _createPeersView() { | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     final model = Provider.of<PeerTabModel>(context); | 
					
						
							|  |  |  |     Widget child; | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |     if (model.indexs.isEmpty) { | 
					
						
							|  |  |  |       child = Center( | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |         child: Text(translate('Right click to select tabs')), | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |       ); | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |       if (model.indexs.contains(model.currentTab)) { | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |         child = entries[model.currentTab].widget; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2023-06-17 20:48:58 +08:00
										 |  |  |         Future.delayed(Duration.zero, () { | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |           model.setCurrentTab(model.indexs[0]); | 
					
						
							| 
									
										
										
										
											2023-06-17 20:48:58 +08:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |         child = entries[0].widget; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return Expanded( | 
					
						
							|  |  |  |         child: child.marginSymmetric(vertical: isDesktop ? 12.0 : 6.0)); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 11:51:35 +08:00
										 |  |  |   Widget _createRefresh() { | 
					
						
							|  |  |  |     final textColor = Theme.of(context).textTheme.titleLarge?.color; | 
					
						
							|  |  |  |     return Offstage( | 
					
						
							|  |  |  |       offstage: gFFI.peerTabModel.currentTab < 3, // local tab can't see effect
 | 
					
						
							|  |  |  |       child: Container( | 
					
						
							|  |  |  |         padding: EdgeInsets.all(4.0), | 
					
						
							|  |  |  |         child: AnimatedRotationWidget( | 
					
						
							|  |  |  |             onPressed: () { | 
					
						
							|  |  |  |               if (gFFI.peerTabModel.currentTab < entries.length) { | 
					
						
							|  |  |  |                 entries[gFFI.peerTabModel.currentTab].load(); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             child: RotatedBox( | 
					
						
							|  |  |  |                 quarterTurns: 2, | 
					
						
							|  |  |  |                 child: Icon( | 
					
						
							|  |  |  |                   Icons.refresh, | 
					
						
							|  |  |  |                   size: 18, | 
					
						
							|  |  |  |                   color: textColor, | 
					
						
							|  |  |  |                 ))), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2023-06-24 17:52:48 +08:00
										 |  |  |     final types = [PeerUiType.grid, PeerUiType.list]; | 
					
						
							|  |  |  |     final hover = false.obs; | 
					
						
							| 
									
										
										
										
											2023-03-08 16:40:35 +01:00
										 |  |  |     final deco = BoxDecoration( | 
					
						
							| 
									
										
										
										
											2023-03-07 19:27:39 +01:00
										 |  |  |       color: Theme.of(context).colorScheme.background, | 
					
						
							|  |  |  |       borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Obx( | 
					
						
							|  |  |  |       () => Container( | 
					
						
							|  |  |  |         padding: EdgeInsets.all(4.0), | 
					
						
							| 
									
										
										
										
											2023-06-24 17:52:48 +08:00
										 |  |  |         decoration: hover.value ? deco : null, | 
					
						
							| 
									
										
										
										
											2023-03-07 19:27:39 +01:00
										 |  |  |         child: InkWell( | 
					
						
							| 
									
										
										
										
											2023-06-24 17:52:48 +08:00
										 |  |  |             onHover: (value) => hover.value = value, | 
					
						
							| 
									
										
										
										
											2023-03-07 19:27:39 +01:00
										 |  |  |             onTap: () async { | 
					
						
							|  |  |  |               final type = types.elementAt( | 
					
						
							|  |  |  |                   peerCardUiType.value == types.elementAt(0) ? 1 : 0); | 
					
						
							|  |  |  |               await bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |                   k: 'peer-card-ui-type', v: type.index.toString()); | 
					
						
							|  |  |  |               peerCardUiType.value = type; | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             child: Icon( | 
					
						
							|  |  |  |               peerCardUiType.value == PeerUiType.grid | 
					
						
							| 
									
										
										
										
											2023-06-24 17:52:48 +08:00
										 |  |  |                   ? Icons.view_list_rounded | 
					
						
							| 
									
										
										
										
											2023-03-07 19:27:39 +01:00
										 |  |  |                   : Icons.grid_view_rounded, | 
					
						
							|  |  |  |               size: 18, | 
					
						
							|  |  |  |               color: textColor, | 
					
						
							|  |  |  |             )), | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											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(); | 
					
						
							| 
									
										
										
										
											2023-01-30 18:30:38 +08:00
										 |  |  |     focusNode.addListener(() { | 
					
						
							|  |  |  |       focused.value = focusNode.hasFocus; | 
					
						
							| 
									
										
										
										
											2023-02-02 16:45:29 +08:00
										 |  |  |       peerSearchTextController.selection = TextSelection( | 
					
						
							|  |  |  |           baseOffset: 0, | 
					
						
							|  |  |  |           extentOffset: peerSearchTextController.value.text.length); | 
					
						
							| 
									
										
										
										
											2023-01-30 18:30:38 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     return Container( | 
					
						
							|  |  |  |       width: 120, | 
					
						
							|  |  |  |       decoration: BoxDecoration( | 
					
						
							| 
									
										
										
										
											2023-02-23 16:49:31 +01:00
										 |  |  |         color: Theme.of(context).colorScheme.background, | 
					
						
							| 
									
										
										
										
											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
										 |  |  |                         )), | 
					
						
							|  |  |  |                   ], | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           )), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-03-03 20:53:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | class PeerSortDropdown extends StatefulWidget { | 
					
						
							|  |  |  |   const PeerSortDropdown({super.key}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<PeerSortDropdown> createState() => _PeerSortDropdownState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _PeerSortDropdownState extends State<PeerSortDropdown> { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:04:03 +01:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     if (!PeerSortType.values.contains(peerSort.value)) { | 
					
						
							|  |  |  |       peerSort.value = PeerSortType.remoteId; | 
					
						
							|  |  |  |       bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |         k: "peer-sorting", | 
					
						
							|  |  |  |         v: peerSort.value, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-03 20:53:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2023-06-11 15:28:41 +08:00
										 |  |  |     final style = TextStyle( | 
					
						
							| 
									
										
										
										
											2023-06-10 07:08:10 +08:00
										 |  |  |         color: Theme.of(context).textTheme.titleLarge?.color, | 
					
						
							|  |  |  |         fontSize: MenuConfig.fontSize, | 
					
						
							|  |  |  |         fontWeight: FontWeight.normal); | 
					
						
							| 
									
										
										
										
											2023-06-10 06:56:45 +08:00
										 |  |  |     List<PopupMenuEntry> items = List.empty(growable: true); | 
					
						
							|  |  |  |     items.add(PopupMenuItem( | 
					
						
							| 
									
										
										
										
											2023-06-11 16:32:22 +08:00
										 |  |  |         height: 36, | 
					
						
							|  |  |  |         enabled: false, | 
					
						
							|  |  |  |         child: Text(translate("Sort by"), style: style))); | 
					
						
							| 
									
										
										
										
											2023-06-10 06:56:45 +08:00
										 |  |  |     for (var e in PeerSortType.values) { | 
					
						
							|  |  |  |       items.add(PopupMenuItem( | 
					
						
							| 
									
										
										
										
											2023-06-11 16:32:22 +08:00
										 |  |  |           height: 36, | 
					
						
							|  |  |  |           child: Obx(() => Center( | 
					
						
							|  |  |  |                 child: SizedBox( | 
					
						
							|  |  |  |                   height: 36, | 
					
						
							|  |  |  |                   child: getRadio( | 
					
						
							|  |  |  |                       Text(translate(e), style: style), e, peerSort.value, | 
					
						
							|  |  |  |                       dense: true, (String? v) async { | 
					
						
							|  |  |  |                     if (v != null) { | 
					
						
							|  |  |  |                       peerSort.value = v; | 
					
						
							|  |  |  |                       await bind.setLocalFlutterConfig( | 
					
						
							|  |  |  |                         k: "peer-sorting", | 
					
						
							|  |  |  |                         v: peerSort.value, | 
					
						
							|  |  |  |                       ); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                   }), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               )))); | 
					
						
							| 
									
										
										
										
											2023-06-10 06:56:45 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-13 09:05:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 15:28:41 +08:00
										 |  |  |     var menuPos = RelativeRect.fromLTRB(0, 0, 0, 0); | 
					
						
							| 
									
										
										
										
											2023-06-10 06:56:45 +08:00
										 |  |  |     return InkWell( | 
					
						
							|  |  |  |       child: Icon( | 
					
						
							| 
									
										
										
										
											2023-06-23 13:26:45 +08:00
										 |  |  |         Icons.sort_rounded, | 
					
						
							| 
									
										
										
										
											2023-06-10 06:56:45 +08:00
										 |  |  |         size: 18, | 
					
						
							| 
									
										
										
										
											2023-03-08 16:40:35 +01:00
										 |  |  |       ), | 
					
						
							| 
									
										
										
										
											2023-06-10 06:56:45 +08:00
										 |  |  |       onTapDown: (details) { | 
					
						
							|  |  |  |         final x = details.globalPosition.dx; | 
					
						
							|  |  |  |         final y = details.globalPosition.dy; | 
					
						
							| 
									
										
										
										
											2023-06-11 15:28:41 +08:00
										 |  |  |         menuPos = RelativeRect.fromLTRB(x, y, x, y); | 
					
						
							| 
									
										
										
										
											2023-06-10 06:56:45 +08:00
										 |  |  |       }, | 
					
						
							| 
									
										
										
										
											2023-06-11 15:28:41 +08:00
										 |  |  |       onTap: () => showMenu( | 
					
						
							|  |  |  |         context: context, | 
					
						
							|  |  |  |         position: menuPos, | 
					
						
							|  |  |  |         items: items, | 
					
						
							|  |  |  |         elevation: 8, | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2023-03-03 20:53:42 +01:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |