| 
									
										
										
										
											2023-09-14 16:30:45 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							| 
									
										
										
										
											2023-08-04 13:11:24 +08:00
										 |  |  | import 'dart:math'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  | import 'package:flutter_hbb/models/peer_model.dart'; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | import 'package:flutter_hbb/models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import '../common.dart'; | 
					
						
							|  |  |  | import 'model.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  | enum PeerTabIndex { | 
					
						
							|  |  |  |   recent, | 
					
						
							|  |  |  |   fav, | 
					
						
							|  |  |  |   lan, | 
					
						
							|  |  |  |   ab, | 
					
						
							|  |  |  |   group, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | class PeerTabModel with ChangeNotifier { | 
					
						
							|  |  |  |   WeakReference<FFI> parent; | 
					
						
							|  |  |  |   int get currentTab => _currentTab; | 
					
						
							|  |  |  |   int _currentTab = 0; // index in tabNames
 | 
					
						
							|  |  |  |   List<String> tabNames = [ | 
					
						
							| 
									
										
										
										
											2023-11-06 20:12:01 +08:00
										 |  |  |     'Recent sessions', | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     'Favorites', | 
					
						
							|  |  |  |     'Discovered', | 
					
						
							| 
									
										
										
										
											2023-11-06 20:12:01 +08:00
										 |  |  |     'Address book', | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     'Group', | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |   ]; | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |   final List<IconData> icons = [ | 
					
						
							| 
									
										
										
										
											2023-06-23 12:58:27 +08:00
										 |  |  |     Icons.access_time_filled, | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |     Icons.star, | 
					
						
							|  |  |  |     Icons.explore, | 
					
						
							|  |  |  |     IconFont.addressBook, | 
					
						
							|  |  |  |     Icons.group, | 
					
						
							|  |  |  |   ]; | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |   final List<bool> _isVisible = List.filled(5, true, growable: false); | 
					
						
							| 
									
										
										
										
											2023-09-14 16:30:45 +08:00
										 |  |  |   List<bool> get isVisible => _isVisible; | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |   List<int> get indexs => List.generate(tabNames.length, (index) => index); | 
					
						
							| 
									
										
										
										
											2023-09-14 16:30:45 +08:00
										 |  |  |   List<int> get visibleIndexs => indexs.where((e) => _isVisible[e]).toList(); | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  |   List<Peer> _selectedPeers = List.empty(growable: true); | 
					
						
							|  |  |  |   List<Peer> get selectedPeers => _selectedPeers; | 
					
						
							| 
									
										
										
										
											2023-08-09 22:00:15 +08:00
										 |  |  |   bool _multiSelectionMode = false; | 
					
						
							|  |  |  |   bool get multiSelectionMode => _multiSelectionMode; | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  |   List<Peer> _currentTabCachedPeers = List.empty(growable: true); | 
					
						
							|  |  |  |   List<Peer> get currentTabCachedPeers => _currentTabCachedPeers; | 
					
						
							| 
									
										
										
										
											2023-08-09 22:00:15 +08:00
										 |  |  |   bool _isShiftDown = false; | 
					
						
							|  |  |  |   bool get isShiftDown => _isShiftDown; | 
					
						
							|  |  |  |   String _lastId = ''; | 
					
						
							|  |  |  |   String get lastId => _lastId; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   PeerTabModel(this.parent) { | 
					
						
							| 
									
										
										
										
											2023-09-14 16:30:45 +08:00
										 |  |  |     // visible
 | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       final option = bind.getLocalFlutterOption(k: 'peer-tab-visible'); | 
					
						
							|  |  |  |       if (option.isNotEmpty) { | 
					
						
							|  |  |  |         List<dynamic> decodeList = jsonDecode(option); | 
					
						
							|  |  |  |         if (decodeList.length == _isVisible.length) { | 
					
						
							|  |  |  |           for (int i = 0; i < _isVisible.length; i++) { | 
					
						
							|  |  |  |             if (decodeList[i] is bool) { | 
					
						
							|  |  |  |               _isVisible[i] = decodeList[i]; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrint("failed to get peer tab visible list:$e"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     // init currentTab
 | 
					
						
							|  |  |  |     _currentTab = | 
					
						
							| 
									
										
										
										
											2023-08-10 22:27:35 +08:00
										 |  |  |         int.tryParse(bind.getLocalFlutterOption(k: 'peer-tab-index')) ?? 0; | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |     if (_currentTab < 0 || _currentTab >= tabNames.length) { | 
					
						
							|  |  |  |       _currentTab = 0; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-14 16:30:45 +08:00
										 |  |  |     _trySetCurrentTabToFirstVisible(); | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setCurrentTab(int index) { | 
					
						
							|  |  |  |     if (_currentTab != index) { | 
					
						
							|  |  |  |       _currentTab = index; | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |   String tabTooltip(int index) { | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     if (index >= 0 && index < tabNames.length) { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       return translate(tabNames[index]); | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     assert(false); | 
					
						
							|  |  |  |     return index.toString(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |   IconData tabIcon(int index) { | 
					
						
							|  |  |  |     if (index >= 0 && index < tabNames.length) { | 
					
						
							|  |  |  |       return icons[index]; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |     assert(false); | 
					
						
							|  |  |  |     return Icons.help; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-09 22:00:15 +08:00
										 |  |  |   setMultiSelectionMode(bool mode) { | 
					
						
							|  |  |  |     _multiSelectionMode = mode; | 
					
						
							|  |  |  |     if (!mode) { | 
					
						
							|  |  |  |       _selectedPeers.clear(); | 
					
						
							|  |  |  |       _lastId = ''; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   select(Peer peer) { | 
					
						
							|  |  |  |     if (!_multiSelectionMode) { | 
					
						
							|  |  |  |       // https://github.com/flutter/flutter/issues/101275#issuecomment-1604541700
 | 
					
						
							|  |  |  |       // After onTap, the shift key should be pressed for a while when not in multiselection mode,
 | 
					
						
							|  |  |  |       // because onTap is delayed when onDoubleTap is not null
 | 
					
						
							|  |  |  |       if (isDesktop && !_isShiftDown) return; | 
					
						
							|  |  |  |       _multiSelectionMode = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-04 13:11:24 +08:00
										 |  |  |     final cached = _currentTabCachedPeers.map((e) => e.id).toList(); | 
					
						
							|  |  |  |     int thisIndex = cached.indexOf(peer.id); | 
					
						
							| 
									
										
										
										
											2023-08-09 22:00:15 +08:00
										 |  |  |     int lastIndex = cached.indexOf(_lastId); | 
					
						
							|  |  |  |     if (_isShiftDown && thisIndex >= 0 && lastIndex >= 0) { | 
					
						
							|  |  |  |       int start = min(thisIndex, lastIndex); | 
					
						
							|  |  |  |       int end = max(thisIndex, lastIndex); | 
					
						
							|  |  |  |       bool remove = isPeerSelected(peer.id); | 
					
						
							| 
									
										
										
										
											2023-08-04 13:11:24 +08:00
										 |  |  |       for (var i = start; i <= end; i++) { | 
					
						
							| 
									
										
										
										
											2023-08-09 22:00:15 +08:00
										 |  |  |         if (remove) { | 
					
						
							|  |  |  |           if (isPeerSelected(cached[i])) { | 
					
						
							|  |  |  |             _selectedPeers.removeWhere((p) => p.id == cached[i]); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           if (!isPeerSelected(cached[i])) { | 
					
						
							|  |  |  |             _selectedPeers.add(_currentTabCachedPeers[i]); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2023-08-04 13:11:24 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-08-04 13:11:24 +08:00
										 |  |  |       if (isPeerSelected(peer.id)) { | 
					
						
							|  |  |  |         _selectedPeers.removeWhere((p) => p.id == peer.id); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         _selectedPeers.add(peer); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-09 22:00:15 +08:00
										 |  |  |     _lastId = peer.id; | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setCurrentTabCachedPeers(List<Peer> peers) { | 
					
						
							|  |  |  |     Future.delayed(Duration.zero, () { | 
					
						
							|  |  |  |       _currentTabCachedPeers = peers; | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   selectAll() { | 
					
						
							|  |  |  |     _selectedPeers = _currentTabCachedPeers.toList(); | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool isPeerSelected(String id) { | 
					
						
							|  |  |  |     return selectedPeers.firstWhereOrNull((p) => p.id == id) != null; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-08-09 22:00:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   setShiftDown(bool v) { | 
					
						
							|  |  |  |     if (_isShiftDown != v) { | 
					
						
							|  |  |  |       _isShiftDown = v; | 
					
						
							|  |  |  |       if (_multiSelectionMode) { | 
					
						
							|  |  |  |         notifyListeners(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-09-14 16:30:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   setTabVisible(int index, bool visible) { | 
					
						
							|  |  |  |     if (index >= 0 && index < _isVisible.length) { | 
					
						
							|  |  |  |       if (_isVisible[index] != visible) { | 
					
						
							|  |  |  |         _isVisible[index] = visible; | 
					
						
							|  |  |  |         if (index == _currentTab && !visible) { | 
					
						
							|  |  |  |           _trySetCurrentTabToFirstVisible(); | 
					
						
							|  |  |  |         } else if (visible && visibleIndexs.length == 1) { | 
					
						
							|  |  |  |           _currentTab = index; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           bind.setLocalFlutterOption( | 
					
						
							|  |  |  |               k: 'peer-tab-visible', v: jsonEncode(_isVisible)); | 
					
						
							|  |  |  |         } catch (_) {} | 
					
						
							|  |  |  |         notifyListeners(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _trySetCurrentTabToFirstVisible() { | 
					
						
							|  |  |  |     if (!_isVisible[_currentTab]) { | 
					
						
							|  |  |  |       int firstVisible = _isVisible.indexWhere((e) => e); | 
					
						
							|  |  |  |       if (firstVisible >= 0) { | 
					
						
							|  |  |  |         _currentTab = firstVisible; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | } |