2022-03-16 15:33:00 +08:00
import ' dart:async ' ;
2022-03-07 22:54:34 +08:00
import ' dart:convert ' ;
2022-06-13 21:07:26 +08:00
2022-03-07 22:54:34 +08:00
import ' package:flutter/material.dart ' ;
2022-06-13 21:07:26 +08:00
import ' package:flutter_hbb/common.dart ' ;
2022-05-24 23:33:00 +08:00
import ' package:flutter_hbb/mobile/pages/file_manager_page.dart ' ;
2022-04-19 13:07:45 +08:00
import ' package:flutter_smart_dialog/flutter_smart_dialog.dart ' ;
2022-07-09 19:14:40 +08:00
import ' package:get/get.dart ' ;
2022-03-12 21:42:05 +08:00
import ' package:path/path.dart ' as Path ;
2022-03-07 22:54:34 +08:00
import ' model.dart ' ;
2022-08-03 22:03:31 +08:00
import ' platform_model.dart ' ;
2022-03-07 22:54:34 +08:00
2022-03-23 15:28:21 +08:00
enum SortBy { Name , Type , Modified , Size }
2022-03-07 22:54:34 +08:00
2022-03-11 01:28:13 +08:00
class FileModel extends ChangeNotifier {
var _isLocal = false ;
var _selectMode = false ;
2022-03-07 22:54:34 +08:00
2022-03-17 21:03:52 +08:00
var _localOption = DirectoryOption ( ) ;
var _remoteOption = DirectoryOption ( ) ;
2022-03-11 01:28:13 +08:00
var _jobId = 0 ;
2022-03-07 22:54:34 +08:00
2022-03-11 01:28:13 +08:00
var _jobProgress = JobProgress ( ) ; // from rust update
2022-03-07 22:54:34 +08:00
2022-07-09 19:14:40 +08:00
/// JobTable <jobId, JobProgress>
final _jobTable = List < JobProgress > . empty ( growable: true ) . obs ;
RxList < JobProgress > get jobTable = > _jobTable ;
2022-03-11 01:28:13 +08:00
bool get isLocal = > _isLocal ;
2022-03-09 22:43:05 +08:00
2022-03-11 01:28:13 +08:00
bool get selectMode = > _selectMode ;
2022-03-07 22:54:34 +08:00
2022-03-11 01:28:13 +08:00
JobProgress get jobProgress = > _jobProgress ;
2022-03-07 22:54:34 +08:00
2022-03-11 01:28:13 +08:00
JobState get jobState = > _jobProgress . state ;
2022-03-07 22:54:34 +08:00
2022-03-23 15:28:21 +08:00
SortBy _sortStyle = SortBy . Name ;
2022-03-09 22:43:05 +08:00
2022-03-09 17:07:24 +08:00
SortBy get sortStyle = > _sortStyle ;
2022-03-07 22:54:34 +08:00
2022-07-11 16:07:49 +08:00
SortBy _localSortStyle = SortBy . Name ;
bool _localSortAscending = true ;
bool _remoteSortAscending = true ;
SortBy _remoteSortStyle = SortBy . Name ;
bool get localSortAscending = > _localSortAscending ;
2022-08-03 22:03:31 +08:00
SortBy getSortStyle ( bool isLocal ) {
2022-07-11 16:07:49 +08:00
return isLocal ? _localSortStyle : _remoteSortStyle ;
}
2022-03-09 22:43:05 +08:00
FileDirectory _currentLocalDir = FileDirectory ( ) ;
FileDirectory get currentLocalDir = > _currentLocalDir ;
2022-03-09 17:07:24 +08:00
FileDirectory _currentRemoteDir = FileDirectory ( ) ;
2022-03-09 22:43:05 +08:00
2022-03-07 22:54:34 +08:00
FileDirectory get currentRemoteDir = > _currentRemoteDir ;
2022-03-11 01:28:13 +08:00
FileDirectory get currentDir = > _isLocal ? currentLocalDir : currentRemoteDir ;
2022-07-11 16:07:49 +08:00
FileDirectory getCurrentDir ( bool isLocal ) {
return isLocal ? currentLocalDir : currentRemoteDir ;
}
2022-03-17 21:03:52 +08:00
String get currentHome = > _isLocal ? _localOption . home : _remoteOption . home ;
2022-07-09 19:14:40 +08:00
String getCurrentHome ( bool isLocal ) {
return isLocal ? _localOption . home : _remoteOption . home ;
}
2022-07-11 10:30:45 +08:00
int getJob ( int id ) {
return jobTable . indexWhere ( ( element ) = > element . id = = id ) ;
}
2022-03-17 21:03:52 +08:00
String get currentShortPath {
2022-04-07 16:20:32 +08:00
if ( currentDir . path . startsWith ( currentHome ) ) {
2022-03-17 21:03:52 +08:00
var path = currentDir . path . replaceFirst ( currentHome , " " ) ;
2022-04-07 16:20:32 +08:00
if ( path . length = = 0 ) return " " ;
if ( path [ 0 ] = = " / " | | path [ 0 ] = = " \\ " ) {
2022-03-17 21:03:52 +08:00
// remove more '/' or '\'
path = path . replaceFirst ( path [ 0 ] , " " ) ;
}
return path ;
2022-04-07 16:20:32 +08:00
} else {
2022-03-17 21:03:52 +08:00
return currentDir . path . replaceFirst ( currentHome , " " ) ;
}
}
2022-06-27 16:44:34 +08:00
String shortPath ( bool isLocal ) {
final dir = isLocal ? currentLocalDir : currentRemoteDir ;
if ( dir . path . startsWith ( currentHome ) ) {
var path = dir . path . replaceFirst ( currentHome , " " ) ;
if ( path . length = = 0 ) return " " ;
if ( path [ 0 ] = = " / " | | path [ 0 ] = = " \\ " ) {
// remove more '/' or '\'
path = path . replaceFirst ( path [ 0 ] , " " ) ;
}
return path ;
} else {
return dir . path . replaceFirst ( currentHome , " " ) ;
}
}
2022-03-17 21:03:52 +08:00
bool get currentShowHidden = >
_isLocal ? _localOption . showHidden : _remoteOption . showHidden ;
2022-07-11 16:07:49 +08:00
bool getCurrentShowHidden ( bool isLocal ) {
return isLocal ? _localOption . showHidden : _remoteOption . showHidden ;
}
2022-03-17 21:03:52 +08:00
bool get currentIsWindows = >
_isLocal ? _localOption . isWindows : _remoteOption . isWindows ;
2022-07-09 19:14:40 +08:00
bool getCurrentIsWindows ( bool isLocal ) {
return isLocal ? _localOption . isWindows : _remoteOption . isWindows ;
}
2022-03-16 15:33:00 +08:00
final _fileFetcher = FileFetcher ( ) ;
final _jobResultListener = JobResultListener < Map < String , dynamic > > ( ) ;
2022-06-13 21:07:26 +08:00
final WeakReference < FFI > _ffi ;
FileModel ( this . _ffi ) ;
2022-03-11 01:28:13 +08:00
toggleSelectMode ( ) {
2022-04-07 22:58:47 +08:00
if ( jobState = = JobState . inProgress ) {
return ;
}
2022-03-11 01:28:13 +08:00
_selectMode = ! _selectMode ;
notifyListeners ( ) ;
}
togglePage ( ) {
_isLocal = ! _isLocal ;
notifyListeners ( ) ;
}
2022-03-17 21:03:52 +08:00
toggleShowHidden ( { bool ? showHidden , bool ? local } ) {
final isLocal = local ? ? _isLocal ;
if ( isLocal ) {
_localOption . showHidden = showHidden ? ? ! _localOption . showHidden ;
} else {
_remoteOption . showHidden = showHidden ? ? ! _remoteOption . showHidden ;
}
2022-07-12 11:51:58 +08:00
refresh ( isLocal: local ) ;
2022-03-17 21:03:52 +08:00
}
2022-03-11 01:28:13 +08:00
tryUpdateJobProgress ( Map < String , dynamic > evt ) {
try {
int id = int . parse ( evt [ ' id ' ] ) ;
2022-07-09 19:14:40 +08:00
if ( ! isDesktop ) {
_jobProgress . id = id ;
_jobProgress . fileNum = int . parse ( evt [ ' file_num ' ] ) ;
_jobProgress . speed = double . parse ( evt [ ' speed ' ] ) ;
_jobProgress . finishedSize = int . parse ( evt [ ' finished_size ' ] ) ;
} else {
// Desktop uses jobTable
2022-07-11 10:30:45 +08:00
// id = index + 1
final jobIndex = getJob ( id ) ;
2022-08-03 22:03:31 +08:00
if ( jobIndex > = 0 & & _jobTable . length > jobIndex ) {
2022-07-11 10:30:45 +08:00
final job = _jobTable [ jobIndex ] ;
2022-07-09 19:14:40 +08:00
job . fileNum = int . parse ( evt [ ' file_num ' ] ) ;
job . speed = double . parse ( evt [ ' speed ' ] ) ;
job . finishedSize = int . parse ( evt [ ' finished_size ' ] ) ;
2022-07-11 10:30:45 +08:00
debugPrint ( " update job ${ id } with ${ evt } " ) ;
2022-07-09 19:14:40 +08:00
}
}
2022-03-12 21:42:05 +08:00
notifyListeners ( ) ;
2022-03-11 01:28:13 +08:00
} catch ( e ) {
debugPrint ( " Failed to tryUpdateJobProgress,evt: ${ evt . toString ( ) } " ) ;
}
}
2022-03-16 15:33:00 +08:00
receiveFileDir ( Map < String , dynamic > evt ) {
2022-07-11 10:30:45 +08:00
debugPrint ( " recv file dir: ${ evt } " ) ;
if ( evt [ ' is_local ' ] = = " false " ) {
2022-04-07 16:20:32 +08:00
// init remote home, the connection will automatic read remote home when established,
try {
final fd = FileDirectory . fromJson ( jsonDecode ( evt [ ' value ' ] ) ) ;
fd . format ( _remoteOption . isWindows , sort: _sortStyle ) ;
2022-07-11 16:07:49 +08:00
if ( fd . id > 0 ) {
2022-07-11 10:30:45 +08:00
final jobIndex = getJob ( fd . id ) ;
2022-07-11 16:07:49 +08:00
if ( jobIndex ! = - 1 ) {
2022-07-11 10:30:45 +08:00
final job = jobTable [ jobIndex ] ;
var totalSize = 0 ;
var fileCount = fd . entries . length ;
2022-07-11 16:07:49 +08:00
fd . entries . forEach ( ( element ) {
totalSize + = element . size ;
} ) ;
2022-07-11 10:30:45 +08:00
job . totalSize = totalSize ;
job . fileCount = fileCount ;
debugPrint ( " update receive details: ${ fd . path } " ) ;
}
} else if ( _remoteOption . home . isEmpty ) {
_remoteOption . home = fd . path ;
debugPrint ( " init remote home: ${ fd . path } " ) ;
_currentRemoteDir = fd ;
}
2022-08-03 22:03:31 +08:00
} finally { }
2022-04-07 16:20:32 +08:00
}
2022-03-16 15:33:00 +08:00
_fileFetcher . tryCompleteTask ( evt [ ' value ' ] , evt [ ' is_local ' ] ) ;
2022-07-11 16:07:49 +08:00
notifyListeners ( ) ;
2022-03-16 15:33:00 +08:00
}
2022-07-12 11:51:58 +08:00
jobDone ( Map < String , dynamic > evt ) async {
if ( _jobResultListener . isListening ) {
_jobResultListener . complete ( evt ) ;
return ;
}
2022-07-11 10:30:45 +08:00
if ( ! isDesktop ) {
_selectMode = false ;
_jobProgress . state = JobState . done ;
} else {
int id = int . parse ( evt [ ' id ' ] ) ;
final jobIndex = getJob ( id ) ;
if ( jobIndex ! = - 1 ) {
final job = jobTable [ jobIndex ] ;
job . finishedSize = job . totalSize ;
job . state = JobState . done ;
job . fileNum = int . parse ( evt [ ' file_num ' ] ) ;
}
2022-03-16 15:33:00 +08:00
}
2022-07-12 11:51:58 +08:00
await Future . wait ( [
refresh ( isLocal: false ) ,
refresh ( isLocal: true ) ,
] ) ;
2022-03-11 01:28:13 +08:00
}
jobError ( Map < String , dynamic > evt ) {
2022-07-11 10:30:45 +08:00
if ( ! isDesktop ) {
if ( _jobResultListener . isListening ) {
_jobResultListener . complete ( evt ) ;
return ;
}
_selectMode = false ;
_jobProgress . clear ( ) ;
_jobProgress . state = JobState . error ;
} else {
int jobIndex = getJob ( int . parse ( evt [ ' id ' ] ) ) ;
if ( jobIndex ! = - 1 ) {
final job = jobTable [ jobIndex ] ;
job . state = JobState . error ;
}
2022-03-16 15:33:00 +08:00
}
2022-03-17 21:03:52 +08:00
debugPrint ( " jobError $ evt " ) ;
2022-03-11 01:28:13 +08:00
notifyListeners ( ) ;
}
2022-05-18 15:47:07 +08:00
overrideFileConfirm ( Map < String , dynamic > evt ) async {
2022-05-17 20:56:36 +08:00
final resp = await showFileConfirmDialog (
translate ( " Overwrite " ) , " ${ evt [ ' read_path ' ] } " , true ) ;
2022-07-11 10:30:45 +08:00
final id = int . tryParse ( evt [ ' id ' ] ) ? ? 0 ;
2022-05-17 20:56:36 +08:00
if ( false = = resp ) {
2022-07-11 10:30:45 +08:00
final jobIndex = getJob ( id ) ;
2022-08-03 22:03:31 +08:00
if ( jobIndex ! = - 1 ) {
2022-07-11 10:30:45 +08:00
cancelJob ( id ) ;
final job = jobTable [ jobIndex ] ;
job . state = JobState . done ;
}
2022-05-17 20:56:36 +08:00
} else {
2022-07-01 11:26:32 +08:00
var need_override = false ;
2022-05-17 20:56:36 +08:00
if ( resp = = null ) {
// skip
2022-07-01 11:26:32 +08:00
need_override = false ;
2022-05-17 20:56:36 +08:00
} else {
// overwrite
2022-07-01 11:26:32 +08:00
need_override = true ;
2022-05-17 20:56:36 +08:00
}
2022-08-03 22:03:31 +08:00
bind . sessionSetConfirmOverrideFile (
id: _ffi . target ? . id ? ? " " ,
actId: id ,
fileNum: int . parse ( evt [ ' file_num ' ] ) ,
needOverride: need_override ,
remember: fileConfirmCheckboxRemember ,
2022-07-11 10:30:45 +08:00
isUpload: evt [ ' is_upload ' ] = = " true " ) ;
2022-05-17 20:56:36 +08:00
}
}
2022-03-12 21:42:05 +08:00
jobReset ( ) {
_jobProgress . clear ( ) ;
notifyListeners ( ) ;
}
2022-04-07 16:20:32 +08:00
onReady ( ) async {
2022-06-13 21:07:26 +08:00
_localOption . home = _ffi . target ? . getByName ( " get_home_dir " ) ? ? " " ;
2022-08-03 22:03:31 +08:00
_localOption . showHidden = ( await bind . sessionGetPeerOption (
id: _ffi . target ? . id ? ? " " , name: " local_show_hidden " ) )
? . isNotEmpty ? ?
false ;
_remoteOption . showHidden = ( await bind . sessionGetPeerOption (
id: _ffi . target ? . id ? ? " " , name: " remote_show_hidden " ) )
? . isNotEmpty ? ?
false ;
2022-06-13 21:07:26 +08:00
_remoteOption . isWindows = _ffi . target ? . ffiModel . pi . platform = = " Windows " ;
2022-03-17 21:03:52 +08:00
2022-06-13 21:07:26 +08:00
debugPrint ( " remote platform: ${ _ffi . target ? . ffiModel . pi . platform } " ) ;
2022-03-17 21:03:52 +08:00
2022-04-07 16:20:32 +08:00
await Future . delayed ( Duration ( milliseconds: 100 ) ) ;
2022-08-03 22:03:31 +08:00
final local = ( await bind . sessionGetPeerOption (
id: _ffi . target ? . id ? ? " " , name: " local_dir " ) ) ? ?
" " ;
final remote = ( await bind . sessionGetPeerOption (
id: _ffi . target ? . id ? ? " " , name: " remote_dir " ) ) ? ?
" " ;
2022-03-17 21:03:52 +08:00
openDirectory ( local . isEmpty ? _localOption . home : local , isLocal: true ) ;
openDirectory ( remote . isEmpty ? _remoteOption . home : remote , isLocal: false ) ;
2022-04-07 16:20:32 +08:00
await Future . delayed ( Duration ( seconds: 1 ) ) ;
if ( _currentLocalDir . path . isEmpty ) {
openDirectory ( _localOption . home , isLocal: true ) ;
}
if ( _currentRemoteDir . path . isEmpty ) {
openDirectory ( _remoteOption . home , isLocal: false ) ;
}
2022-07-11 18:23:58 +08:00
// load last transfer jobs
2022-08-03 22:03:31 +08:00
await bind . sessionLoadLastTransferJobs ( id: ' ${ _ffi . target ? . id } ' ) ;
2022-03-17 21:03:52 +08:00
}
onClose ( ) {
2022-04-19 13:07:45 +08:00
SmartDialog . dismiss ( ) ;
2022-03-17 21:03:52 +08:00
// save config
2022-07-01 11:26:32 +08:00
Map < String , String > msgMap = Map ( ) ;
msgMap [ " local_dir " ] = _currentLocalDir . path ;
msgMap [ " local_show_hidden " ] = _localOption . showHidden ? " Y " : " " ;
msgMap [ " remote_dir " ] = _currentRemoteDir . path ;
msgMap [ " remote_show_hidden " ] = _remoteOption . showHidden ? " Y " : " " ;
final id = _ffi . target ? . id ? ? " " ;
2022-08-03 22:03:31 +08:00
for ( final msg in msgMap . entries ) {
bind . sessionPeerOption ( id: id , name: msg . key , value: msg . value ) ;
2022-07-01 11:26:32 +08:00
}
2022-03-17 21:03:52 +08:00
_currentLocalDir . clear ( ) ;
_currentRemoteDir . clear ( ) ;
2022-04-07 16:20:32 +08:00
_localOption . clear ( ) ;
_remoteOption . clear ( ) ;
2022-03-07 22:54:34 +08:00
}
2022-07-12 11:51:58 +08:00
Future refresh ( { bool ? isLocal } ) async {
2022-06-21 18:14:44 +08:00
if ( isDesktop ) {
2022-07-11 16:07:49 +08:00
isLocal = isLocal ? ? _isLocal ;
2022-08-03 22:03:31 +08:00
await isLocal
? openDirectory ( currentLocalDir . path , isLocal: isLocal )
: openDirectory ( currentRemoteDir . path , isLocal: isLocal ) ;
2022-06-21 18:14:44 +08:00
} else {
2022-07-12 11:51:58 +08:00
await openDirectory ( currentDir . path ) ;
2022-06-21 18:14:44 +08:00
}
2022-03-07 22:54:34 +08:00
}
2022-03-09 17:07:24 +08:00
2022-03-16 15:33:00 +08:00
openDirectory ( String path , { bool ? isLocal } ) async {
isLocal = isLocal ? ? _isLocal ;
2022-03-17 21:03:52 +08:00
final showHidden =
isLocal ? _localOption . showHidden : _remoteOption . showHidden ;
final isWindows =
isLocal ? _localOption . isWindows : _remoteOption . isWindows ;
2022-07-09 11:27:59 +08:00
// process /C:\ -> C:\ on Windows
2022-08-03 22:03:31 +08:00
if ( isLocal
? _localOption . isWindows
: _remoteOption . isWindows & & path . length > 1 & & path [ 0 ] = = ' / ' ) {
2022-07-09 11:27:59 +08:00
path = path . substring ( 1 ) ;
if ( path [ path . length - 1 ] ! = ' \\ ' ) {
path = path + " \\ " ;
}
}
2022-03-16 15:33:00 +08:00
try {
2022-03-17 21:03:52 +08:00
final fd = await _fileFetcher . fetchDirectory ( path , isLocal , showHidden ) ;
fd . format ( isWindows , sort: _sortStyle ) ;
2022-03-16 15:33:00 +08:00
if ( isLocal ) {
_currentLocalDir = fd ;
} else {
_currentRemoteDir = fd ;
}
notifyListeners ( ) ;
} catch ( e ) {
2022-07-09 19:14:40 +08:00
debugPrint ( " Failed to openDirectory ${ path } : $ e " ) ;
2022-03-09 17:07:24 +08:00
}
}
2022-03-07 22:54:34 +08:00
2022-07-09 19:14:40 +08:00
goHome ( { bool ? isLocal } ) {
2022-07-11 16:07:49 +08:00
isLocal = isLocal ? ? _isLocal ;
openDirectory ( getCurrentHome ( isLocal ) , isLocal: isLocal ) ;
2022-03-17 21:03:52 +08:00
}
2022-06-27 16:44:34 +08:00
goToParentDirectory ( { bool ? isLocal } ) {
2022-07-09 13:04:22 +08:00
isLocal = isLocal ? ? _isLocal ;
2022-08-03 22:03:31 +08:00
final isWindows =
isLocal ? _localOption . isWindows : _remoteOption . isWindows ;
2022-07-09 13:04:22 +08:00
final currDir = isLocal ? currentLocalDir : currentRemoteDir ;
var parent = PathUtil . dirname ( currDir . path , isWindows ) ;
2022-07-09 11:27:59 +08:00
// specially for C:\, D:\, goto '/'
2022-07-09 13:04:22 +08:00
if ( parent = = currDir . path & & isWindows ) {
2022-07-09 11:27:59 +08:00
openDirectory ( ' / ' , isLocal: isLocal ) ;
return ;
}
2022-06-27 16:44:34 +08:00
openDirectory ( parent , isLocal: isLocal ) ;
2022-03-07 22:54:34 +08:00
}
2022-07-01 12:08:52 +08:00
/// isRemote only for desktop now, [isRemote == true] means [remote -> local]
sendFiles ( SelectedItems items , { bool isRemote = false } ) {
if ( isDesktop ) {
// desktop sendFiles
2022-08-03 22:03:31 +08:00
final toPath = isRemote ? currentLocalDir . path : currentRemoteDir . path ;
2022-07-01 12:08:52 +08:00
final isWindows =
2022-08-03 22:03:31 +08:00
isRemote ? _localOption . isWindows : _remoteOption . isWindows ;
2022-07-01 12:08:52 +08:00
final showHidden =
2022-08-03 22:03:31 +08:00
isRemote ? _localOption . showHidden : _remoteOption . showHidden ;
2022-07-01 12:08:52 +08:00
items . items . forEach ( ( from ) async {
2022-07-09 19:14:40 +08:00
final jobId = + + _jobId ;
2022-07-11 10:30:45 +08:00
_jobTable . add ( JobProgress ( )
. . jobName = from . path
. . totalSize = from . size
2022-07-09 19:14:40 +08:00
. . state = JobState . inProgress
2022-07-11 10:30:45 +08:00
. . id = jobId
2022-08-03 22:03:31 +08:00
. . isRemote = isRemote ) ;
bind . sessionSendFiles (
id: ' ${ _ffi . target ? . id } ' ,
actId: _jobId ,
path: from . path ,
to: PathUtil . join ( toPath , from . name , isWindows ) ,
fileNum: 0 ,
includeHidden: showHidden ,
isRemote: isRemote ) ;
print (
" path: ${ from . path } , toPath: ${ toPath } , to: ${ PathUtil . join ( toPath , from . name , isWindows ) } " ) ;
2022-07-01 12:08:52 +08:00
} ) ;
} else {
if ( items . isLocal = = null ) {
debugPrint ( " Failed to sendFiles ,wrong path state " ) ;
return ;
}
_jobProgress . state = JobState . inProgress ;
final toPath =
2022-08-03 22:03:31 +08:00
items . isLocal ! ? currentRemoteDir . path : currentLocalDir . path ;
2022-07-01 12:08:52 +08:00
final isWindows =
2022-08-03 22:03:31 +08:00
items . isLocal ! ? _localOption . isWindows : _remoteOption . isWindows ;
2022-07-01 12:08:52 +08:00
final showHidden =
2022-08-03 22:03:31 +08:00
items . isLocal ! ? _localOption . showHidden : _remoteOption . showHidden ;
2022-07-01 12:08:52 +08:00
items . items . forEach ( ( from ) async {
_jobId + + ;
2022-08-03 22:03:31 +08:00
await bind . sessionSendFiles (
id: ' ${ _ffi . target ? . getId ( ) } ' ,
actId: _jobId ,
path: from . path ,
to: PathUtil . join ( toPath , from . name , isWindows ) ,
fileNum: 0 ,
includeHidden: showHidden ,
isRemote: ! ( items . isLocal ! ) ) ;
2022-07-01 12:08:52 +08:00
} ) ;
2022-03-12 21:42:05 +08:00
}
}
2022-03-16 15:33:00 +08:00
bool removeCheckboxRemember = false ;
2022-07-12 11:51:58 +08:00
removeAction ( SelectedItems items , { bool ? isLocal } ) async {
isLocal = isLocal ? ? _isLocal ;
2022-03-16 15:33:00 +08:00
removeCheckboxRemember = false ;
2022-03-12 21:42:05 +08:00
if ( items . isLocal = = null ) {
2022-03-24 15:29:12 +08:00
debugPrint ( " Failed to removeFile, wrong path state " ) ;
2022-03-12 21:42:05 +08:00
return ;
}
2022-03-17 21:03:52 +08:00
final isWindows =
items . isLocal ! ? _localOption . isWindows : _remoteOption . isWindows ;
2022-03-16 15:33:00 +08:00
await Future . forEach ( items . items , ( Entry item ) async {
2022-03-12 21:42:05 +08:00
_jobId + + ;
2022-03-16 15:33:00 +08:00
var title = " " ;
var content = " " ;
late final List < Entry > entries ;
if ( item . isFile ) {
2022-03-23 15:28:21 +08:00
title = translate ( " Are you sure you want to delete this file? " ) ;
2022-03-16 15:33:00 +08:00
content = " ${ item . name } " ;
entries = [ item ] ;
} else if ( item . isDirectory ) {
2022-03-24 15:29:12 +08:00
title = translate ( " Not an empty directory " ) ;
2022-03-23 15:28:21 +08:00
showLoading ( translate ( " Waiting " ) ) ;
2022-03-16 15:33:00 +08:00
final fd = await _fileFetcher . fetchDirectoryRecursive (
2022-03-17 21:03:52 +08:00
_jobId , item . path , items . isLocal ! , true ) ;
2022-04-07 23:45:19 +08:00
if ( fd . path . isEmpty ) {
fd . path = item . path ;
}
2022-03-17 21:03:52 +08:00
fd . format ( isWindows ) ;
2022-04-19 13:07:45 +08:00
SmartDialog . dismiss ( ) ;
2022-03-17 21:03:52 +08:00
if ( fd . entries . isEmpty ) {
2022-04-07 16:20:32 +08:00
final confirm = await showRemoveDialog (
translate (
" Are you sure you want to delete this empty directory? " ) ,
item . name ,
false ) ;
2022-03-17 21:03:52 +08:00
if ( confirm = = true ) {
2022-03-16 15:33:00 +08:00
sendRemoveEmptyDir ( item . path , 0 , items . isLocal ! ) ;
}
return ;
}
entries = fd . entries ;
} else {
entries = [ ] ;
}
for ( var i = 0 ; i < entries . length ; i + + ) {
2022-04-07 16:20:32 +08:00
final dirShow = item . isDirectory
? " ${ translate ( " Are you sure you want to delete the file of this directory? " ) } \n "
: " " ;
final count = entries . length > 1 ? " ${ i + 1 } / ${ entries . length } " : " " ;
2022-03-16 15:33:00 +08:00
content = dirShow + " $ count \n ${ entries [ i ] . path } " ;
2022-03-17 21:03:52 +08:00
final confirm =
await showRemoveDialog ( title , content , item . isDirectory ) ;
2022-03-16 15:33:00 +08:00
try {
if ( confirm = = true ) {
sendRemoveFile ( entries [ i ] . path , i , items . isLocal ! ) ;
final res = await _jobResultListener . start ( ) ;
// handle remove res;
if ( item . isDirectory & &
res [ ' file_num ' ] = = ( entries . length - 1 ) . toString ( ) ) {
sendRemoveEmptyDir ( item . path , i , items . isLocal ! ) ;
}
}
if ( removeCheckboxRemember ) {
if ( confirm = = true ) {
for ( var j = i + 1 ; j < entries . length ; j + + ) {
sendRemoveFile ( entries [ j ] . path , j , items . isLocal ! ) ;
final res = await _jobResultListener . start ( ) ;
if ( item . isDirectory & &
res [ ' file_num ' ] = = ( entries . length - 1 ) . toString ( ) ) {
sendRemoveEmptyDir ( item . path , i , items . isLocal ! ) ;
}
}
}
break ;
}
2022-07-12 11:51:58 +08:00
} catch ( e ) {
print ( " remove error: ${ e } " ) ;
}
2022-03-12 21:42:05 +08:00
}
} ) ;
2022-03-29 23:10:43 +08:00
_selectMode = false ;
2022-07-12 11:51:58 +08:00
refresh ( isLocal: isLocal ) ;
2022-03-16 15:33:00 +08:00
}
2022-03-17 21:03:52 +08:00
Future < bool ? > showRemoveDialog (
String title , String content , bool showCheckbox ) async {
2022-04-19 13:07:45 +08:00
return await DialogManager . show < bool > (
( setState , Function ( bool v ) close ) = > CustomAlertDialog (
title: Row (
children: [
Icon ( Icons . warning , color: Colors . red ) ,
SizedBox ( width: 20 ) ,
Text ( title )
] ,
) ,
content: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
Text ( content ) ,
SizedBox ( height: 5 ) ,
Text ( translate ( " This is irreversible! " ) ,
style: TextStyle ( fontWeight: FontWeight . bold ) ) ,
showCheckbox
? CheckboxListTile (
contentPadding: const EdgeInsets . all ( 0 ) ,
dense: true ,
controlAffinity: ListTileControlAffinity . leading ,
title: Text (
translate ( " Do this for all conflicts " ) ,
) ,
value: removeCheckboxRemember ,
onChanged: ( v ) {
if ( v = = null ) return ;
setState ( ( ) = > removeCheckboxRemember = v ) ;
} ,
)
: SizedBox . shrink ( )
] ) ,
actions: [
TextButton (
style: flatButtonStyle ,
onPressed: ( ) = > close ( false ) ,
child: Text ( translate ( " Cancel " ) ) ) ,
TextButton (
style: flatButtonStyle ,
onPressed: ( ) = > close ( true ) ,
child: Text ( translate ( " OK " ) ) ) ,
2022-03-16 15:33:00 +08:00
] ) ,
2022-04-19 13:07:45 +08:00
useAnimation: false ) ;
2022-03-12 21:42:05 +08:00
}
2022-05-17 20:56:36 +08:00
bool fileConfirmCheckboxRemember = false ;
Future < bool ? > showFileConfirmDialog (
String title , String content , bool showCheckbox ) async {
2022-05-18 15:47:07 +08:00
fileConfirmCheckboxRemember = false ;
2022-05-17 20:56:36 +08:00
return await DialogManager . show < bool ? > (
2022-05-18 15:47:07 +08:00
( setState , Function ( bool ? v ) close ) = > CustomAlertDialog (
title: Row (
children: [
Icon ( Icons . warning , color: Colors . red ) ,
SizedBox ( width: 20 ) ,
Text ( title )
] ,
) ,
content: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
mainAxisSize: MainAxisSize . min ,
children: [
Text (
translate (
" This file exists, skip or overwrite this file? " ) ,
style: TextStyle ( fontWeight: FontWeight . bold ) ) ,
SizedBox ( height: 5 ) ,
Text ( content ) ,
showCheckbox
? CheckboxListTile (
contentPadding: const EdgeInsets . all ( 0 ) ,
dense: true ,
controlAffinity: ListTileControlAffinity . leading ,
title: Text (
translate ( " Do this for all conflicts " ) ,
) ,
value: fileConfirmCheckboxRemember ,
onChanged: ( v ) {
if ( v = = null ) return ;
setState ( ( ) = > fileConfirmCheckboxRemember = v ) ;
} ,
)
: SizedBox . shrink ( )
] ) ,
actions: [
TextButton (
style: flatButtonStyle ,
onPressed: ( ) = > close ( false ) ,
child: Text ( translate ( " Cancel " ) ) ) ,
TextButton (
style: flatButtonStyle ,
onPressed: ( ) = > close ( null ) ,
child: Text ( translate ( " Skip " ) ) ) ,
TextButton (
style: flatButtonStyle ,
onPressed: ( ) = > close ( true ) ,
child: Text ( translate ( " OK " ) ) ) ,
2022-05-17 20:56:36 +08:00
] ) ,
useAnimation: false ) ;
}
2022-03-16 15:33:00 +08:00
sendRemoveFile ( String path , int fileNum , bool isLocal ) {
2022-08-03 22:03:31 +08:00
bind . sessionRemoveFile (
id: ' ${ _ffi . target ? . id } ' ,
actId: _jobId ,
path: path ,
isRemote: ! isLocal ,
fileNum: fileNum ) ;
2022-03-16 15:33:00 +08:00
}
sendRemoveEmptyDir ( String path , int fileNum , bool isLocal ) {
2022-08-03 22:03:31 +08:00
bind . sessionRemoveAllEmptyDirs (
id: ' ${ _ffi . target ? . id } ' ,
actId: _jobId ,
path: path ,
isRemote: ! isLocal ) ;
2022-03-16 15:33:00 +08:00
}
2022-07-11 16:07:49 +08:00
createDir ( String path , { bool ? isLocal } ) async {
isLocal = isLocal ? ? this . isLocal ;
2022-03-17 21:03:52 +08:00
_jobId + + ;
2022-08-03 22:03:31 +08:00
bind . sessionCreateDir (
id: ' ${ _ffi . target ? . id } ' ,
actId: _jobId ,
path: path ,
isRemote: ! isLocal ) ;
2022-03-16 15:33:00 +08:00
}
2022-03-07 22:54:34 +08:00
2022-06-27 16:44:34 +08:00
cancelJob ( int id ) async {
2022-08-03 22:03:31 +08:00
bind . sessionCancelJob ( id: ' ${ _ffi . target ? . id } ' , actId: id ) ;
2022-04-07 22:58:47 +08:00
jobReset ( ) ;
2022-03-29 23:10:43 +08:00
}
2022-03-17 21:03:52 +08:00
2022-07-11 16:07:49 +08:00
changeSortStyle ( SortBy sort , { bool ? isLocal , bool ascending = true } ) {
2022-03-09 22:43:05 +08:00
_sortStyle = sort ;
2022-06-27 16:44:34 +08:00
if ( isLocal = = null ) {
// compatible for mobile logic
2022-07-11 16:07:49 +08:00
_currentLocalDir . changeSortStyle ( sort , ascending: ascending ) ;
_currentRemoteDir . changeSortStyle ( sort , ascending: ascending ) ;
2022-08-03 22:03:31 +08:00
_localSortStyle = sort ;
_localSortAscending = ascending ;
_remoteSortStyle = sort ;
_remoteSortAscending = ascending ;
2022-06-27 16:44:34 +08:00
} else if ( isLocal ) {
2022-07-11 16:07:49 +08:00
_currentLocalDir . changeSortStyle ( sort , ascending: ascending ) ;
2022-08-03 22:03:31 +08:00
_localSortStyle = sort ;
_localSortAscending = ascending ;
2022-06-27 16:44:34 +08:00
} else {
2022-07-11 16:07:49 +08:00
_currentRemoteDir . changeSortStyle ( sort , ascending: ascending ) ;
2022-08-03 22:03:31 +08:00
_remoteSortStyle = sort ;
_remoteSortAscending = ascending ;
2022-06-27 16:44:34 +08:00
}
2022-03-09 22:43:05 +08:00
notifyListeners ( ) ;
2022-03-07 22:54:34 +08:00
}
2022-06-21 17:58:27 +08:00
initFileFetcher ( ) {
_fileFetcher . id = _ffi . target ? . id ;
}
2022-07-11 10:30:45 +08:00
void updateFolderFiles ( Map < String , dynamic > evt ) {
// ret: "{\"id\":1,\"num_entries\":12,\"total_size\":1264822.0}"
2022-08-03 22:03:31 +08:00
Map < String , dynamic > info = json . decode ( evt [ ' info ' ] ) ;
2022-07-11 10:30:45 +08:00
int id = info [ ' id ' ] ;
int num_entries = info [ ' num_entries ' ] ;
double total_size = info [ ' total_size ' ] ;
final jobIndex = getJob ( id ) ;
if ( jobIndex ! = - 1 ) {
final job = jobTable [ jobIndex ] ;
job . fileCount = num_entries ;
job . totalSize = total_size . toInt ( ) ;
}
debugPrint ( " update folder files: ${ info } " ) ;
}
2022-07-11 16:07:49 +08:00
bool get remoteSortAscending = > _remoteSortAscending ;
2022-07-11 18:23:58 +08:00
void loadLastJob ( Map < String , dynamic > evt ) {
debugPrint ( " load last job: ${ evt } " ) ;
2022-08-03 22:03:31 +08:00
Map < String , dynamic > jobDetail = json . decode ( evt [ ' value ' ] ) ;
2022-07-11 18:23:58 +08:00
// int id = int.parse(jobDetail['id']);
String remote = jobDetail [ ' remote ' ] ;
String to = jobDetail [ ' to ' ] ;
bool showHidden = jobDetail [ ' show_hidden ' ] ;
int fileNum = jobDetail [ ' file_num ' ] ;
bool isRemote = jobDetail [ ' is_remote ' ] ;
final currJobId = _jobId + + ;
var jobProgress = JobProgress ( )
. . jobName = isRemote ? remote : to
. . id = currJobId
. . isRemote = isRemote
. . fileNum = fileNum
. . remote = remote
. . to = to
. . showHidden = showHidden
. . state = JobState . paused ;
jobTable . add ( jobProgress ) ;
2022-08-03 22:03:31 +08:00
bind . sessionAddJob (
id: ' ${ _ffi . target ? . id } ' ,
isRemote: isRemote ,
includeHidden: showHidden ,
actId: currJobId ,
path: isRemote ? remote : to ,
to: isRemote ? to : remote ,
fileNum: fileNum ,
2022-07-11 18:23:58 +08:00
) ;
}
resumeJob ( int jobId ) {
final jobIndex = getJob ( jobId ) ;
if ( jobIndex ! = - 1 ) {
final job = jobTable [ jobIndex ] ;
2022-08-03 22:03:31 +08:00
bind . sessionResumeJob (
id: ' ${ _ffi . target ? . id } ' , actId: job . id , isRemote: job . isRemote ) ;
2022-07-11 18:23:58 +08:00
job . state = JobState . inProgress ;
} else {
debugPrint ( " jobId ${ jobId } is not exists " ) ;
}
notifyListeners ( ) ;
}
2022-03-09 17:07:24 +08:00
}
2022-03-16 15:33:00 +08:00
class JobResultListener < T > {
Completer < T > ? _completer ;
Timer ? _timer ;
int _timeoutSecond = 5 ;
bool get isListening = > _completer ! = null ;
clear ( ) {
if ( _completer ! = null ) {
_timer ? . cancel ( ) ;
_timer = null ;
_completer ! . completeError ( " Cancel manually " ) ;
_completer = null ;
return ;
}
}
Future < T > start ( ) {
if ( _completer ! = null ) return Future . error ( " Already start listen " ) ;
_completer = Completer ( ) ;
_timer = Timer ( Duration ( seconds: _timeoutSecond ) , ( ) {
if ( ! _completer ! . isCompleted ) {
_completer ! . completeError ( " Time out " ) ;
}
_completer = null ;
} ) ;
return _completer ! . future ;
}
complete ( T res ) {
if ( _completer ! = null ) {
_timer ? . cancel ( ) ;
_timer = null ;
_completer ! . complete ( res ) ;
_completer = null ;
return ;
}
}
}
class FileFetcher {
// Map<String,Completer<FileDirectory>> localTasks = Map(); // now we only use read local dir sync
Map < String , Completer < FileDirectory > > remoteTasks = Map ( ) ;
Map < int , Completer < FileDirectory > > readRecursiveTasks = Map ( ) ;
2022-06-21 17:58:27 +08:00
String ? _id ;
String ? get id = > _id ;
set id ( String ? id ) {
_id = id ;
}
// if id == null, means to fetch global FFI
2022-07-01 11:26:32 +08:00
FFI get _ffi = > ffi ( _id ? ? " " ) ;
2022-06-21 17:58:27 +08:00
2022-03-16 15:33:00 +08:00
Future < FileDirectory > registerReadTask ( bool isLocal , String path ) {
// final jobs = isLocal?localJobs:remoteJobs; // maybe we will use read local dir async later
final tasks = remoteTasks ; // bypass now
if ( tasks . containsKey ( path ) ) {
throw " Failed to registerReadTask, already have same read job " ;
}
final c = Completer < FileDirectory > ( ) ;
tasks [ path ] = c ;
Timer ( Duration ( seconds: 2 ) , ( ) {
tasks . remove ( path ) ;
2022-04-04 01:21:44 +08:00
if ( c . isCompleted ) return ;
2022-03-16 15:33:00 +08:00
c . completeError ( " Failed to read dir,timeout " ) ;
} ) ;
return c . future ;
}
Future < FileDirectory > registerReadRecursiveTask ( int id ) {
final tasks = readRecursiveTasks ;
if ( tasks . containsKey ( id ) ) {
throw " Failed to registerRemoveTask, already have same ReadRecursive job " ;
}
final c = Completer < FileDirectory > ( ) ;
tasks [ id ] = c ;
Timer ( Duration ( seconds: 2 ) , ( ) {
tasks . remove ( id ) ;
2022-04-04 01:21:44 +08:00
if ( c . isCompleted ) return ;
2022-03-16 15:33:00 +08:00
c . completeError ( " Failed to read dir,timeout " ) ;
} ) ;
return c . future ;
}
tryCompleteTask ( String ? msg , String ? isLocalStr ) {
if ( msg = = null | | isLocalStr = = null ) return ;
late final tasks ;
try {
final fd = FileDirectory . fromJson ( jsonDecode ( msg ) ) ;
if ( fd . id > 0 ) {
// fd.id > 0 is result for read recursive
2022-04-19 13:07:45 +08:00
// to-do later,will be better if every fetch use ID,so that there will only one task map for read and recursive read
2022-03-16 15:33:00 +08:00
tasks = readRecursiveTasks ;
final completer = tasks . remove ( fd . id ) ;
completer ? . complete ( fd ) ;
} else if ( fd . path . isNotEmpty ) {
// result for normal read dir
// final jobs = isLocal?localJobs:remoteJobs; // maybe we will use read local dir async later
tasks = remoteTasks ; // bypass now
final completer = tasks . remove ( fd . path ) ;
completer ? . complete ( fd ) ;
}
} catch ( e ) {
debugPrint ( " tryCompleteJob err : $ e " ) ;
}
}
2022-03-17 21:03:52 +08:00
Future < FileDirectory > fetchDirectory (
String path , bool isLocal , bool showHidden ) async {
2022-03-16 15:33:00 +08:00
try {
if ( isLocal ) {
2022-08-03 22:03:31 +08:00
final res = await bind . sessionReadLocalDirSync (
2022-06-21 17:58:27 +08:00
id: id ? ? " " , path: path , showHidden: showHidden ) ;
2022-03-16 15:33:00 +08:00
final fd = FileDirectory . fromJson ( jsonDecode ( res ) ) ;
return fd ;
} else {
2022-08-03 22:03:31 +08:00
await bind . sessionReadRemoteDir (
2022-06-21 17:58:27 +08:00
id: id ? ? " " , path: path , includeHidden: showHidden ) ;
2022-03-16 15:33:00 +08:00
return registerReadTask ( isLocal , path ) ;
}
} catch ( e ) {
return Future . error ( e ) ;
}
}
Future < FileDirectory > fetchDirectoryRecursive (
2022-03-17 21:03:52 +08:00
int id , String path , bool isLocal , bool showHidden ) async {
// TODO test Recursive is show hidden default?
2022-03-16 15:33:00 +08:00
try {
2022-08-03 22:03:31 +08:00
await bind . sessionReadDirRecursive (
id: _ffi . id ,
actId: id ,
path: path ,
isRemote: ! isLocal ,
showHidden: showHidden ) ;
2022-03-16 15:33:00 +08:00
return registerReadRecursiveTask ( id ) ;
} catch ( e ) {
return Future . error ( e ) ;
}
}
}
2022-03-11 01:28:13 +08:00
class FileDirectory {
List < Entry > entries = [ ] ;
int id = 0 ;
String path = " " ;
FileDirectory ( ) ;
2022-03-17 21:03:52 +08:00
FileDirectory . fromJson ( Map < String , dynamic > json ) {
2022-03-11 01:28:13 +08:00
id = json [ ' id ' ] ;
path = json [ ' path ' ] ;
2022-03-17 21:03:52 +08:00
json [ ' entries ' ] . forEach ( ( v ) {
entries . add ( new Entry . fromJson ( v ) ) ;
} ) ;
2022-03-11 01:28:13 +08:00
}
2022-03-17 21:03:52 +08:00
// generate full path for every entry , init sort style if need.
format ( bool isWindows , { SortBy ? sort } ) {
entries . forEach ( ( entry ) {
entry . path = PathUtil . join ( path , entry . name , isWindows ) ;
} ) ;
if ( sort ! = null ) {
changeSortStyle ( sort ) ;
2022-03-16 15:33:00 +08:00
}
}
2022-07-11 16:07:49 +08:00
changeSortStyle ( SortBy sort , { bool ascending = true } ) {
entries = _sortList ( entries , sort , ascending ) ;
2022-03-11 01:28:13 +08:00
}
clear ( ) {
entries = [ ] ;
id = 0 ;
path = " " ;
}
}
class Entry {
int entryType = 4 ;
int modifiedTime = 0 ;
String name = " " ;
2022-03-12 21:42:05 +08:00
String path = " " ;
2022-03-11 01:28:13 +08:00
int size = 0 ;
Entry ( ) ;
2022-03-17 21:03:52 +08:00
Entry . fromJson ( Map < String , dynamic > json ) {
2022-03-11 01:28:13 +08:00
entryType = json [ ' entry_type ' ] ;
modifiedTime = json [ ' modified_time ' ] ;
name = json [ ' name ' ] ;
size = json [ ' size ' ] ;
}
bool get isFile = > entryType > 3 ;
bool get isDirectory = > entryType < = 3 ;
DateTime lastModified ( ) {
return DateTime . fromMillisecondsSinceEpoch ( modifiedTime * 1000 ) ;
}
}
2022-07-11 18:23:58 +08:00
enum JobState { none , inProgress , done , error , paused }
2022-03-11 01:28:13 +08:00
2022-07-11 10:30:45 +08:00
extension JobStateDisplay on JobState {
String display ( ) {
switch ( this ) {
case JobState . none:
return translate ( " Waiting " ) ;
case JobState . inProgress:
return translate ( " Transfer File " ) ;
case JobState . done:
return translate ( " Finished " ) ;
case JobState . error:
return translate ( " Error " ) ;
default :
return " " ;
}
}
}
2022-03-11 01:28:13 +08:00
class JobProgress {
JobState state = JobState . none ;
var id = 0 ;
var fileNum = 0 ;
2022-03-12 21:42:05 +08:00
var speed = 0.0 ;
2022-03-11 01:28:13 +08:00
var finishedSize = 0 ;
2022-07-11 10:30:45 +08:00
var totalSize = 0 ;
var fileCount = 0 ;
var isRemote = false ;
var jobName = " " ;
2022-07-11 18:23:58 +08:00
var remote = " " ;
var to = " " ;
var showHidden = false ;
2022-03-11 01:28:13 +08:00
clear ( ) {
state = JobState . none ;
id = 0 ;
fileNum = 0 ;
speed = 0 ;
finishedSize = 0 ;
2022-07-11 10:30:45 +08:00
jobName = " " ;
fileCount = 0 ;
2022-07-11 18:23:58 +08:00
remote = " " ;
to = " " ;
2022-03-11 01:28:13 +08:00
}
}
2022-03-09 17:07:24 +08:00
class _PathStat {
final String path ;
final DateTime dateTime ;
2022-03-09 22:43:05 +08:00
2022-03-09 17:07:24 +08:00
_PathStat ( this . path , this . dateTime ) ;
}
2022-03-17 21:03:52 +08:00
class PathUtil {
static final windowsContext = Path . Context ( style: Path . Style . windows ) ;
static final posixContext = Path . Context ( style: Path . Style . posix ) ;
static String join ( String path1 , String path2 , bool isWindows ) {
final pathUtil = isWindows ? windowsContext : posixContext ;
return pathUtil . join ( path1 , path2 ) ;
}
static List < String > split ( String path , bool isWindows ) {
final pathUtil = isWindows ? windowsContext : posixContext ;
return pathUtil . split ( path ) ;
}
2022-04-07 20:19:07 +08:00
2022-04-07 22:58:47 +08:00
static String dirname ( String path , bool isWindows ) {
2022-04-07 20:19:07 +08:00
final pathUtil = isWindows ? windowsContext : posixContext ;
return pathUtil . dirname ( path ) ;
}
2022-03-17 21:03:52 +08:00
}
class DirectoryOption {
String home ;
bool showHidden ;
bool isWindows ;
DirectoryOption (
{ this . home = " " , this . showHidden = false , this . isWindows = false } ) ;
2022-04-07 16:20:32 +08:00
clear ( ) {
home = " " ;
showHidden = false ;
isWindows = false ;
}
2022-03-17 21:03:52 +08:00
}
2022-03-09 17:07:24 +08:00
// code from file_manager pkg after edit
2022-07-11 16:07:49 +08:00
List < Entry > _sortList ( List < Entry > list , SortBy sortType , bool ascending ) {
2022-03-23 15:28:21 +08:00
if ( sortType = = SortBy . Name ) {
2022-03-09 17:07:24 +08:00
// making list of only folders.
2022-03-09 22:43:05 +08:00
final dirs = list . where ( ( element ) = > element . isDirectory ) . toList ( ) ;
2022-03-09 17:07:24 +08:00
// sorting folder list by name.
2022-03-09 22:43:05 +08:00
dirs . sort ( ( a , b ) = > a . name . toLowerCase ( ) . compareTo ( b . name . toLowerCase ( ) ) ) ;
2022-03-09 17:07:24 +08:00
// making list of only flies.
2022-03-09 22:43:05 +08:00
final files = list . where ( ( element ) = > element . isFile ) . toList ( ) ;
2022-03-09 17:07:24 +08:00
// sorting files list by name.
2022-03-09 22:43:05 +08:00
files . sort ( ( a , b ) = > a . name . toLowerCase ( ) . compareTo ( b . name . toLowerCase ( ) ) ) ;
2022-03-09 17:07:24 +08:00
// first folders will go to list (if available) then files will go to list.
2022-08-03 22:03:31 +08:00
return ascending
? [ . . . dirs , . . . files ]
: [ . . . dirs . reversed . toList ( ) , . . . files . reversed . toList ( ) ] ;
2022-03-23 15:28:21 +08:00
} else if ( sortType = = SortBy . Modified ) {
2022-03-09 17:07:24 +08:00
// making the list of Path & DateTime
List < _PathStat > _pathStat = [ ] ;
2022-03-09 22:43:05 +08:00
for ( Entry e in list ) {
_pathStat . add ( _PathStat ( e . name , e . lastModified ( ) ) ) ;
2022-03-09 17:07:24 +08:00
}
// sort _pathStat according to date
_pathStat . sort ( ( b , a ) = > a . dateTime . compareTo ( b . dateTime ) ) ;
2022-03-09 22:43:05 +08:00
// sorting [list] according to [_pathStat]
2022-03-09 17:07:24 +08:00
list . sort ( ( a , b ) = > _pathStat
2022-03-09 22:43:05 +08:00
. indexWhere ( ( element ) = > element . path = = a . name )
. compareTo ( _pathStat . indexWhere ( ( element ) = > element . path = = b . name ) ) ) ;
2022-07-11 16:07:49 +08:00
return ascending ? list : list . reversed . toList ( ) ;
2022-03-23 15:28:21 +08:00
} else if ( sortType = = SortBy . Type ) {
2022-03-09 17:07:24 +08:00
// making list of only folders.
2022-03-09 22:43:05 +08:00
final dirs = list . where ( ( element ) = > element . isDirectory ) . toList ( ) ;
2022-03-09 17:07:24 +08:00
// sorting folders by name.
2022-03-09 22:43:05 +08:00
dirs . sort ( ( a , b ) = > a . name . toLowerCase ( ) . compareTo ( b . name . toLowerCase ( ) ) ) ;
2022-03-09 17:07:24 +08:00
// making the list of files
2022-03-09 22:43:05 +08:00
final files = list . where ( ( element ) = > element . isFile ) . toList ( ) ;
2022-03-09 17:07:24 +08:00
// sorting files list by extension.
2022-03-09 22:43:05 +08:00
files . sort ( ( a , b ) = > a . name
2022-03-09 17:07:24 +08:00
. toLowerCase ( )
. split ( ' . ' )
. last
2022-03-09 22:43:05 +08:00
. compareTo ( b . name . toLowerCase ( ) . split ( ' . ' ) . last ) ) ;
2022-08-03 22:03:31 +08:00
return ascending
? [ . . . dirs , . . . files ]
: [ . . . dirs . reversed . toList ( ) , . . . files . reversed . toList ( ) ] ;
2022-03-23 15:28:21 +08:00
} else if ( sortType = = SortBy . Size ) {
2022-03-09 17:07:24 +08:00
// create list of path and size
Map < String , int > _sizeMap = { } ;
2022-03-09 22:43:05 +08:00
for ( Entry e in list ) {
_sizeMap [ e . name ] = e . size ;
2022-03-09 17:07:24 +08:00
}
// making list of only folders.
2022-03-09 22:43:05 +08:00
final dirs = list . where ( ( element ) = > element . isDirectory ) . toList ( ) ;
2022-03-09 17:07:24 +08:00
// sorting folder list by name.
2022-03-09 22:43:05 +08:00
dirs . sort ( ( a , b ) = > a . name . toLowerCase ( ) . compareTo ( b . name . toLowerCase ( ) ) ) ;
2022-03-09 17:07:24 +08:00
// making list of only flies.
2022-03-09 22:43:05 +08:00
final files = list . where ( ( element ) = > element . isFile ) . toList ( ) ;
2022-03-09 17:07:24 +08:00
// creating sorted list of [_sizeMapList] by size.
final List < MapEntry < String , int > > _sizeMapList = _sizeMap . entries . toList ( ) ;
_sizeMapList . sort ( ( b , a ) = > a . value . compareTo ( b . value ) ) ;
// sort [list] according to [_sizeMapList]
files . sort ( ( a , b ) = > _sizeMapList
2022-03-09 22:43:05 +08:00
. indexWhere ( ( element ) = > element . key = = a . name )
2022-03-09 17:07:24 +08:00
. compareTo (
2022-03-09 22:43:05 +08:00
_sizeMapList . indexWhere ( ( element ) = > element . key = = b . name ) ) ) ;
2022-08-03 22:03:31 +08:00
return ascending
? [ . . . dirs , . . . files ]
: [ . . . dirs . reversed . toList ( ) , . . . files . reversed . toList ( ) ] ;
2022-03-09 17:07:24 +08:00
}
return [ ] ;
}