2023-09-14 11:30:45 +03:00
import ' dart:convert ' ;
2023-08-04 08:11:24 +03:00
import ' dart:math ' ;
2023-02-03 10:07:45 +03:00
import ' package:flutter/material.dart ' ;
2024-05-18 18:13:54 +03:00
import ' package:flutter_hbb/consts.dart ' ;
2023-08-03 11:48:14 +03:00
import ' package:flutter_hbb/models/peer_model.dart ' ;
2023-02-03 10:07:45 +03:00
import ' package:flutter_hbb/models/platform_model.dart ' ;
2023-08-03 11:48:14 +03:00
import ' package:get/get.dart ' ;
2023-02-03 10:07:45 +03:00
import ' ../common.dart ' ;
import ' model.dart ' ;
2023-08-03 11:48:14 +03:00
enum PeerTabIndex {
recent ,
fav ,
lan ,
ab ,
group ,
}
2023-02-03 10:07:45 +03:00
class PeerTabModel with ChangeNotifier {
WeakReference < FFI > parent ;
int get currentTab = > _currentTab ;
int _currentTab = 0 ; // index in tabNames
2024-04-06 12:53:03 +03:00
static const int maxTabCount = 5 ;
static const List < String > tabNames = [
2023-11-06 15:12:01 +03:00
' Recent sessions ' ,
2023-02-03 10:07:45 +03:00
' Favorites ' ,
2024-04-06 12:53:03 +03:00
' Discovered ' ,
' Address book ' ,
' Group ' ,
2023-02-03 10:07:45 +03:00
] ;
2024-04-06 12:53:03 +03:00
static const List < IconData > icons = [
2023-06-23 07:58:27 +03:00
Icons . access_time_filled ,
2023-06-21 11:04:52 +03:00
Icons . star ,
2024-04-06 12:53:03 +03:00
Icons . explore ,
IconFont . addressBook ,
Icons . group ,
2023-06-21 11:04:52 +03:00
] ;
2024-04-06 12:53:03 +03:00
List < bool > isEnabled = List . from ( [
true ,
true ,
! isWeb ,
! ( bind . isDisableAb ( ) | | bind . isDisableAccount ( ) ) ,
2024-05-28 15:10:12 +03:00
! ( bind . isDisableGroupPanel ( ) | | bind . isDisableAccount ( ) ) ,
2024-04-06 12:53:03 +03:00
] ) ;
final List < bool > _isVisible = List . filled ( maxTabCount , true , growable: false ) ;
List < bool > get isVisibleEnabled = > ( ) {
final list = _isVisible . toList ( ) ;
for ( int i = 0 ; i < maxTabCount ; i + + ) {
list [ i ] = list [ i ] & & isEnabled [ i ] ;
}
return list ;
} ( ) ;
final List < int > orders =
List . generate ( maxTabCount , ( index ) = > index , growable: false ) ;
List < int > get visibleEnabledOrderedIndexs = >
orders . where ( ( e ) = > isVisibleEnabled [ e ] ) . toList ( ) ;
2023-08-03 11:48:14 +03:00
List < Peer > _selectedPeers = List . empty ( growable: true ) ;
List < Peer > get selectedPeers = > _selectedPeers ;
2023-08-09 17:00:15 +03:00
bool _multiSelectionMode = false ;
bool get multiSelectionMode = > _multiSelectionMode ;
2023-08-03 11:48:14 +03:00
List < Peer > _currentTabCachedPeers = List . empty ( growable: true ) ;
List < Peer > get currentTabCachedPeers = > _currentTabCachedPeers ;
2023-08-09 17:00:15 +03:00
bool _isShiftDown = false ;
bool get isShiftDown = > _isShiftDown ;
String _lastId = ' ' ;
String get lastId = > _lastId ;
2023-02-03 10:07:45 +03:00
PeerTabModel ( this . parent ) {
2023-09-14 11:30:45 +03:00
// visible
try {
2024-05-18 18:13:54 +03:00
final option = bind . getLocalFlutterOption ( k: kOptionPeerTabVisible ) ;
2023-09-14 11:30:45 +03:00
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 " ) ;
}
2024-04-06 12:53:03 +03:00
// order
try {
2024-05-18 18:13:54 +03:00
final option = bind . getLocalFlutterOption ( k: kOptionPeerTabOrder ) ;
2024-04-06 12:53:03 +03:00
if ( option . isNotEmpty ) {
List < dynamic > decodeList = jsonDecode ( option ) ;
if ( decodeList . length = = maxTabCount ) {
var sortedList = decodeList . toList ( ) ;
sortedList . sort ( ) ;
bool valid = true ;
for ( int i = 0 ; i < maxTabCount ; i + + ) {
if ( sortedList [ i ] is ! int | | sortedList [ i ] ! = i ) {
valid = false ;
}
}
if ( valid ) {
for ( int i = 0 ; i < orders . length ; i + + ) {
orders [ i ] = decodeList [ i ] ;
}
}
}
}
} catch ( e ) {
debugPrint ( " failed to get peer tab order list: $ e " ) ;
}
2023-02-03 10:07:45 +03:00
// init currentTab
_currentTab =
2024-05-18 18:13:54 +03:00
int . tryParse ( bind . getLocalFlutterOption ( k: kOptionPeerTabIndex ) ) ? ? 0 ;
2024-04-06 12:53:03 +03:00
if ( _currentTab < 0 | | _currentTab > = maxTabCount ) {
2023-06-21 11:04:52 +03:00
_currentTab = 0 ;
2023-02-03 10:07:45 +03:00
}
2024-04-06 12:53:03 +03:00
_trySetCurrentTabToFirstVisibleEnabled ( ) ;
2023-02-03 10:07:45 +03:00
}
setCurrentTab ( int index ) {
if ( _currentTab ! = index ) {
_currentTab = index ;
notifyListeners ( ) ;
}
}
2023-09-14 05:17:03 +03:00
String tabTooltip ( int index ) {
2023-02-03 10:07:45 +03:00
if ( index > = 0 & & index < tabNames . length ) {
2023-09-14 05:17:03 +03:00
return translate ( tabNames [ index ] ) ;
2023-02-03 10:07:45 +03:00
}
return index . toString ( ) ;
}
2023-06-21 11:04:52 +03:00
IconData tabIcon ( int index ) {
2024-04-06 12:53:03 +03:00
if ( index > = 0 & & index < icons . length ) {
2023-06-21 11:04:52 +03:00
return icons [ index ] ;
2023-02-03 10:07:45 +03:00
}
2023-06-21 11:04:52 +03:00
return Icons . help ;
2023-02-03 10:07:45 +03:00
}
2023-08-03 11:48:14 +03:00
2023-08-09 17:00:15 +03: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 08:11:24 +03:00
final cached = _currentTabCachedPeers . map ( ( e ) = > e . id ) . toList ( ) ;
int thisIndex = cached . indexOf ( peer . id ) ;
2023-08-09 17:00:15 +03: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 08:11:24 +03:00
for ( var i = start ; i < = end ; i + + ) {
2023-08-09 17:00:15 +03: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 08:11:24 +03:00
}
}
2023-08-03 11:48:14 +03:00
} else {
2023-08-04 08:11:24 +03:00
if ( isPeerSelected ( peer . id ) ) {
_selectedPeers . removeWhere ( ( p ) = > p . id = = peer . id ) ;
} else {
_selectedPeers . add ( peer ) ;
}
2023-08-03 11:48:14 +03:00
}
2023-08-09 17:00:15 +03:00
_lastId = peer . id ;
2023-08-03 11:48:14 +03: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 17:00:15 +03:00
setShiftDown ( bool v ) {
if ( _isShiftDown ! = v ) {
_isShiftDown = v ;
if ( _multiSelectionMode ) {
notifyListeners ( ) ;
}
}
}
2023-09-14 11:30:45 +03:00
setTabVisible ( int index , bool visible ) {
2024-04-06 12:53:03 +03:00
if ( index > = 0 & & index < maxTabCount ) {
2023-09-14 11:30:45 +03:00
if ( _isVisible [ index ] ! = visible ) {
_isVisible [ index ] = visible ;
if ( index = = _currentTab & & ! visible ) {
2024-04-06 12:53:03 +03:00
_trySetCurrentTabToFirstVisibleEnabled ( ) ;
} else if ( visible & & visibleEnabledOrderedIndexs . length = = 1 ) {
2023-09-14 11:30:45 +03:00
_currentTab = index ;
}
try {
bind . setLocalFlutterOption (
2024-05-18 18:13:54 +03:00
k: kOptionPeerTabVisible , v: jsonEncode ( _isVisible ) ) ;
2023-09-14 11:30:45 +03:00
} catch ( _ ) { }
notifyListeners ( ) ;
}
}
}
2024-04-06 12:53:03 +03:00
_trySetCurrentTabToFirstVisibleEnabled ( ) {
if ( ! visibleEnabledOrderedIndexs . contains ( _currentTab ) ) {
if ( visibleEnabledOrderedIndexs . isNotEmpty ) {
_currentTab = visibleEnabledOrderedIndexs . first ;
}
}
}
reorder ( int oldIndex , int newIndex ) {
if ( oldIndex < newIndex ) {
newIndex - = 1 ;
}
if ( oldIndex < 0 | | oldIndex > = visibleEnabledOrderedIndexs . length ) {
return ;
}
if ( newIndex < 0 | | newIndex > = visibleEnabledOrderedIndexs . length ) {
return ;
}
final oldTabValue = visibleEnabledOrderedIndexs [ oldIndex ] ;
final newTabValue = visibleEnabledOrderedIndexs [ newIndex ] ;
int oldValueIndex = orders . indexOf ( oldTabValue ) ;
int newValueIndex = orders . indexOf ( newTabValue ) ;
final list = orders . toList ( ) ;
if ( oldIndex ! = - 1 & & newIndex ! = - 1 ) {
list . removeAt ( oldValueIndex ) ;
list . insert ( newValueIndex , oldTabValue ) ;
for ( int i = 0 ; i < list . length ; i + + ) {
orders [ i ] = list [ i ] ;
2023-09-14 11:30:45 +03:00
}
2024-05-18 18:13:54 +03:00
bind . setLocalFlutterOption ( k: kOptionPeerTabOrder , v: jsonEncode ( orders ) ) ;
2024-04-06 12:53:03 +03:00
notifyListeners ( ) ;
2023-09-14 11:30:45 +03:00
}
}
2023-02-03 10:07:45 +03:00
}