| 
									
										
										
										
											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'; | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  | import 'package:flutter_hbb/utils/event_loop.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-09 19:14:40 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  | import 'package:path/path.dart' as path; | 
					
						
							| 
									
										
										
										
											2022-03-12 21:42:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  | import '../consts.dart'; | 
					
						
							| 
									
										
										
										
											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-10-20 10:31:31 +09:00
										 |  |  | enum SortBy { | 
					
						
							|  |  |  |   name, | 
					
						
							|  |  |  |   type, | 
					
						
							|  |  |  |   modified, | 
					
						
							|  |  |  |   size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   String toString() { | 
					
						
							|  |  |  |     final str = this.name.toString(); | 
					
						
							|  |  |  |     return "${str[0].toUpperCase()}${str.substring(1)}"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 00:49:14 +09:00
										 |  |  | class JobID { | 
					
						
							|  |  |  |   int _count = 0; | 
					
						
							|  |  |  |   int next() { | 
					
						
							|  |  |  |     _count++; | 
					
						
							|  |  |  |     return _count; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  | typedef GetSessionID = SessionID Function(); | 
					
						
							| 
									
										
										
										
											2023-03-08 00:49:14 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | class FileModel { | 
					
						
							|  |  |  |   final WeakReference<FFI> parent; | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |   // late final String sessionId;
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   late final FileFetcher fileFetcher; | 
					
						
							|  |  |  |   late final JobController jobController; | 
					
						
							| 
									
										
										
										
											2022-07-09 19:14:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   late final FileController localController; | 
					
						
							|  |  |  |   late final FileController remoteController; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   late final GetSessionID getSessionID; | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |   SessionID get sessionId => getSessionID(); | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   late final FileDialogEventLoop evtLoop; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   FileModel(this.parent) { | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |     getSessionID = () => parent.target!.sessionId; | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |     fileFetcher = FileFetcher(getSessionID); | 
					
						
							|  |  |  |     jobController = JobController(getSessionID); | 
					
						
							|  |  |  |     localController = FileController( | 
					
						
							|  |  |  |         isLocal: true, | 
					
						
							|  |  |  |         getSessionID: getSessionID, | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  |         rootState: parent, | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |         jobController: jobController, | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |         fileFetcher: fileFetcher, | 
					
						
							|  |  |  |         getOtherSideDirectoryData: () => remoteController.directoryData()); | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |     remoteController = FileController( | 
					
						
							|  |  |  |         isLocal: false, | 
					
						
							|  |  |  |         getSessionID: getSessionID, | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  |         rootState: parent, | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |         jobController: jobController, | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |         fileFetcher: fileFetcher, | 
					
						
							|  |  |  |         getOtherSideDirectoryData: () => localController.directoryData()); | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |     evtLoop = FileDialogEventLoop(); | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-11 01:28:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> onReady() async { | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |     await evtLoop.onReady(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     await localController.onReady(); | 
					
						
							|  |  |  |     await remoteController.onReady(); | 
					
						
							| 
									
										
										
										
											2022-03-11 01:28:13 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> close() async { | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |     await evtLoop.close(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     parent.target?.dialogManager.dismissAll(); | 
					
						
							|  |  |  |     await localController.close(); | 
					
						
							|  |  |  |     await remoteController.close(); | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> refreshAll() async { | 
					
						
							|  |  |  |     await localController.refresh(); | 
					
						
							|  |  |  |     await remoteController.refresh(); | 
					
						
							| 
									
										
										
										
											2022-03-11 01:28:13 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void receiveFileDir(Map<String, dynamic> evt) { | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |     if (evt['is_local'] == "false") { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       // init remote home, the remote connection will send one dir event when established. TODO opt
 | 
					
						
							|  |  |  |       remoteController.initDirAndHome(evt); | 
					
						
							| 
									
										
										
										
											2022-04-07 16:20:32 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     fileFetcher.tryCompleteTask(evt['value'], evt['is_local']); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   Future<void> postOverrideFileConfirm(Map<String, dynamic> evt) async { | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |     evtLoop.pushEvent( | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |         _FileDialogEvent(WeakReference(this), FileDialogType.overwrite, evt)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   Future<void> overrideFileConfirm(Map<String, dynamic> evt, | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |       {bool? overrideConfirm, bool skip = false}) async { | 
					
						
							|  |  |  |     // If `skip == true`, it means to skip this file without showing dialog.
 | 
					
						
							|  |  |  |     // Because `resp` may be null after the user operation or the last remembered operation,
 | 
					
						
							|  |  |  |     // and we should distinguish them.
 | 
					
						
							| 
									
										
										
										
											2023-03-15 17:18:59 +08:00
										 |  |  |     final resp = overrideConfirm ?? | 
					
						
							|  |  |  |         (!skip | 
					
						
							|  |  |  |             ? await showFileConfirmDialog(translate("Overwrite"), | 
					
						
							|  |  |  |                 "${evt['read_path']}", true, evt['is_identical'] == "true") | 
					
						
							|  |  |  |             : null); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       final jobIndex = jobController.getJob(id); | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |       if (jobIndex != -1) { | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |         await jobController.cancelJob(id); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         final job = jobController.jobTable[jobIndex]; | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |         job.state = JobState.done; | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |         jobController.jobTable.refresh(); | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											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
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |       // Update the loop config.
 | 
					
						
							|  |  |  |       if (fileConfirmCheckboxRemember) { | 
					
						
							|  |  |  |         evtLoop.setSkip(!need_override); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |       await bind.sessionSetConfirmOverrideFile( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |           sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |           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
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |     // Update the loop config.
 | 
					
						
							|  |  |  |     if (fileConfirmCheckboxRemember) { | 
					
						
							|  |  |  |       evtLoop.setOverrideConfirm(resp); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-17 20:56:36 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   bool fileConfirmCheckboxRemember = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<bool?> showFileConfirmDialog( | 
					
						
							| 
									
										
										
										
											2023-03-15 17:18:59 +08:00
										 |  |  |       String title, String content, bool showCheckbox, bool isIdentical) async { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     fileConfirmCheckboxRemember = false; | 
					
						
							|  |  |  |     return await parent.target?.dialogManager.show<bool?>( | 
					
						
							| 
									
										
										
										
											2023-05-08 12:34:19 +08:00
										 |  |  |         (setState, Function(bool? v) close, context) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       cancel() => close(false); | 
					
						
							|  |  |  |       submit() => close(true); | 
					
						
							|  |  |  |       return CustomAlertDialog( | 
					
						
							|  |  |  |         title: Row( | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             const Icon(Icons.warning_rounded, color: Colors.red), | 
					
						
							|  |  |  |             Text(title).paddingOnly( | 
					
						
							|  |  |  |               left: 10, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         contentBoxConstraints: | 
					
						
							|  |  |  |             BoxConstraints(minHeight: 100, minWidth: 400, maxWidth: 400), | 
					
						
							|  |  |  |         content: Column( | 
					
						
							|  |  |  |             crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |             mainAxisSize: MainAxisSize.min, | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Text(translate("This file exists, skip or overwrite this file?"), | 
					
						
							|  |  |  |                   style: const TextStyle(fontWeight: FontWeight.bold)), | 
					
						
							|  |  |  |               const SizedBox(height: 5), | 
					
						
							|  |  |  |               Text(content), | 
					
						
							| 
									
										
										
										
											2023-03-15 17:18:59 +08:00
										 |  |  |               Offstage( | 
					
						
							|  |  |  |                 offstage: !isIdentical, | 
					
						
							|  |  |  |                 child: Column( | 
					
						
							|  |  |  |                   mainAxisSize: MainAxisSize.min, | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     const SizedBox(height: 12), | 
					
						
							| 
									
										
										
										
											2023-03-15 17:26:33 +08:00
										 |  |  |                     Text(translate("identical_file_tip"), | 
					
						
							| 
									
										
										
										
											2023-03-15 17:18:59 +08:00
										 |  |  |                         style: const TextStyle(fontWeight: FontWeight.w500)) | 
					
						
							|  |  |  |                   ], | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |               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); | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                   : const SizedBox.shrink() | 
					
						
							|  |  |  |             ]), | 
					
						
							|  |  |  |         actions: [ | 
					
						
							|  |  |  |           dialogButton( | 
					
						
							|  |  |  |             "Cancel", | 
					
						
							|  |  |  |             icon: Icon(Icons.close_rounded), | 
					
						
							|  |  |  |             onPressed: cancel, | 
					
						
							|  |  |  |             isOutline: true, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           dialogButton( | 
					
						
							|  |  |  |             "Skip", | 
					
						
							|  |  |  |             icon: Icon(Icons.navigate_next_rounded), | 
					
						
							|  |  |  |             onPressed: () => close(null), | 
					
						
							|  |  |  |             isOutline: true, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           dialogButton( | 
					
						
							|  |  |  |             "OK", | 
					
						
							|  |  |  |             icon: Icon(Icons.done_rounded), | 
					
						
							|  |  |  |             onPressed: submit, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         onSubmit: submit, | 
					
						
							|  |  |  |         onCancel: cancel, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     }, useAnimation: false); | 
					
						
							| 
									
										
										
										
											2022-03-12 21:42:05 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-12 21:42:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  | class DirectoryData { | 
					
						
							|  |  |  |   final DirectoryOptions options; | 
					
						
							|  |  |  |   final FileDirectory directory; | 
					
						
							|  |  |  |   DirectoryData(this.directory, this.options); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | class FileController { | 
					
						
							|  |  |  |   final bool isLocal; | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   final GetSessionID getSessionID; | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |   SessionID get sessionId => getSessionID(); | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   final FileFetcher fileFetcher; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   final options = DirectoryOptions().obs; | 
					
						
							|  |  |  |   final directory = FileDirectory().obs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   final history = RxList<String>.empty(growable: true); | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   final sortBy = SortBy.name.obs; | 
					
						
							| 
									
										
										
										
											2023-03-09 00:06:24 +09:00
										 |  |  |   var sortAscending = true; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   final JobController jobController; | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  |   final WeakReference<FFI> rootState; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |   final DirectoryData Function() getOtherSideDirectoryData; | 
					
						
							| 
									
										
										
										
											2023-03-09 18:05:09 +09:00
										 |  |  |   late final SelectedItems selectedItems = SelectedItems(isLocal: isLocal); | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   FileController( | 
					
						
							|  |  |  |       {required this.isLocal, | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |       required this.getSessionID, | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  |       required this.rootState, | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       required this.jobController, | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |       required this.fileFetcher, | 
					
						
							|  |  |  |       required this.getOtherSideDirectoryData}); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   String get homePath => options.value.home; | 
					
						
							| 
									
										
										
										
											2023-10-20 00:14:14 +05:30
										 |  |  |   void set homePath(String path) => options.value.home = path; | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  |   OverlayDialogManager? get dialogManager => rootState.target?.dialogManager; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   String get shortPath { | 
					
						
							|  |  |  |     final dirPath = directory.value.path; | 
					
						
							|  |  |  |     if (dirPath.startsWith(homePath)) { | 
					
						
							|  |  |  |       var path = dirPath.replaceFirst(homePath, ""); | 
					
						
							|  |  |  |       if (path.isEmpty) return ""; | 
					
						
							|  |  |  |       if (path[0] == "/" || path[0] == "\\") { | 
					
						
							|  |  |  |         // remove more '/' or '\'
 | 
					
						
							|  |  |  |         path = path.replaceFirst(path[0], ""); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return path; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return dirPath.replaceFirst(homePath, ""); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |   DirectoryData directoryData() { | 
					
						
							|  |  |  |     return DirectoryData(directory.value, options.value); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> onReady() async { | 
					
						
							| 
									
										
										
										
											2023-03-16 19:39:37 +09:00
										 |  |  |     if (isLocal) { | 
					
						
							|  |  |  |       options.value.home = await bind.mainGetHomeDir(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     options.value.showHidden = (await bind.sessionGetPeerOption( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |             sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |             name: isLocal ? "local_show_hidden" : "remote_show_hidden")) | 
					
						
							| 
									
										
										
										
											2022-08-03 22:13:40 +08:00
										 |  |  |         .isNotEmpty; | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  |     options.value.isWindows = isLocal | 
					
						
							| 
									
										
										
										
											2024-03-24 11:23:06 +08:00
										 |  |  |         ? isWindows | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09:00
										 |  |  |         : rootState.target?.ffiModel.pi.platform == kPeerPlatformWindows; | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-07 16:20:32 +08:00
										 |  |  |     await Future.delayed(Duration(milliseconds: 100)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     final dir = (await bind.sessionGetPeerOption( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |         sessionId: sessionId, name: isLocal ? "local_dir" : "remote_dir")); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     openDirectory(dir.isEmpty ? options.value.home : dir); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-07 16:20:32 +08:00
										 |  |  |     await Future.delayed(Duration(seconds: 1)); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (directory.value.path.isEmpty) { | 
					
						
							|  |  |  |       openDirectory(options.value.home); | 
					
						
							| 
									
										
										
										
											2022-04-07 16:20:32 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> close() async { | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |     // save config
 | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     Map<String, String> msgMap = {}; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     msgMap[isLocal ? "local_dir" : "remote_dir"] = directory.value.path; | 
					
						
							|  |  |  |     msgMap[isLocal ? "local_show_hidden" : "remote_show_hidden"] = | 
					
						
							|  |  |  |         options.value.showHidden ? "Y" : ""; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     for (final msg in msgMap.entries) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       await bind.sessionPeerOption( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |           sessionId: sessionId, name: msg.key, value: msg.value); | 
					
						
							| 
									
										
										
										
											2022-07-01 11:26:32 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     directory.value.clear(); | 
					
						
							|  |  |  |     options.value.clear(); | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void toggleShowHidden({bool? showHidden}) { | 
					
						
							|  |  |  |     options.value.showHidden = showHidden ?? !options.value.showHidden; | 
					
						
							|  |  |  |     refresh(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void changeSortStyle(SortBy sort, {bool? isLocal, bool ascending = true}) { | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |     sortBy.value = sort; | 
					
						
							| 
									
										
										
										
											2023-03-09 00:06:24 +09:00
										 |  |  |     sortAscending = ascending; | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |     directory.update((dir) { | 
					
						
							|  |  |  |       dir?.changeSortStyle(sort, ascending: ascending); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<void> refresh() async { | 
					
						
							|  |  |  |     await openDirectory(directory.value.path); | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> openDirectory(String path, {bool isBack = false}) async { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     if (path == ".") { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       refresh(); | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (path == "..") { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       goToParentDirectory(); | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |     if (!isBack) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       pushHistory(); | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     final showHidden = options.value.showHidden; | 
					
						
							|  |  |  |     final isWindows = options.value.isWindows; | 
					
						
							| 
									
										
										
										
											2022-07-09 11:27:59 +08:00
										 |  |  |     // process /C:\ -> C:\ on Windows
 | 
					
						
							| 
									
										
										
										
											2022-12-04 23:44:03 +09:00
										 |  |  |     if (isWindows && path.length > 1 && path[0] == '/') { | 
					
						
							| 
									
										
										
										
											2022-07-09 11:27:59 +08:00
										 |  |  |       path = path.substring(1); | 
					
						
							|  |  |  |       if (path[path.length - 1] != '\\') { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |         path = "$path\\"; | 
					
						
							| 
									
										
										
										
											2022-07-09 11:27:59 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       final fd = await fileFetcher.fetchDirectory(path, isLocal, showHidden); | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |       fd.format(isWindows, sort: sortBy.value); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       directory.value = fd; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2022-09-06 19:08:45 +08:00
										 |  |  |       debugPrint("Failed to openDirectory $path: $e"); | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void pushHistory() { | 
					
						
							|  |  |  |     if (history.isNotEmpty && history.last == directory.value.path) { | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     history.add(directory.value.path); | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 23:45:48 +05:30
										 |  |  |   void goToHomeDirectory() { | 
					
						
							| 
									
										
										
										
											2023-10-20 00:14:14 +05:30
										 |  |  |     if (isLocal) { | 
					
						
							|  |  |  |       openDirectory(homePath); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     homePath = ""; | 
					
						
							| 
									
										
										
										
											2023-10-19 23:45:48 +05:30
										 |  |  |     openDirectory(homePath); | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void goBack() { | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |     if (history.isEmpty) return; | 
					
						
							|  |  |  |     final path = history.removeAt(history.length - 1); | 
					
						
							|  |  |  |     if (path.isEmpty) return; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     if (directory.value.path == path) { | 
					
						
							|  |  |  |       goBack(); | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     openDirectory(path, isBack: true); | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void goToParentDirectory() { | 
					
						
							|  |  |  |     final isWindows = options.value.isWindows; | 
					
						
							|  |  |  |     final dirPath = directory.value.path; | 
					
						
							|  |  |  |     var parent = PathUtil.dirname(dirPath, isWindows); | 
					
						
							| 
									
										
										
										
											2022-07-09 11:27:59 +08:00
										 |  |  |     // specially for C:\, D:\, goto '/'
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     if (parent == dirPath && isWindows) { | 
					
						
							|  |  |  |       openDirectory('/'); | 
					
						
							| 
									
										
										
										
											2022-07-09 11:27:59 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     openDirectory(parent); | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   // TODO deprecated this
 | 
					
						
							| 
									
										
										
										
											2023-10-19 23:45:48 +05:30
										 |  |  |   void initDirAndHome(Map<String, dynamic> evt) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     try { | 
					
						
							|  |  |  |       final fd = FileDirectory.fromJson(jsonDecode(evt['value'])); | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |       fd.format(options.value.isWindows, sort: sortBy.value); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       if (fd.id > 0) { | 
					
						
							|  |  |  |         final jobIndex = jobController.getJob(fd.id); | 
					
						
							|  |  |  |         if (jobIndex != -1) { | 
					
						
							|  |  |  |           final job = jobController.jobTable[jobIndex]; | 
					
						
							|  |  |  |           var totalSize = 0; | 
					
						
							|  |  |  |           var fileCount = fd.entries.length; | 
					
						
							|  |  |  |           for (var element in fd.entries) { | 
					
						
							|  |  |  |             totalSize += element.size; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           job.totalSize = totalSize; | 
					
						
							|  |  |  |           job.fileCount = fileCount; | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |           debugPrint("update receive details: ${fd.path}"); | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |           jobController.jobTable.refresh(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         } | 
					
						
							|  |  |  |       } else if (options.value.home.isEmpty) { | 
					
						
							|  |  |  |         options.value.home = fd.path; | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |         debugPrint("init remote home: ${fd.path}"); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         directory.value = fd; | 
					
						
							| 
									
										
										
										
											2022-07-01 12:08:52 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrint("initDirAndHome err=$e"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-09 22:34:43 +09:00
										 |  |  |   /// sendFiles from current side (FileController.isLocal) to other side (SelectedItems).
 | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |   void sendFiles(SelectedItems items, DirectoryData otherSideData) { | 
					
						
							|  |  |  |     /// ignore wrong items side status
 | 
					
						
							|  |  |  |     if (items.isLocal != isLocal) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // alias
 | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |     final isRemoteToLocal = !isLocal; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |     final toPath = otherSideData.directory.path; | 
					
						
							|  |  |  |     final isWindows = otherSideData.options.isWindows; | 
					
						
							|  |  |  |     final showHidden = otherSideData.options.showHidden; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     for (var from in items.items) { | 
					
						
							|  |  |  |       final jobID = jobController.add(from, isRemoteToLocal); | 
					
						
							|  |  |  |       bind.sessionSendFiles( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |           sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |           actId: jobID, | 
					
						
							|  |  |  |           path: from.path, | 
					
						
							|  |  |  |           to: PathUtil.join(toPath, from.name, isWindows), | 
					
						
							|  |  |  |           fileNum: 0, | 
					
						
							|  |  |  |           includeHidden: showHidden, | 
					
						
							|  |  |  |           isRemote: isRemoteToLocal); | 
					
						
							|  |  |  |       debugPrint( | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |           "path: ${from.path}, toPath: $toPath, to: ${PathUtil.join(toPath, from.name, isWindows)}"); | 
					
						
							| 
									
										
										
										
											2022-03-12 21:42:05 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   bool _removeCheckboxRemember = false; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> removeAction(SelectedItems items) async { | 
					
						
							|  |  |  |     _removeCheckboxRemember = false; | 
					
						
							| 
									
										
										
										
											2023-03-08 23:06:34 +09:00
										 |  |  |     if (items.isLocal != isLocal) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       debugPrint("Failed to removeFile, wrong files"); | 
					
						
							| 
									
										
										
										
											2022-03-12 21:42:05 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     final isWindows = options.value.isWindows; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     await Future.forEach(items.items, (Entry item) async { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       final jobID = JobController.jobID.next(); | 
					
						
							| 
									
										
										
										
											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-10-19 23:29:45 +09:00
										 |  |  |         content = item.name; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |         entries = [item]; | 
					
						
							|  |  |  |       } else if (item.isDirectory) { | 
					
						
							| 
									
										
										
										
											2022-03-24 15:29:12 +08:00
										 |  |  |         title = translate("Not an empty directory"); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         dialogManager?.showLoading(translate("Waiting")); | 
					
						
							|  |  |  |         final fd = await fileFetcher.fetchDirectoryRecursive( | 
					
						
							| 
									
										
										
										
											2023-03-16 11:23:15 +09: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); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         dialogManager?.dismissAll(); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |             sendRemoveEmptyDir(item.path, 0); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |           } | 
					
						
							|  |  |  |           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}" : ""; | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |         content = "$dirShow\n\n${entries[i].path}".trim(); | 
					
						
							|  |  |  |         final confirm = await showRemoveDialog( | 
					
						
							| 
									
										
										
										
											2023-03-01 14:50:50 +01:00
										 |  |  |           count.isEmpty ? title : "$title ($count)", | 
					
						
							|  |  |  |           content, | 
					
						
							|  |  |  |           item.isDirectory, | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |         try { | 
					
						
							|  |  |  |           if (confirm == true) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |             sendRemoveFile(entries[i].path, i); | 
					
						
							|  |  |  |             final res = await jobController.jobResultListener.start(); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |             // handle remove res;
 | 
					
						
							|  |  |  |             if (item.isDirectory && | 
					
						
							|  |  |  |                 res['file_num'] == (entries.length - 1).toString()) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |               sendRemoveEmptyDir(item.path, i); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |           if (_removeCheckboxRemember) { | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |             if (confirm == true) { | 
					
						
							|  |  |  |               for (var j = i + 1; j < entries.length; j++) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |                 sendRemoveFile(entries[j].path, j); | 
					
						
							|  |  |  |                 final res = await jobController.jobResultListener.start(); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |                 if (item.isDirectory && | 
					
						
							|  |  |  |                     res['file_num'] == (entries.length - 1).toString()) { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |                   sendRemoveEmptyDir(item.path, i); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |                 } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-07-12 11:51:58 +08:00
										 |  |  |         } catch (e) { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |           print("remove error: $e"); | 
					
						
							| 
									
										
										
										
											2022-07-12 11:51:58 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-03-12 21:42:05 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     refresh(); | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |     return await dialogManager?.show<bool>( | 
					
						
							|  |  |  |         (setState, Function(bool v) close, context) { | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       cancel() => close(false); | 
					
						
							|  |  |  |       submit() => close(true); | 
					
						
							|  |  |  |       return CustomAlertDialog( | 
					
						
							|  |  |  |         title: Row( | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |           mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |           children: [ | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |             const Icon(Icons.warning_rounded, color: Colors.red), | 
					
						
							| 
									
										
										
										
											2023-08-15 10:11:04 +08:00
										 |  |  |             Expanded( | 
					
						
							|  |  |  |               child: Text(title).paddingOnly( | 
					
						
							|  |  |  |                 left: 10, | 
					
						
							|  |  |  |               ), | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-09-29 21:09:40 +08:00
										 |  |  |         contentBoxConstraints: | 
					
						
							| 
									
										
										
										
											2023-03-01 14:50:50 +01:00
										 |  |  |             BoxConstraints(minHeight: 100, minWidth: 400, maxWidth: 400), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         content: Column( | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Text(content), | 
					
						
							|  |  |  |             Text( | 
					
						
							|  |  |  |               translate("This is irreversible!"), | 
					
						
							|  |  |  |               style: const TextStyle( | 
					
						
							|  |  |  |                 fontWeight: FontWeight.bold, | 
					
						
							|  |  |  |                 color: Colors.red, | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ).paddingOnly(top: 20), | 
					
						
							|  |  |  |             showCheckbox | 
					
						
							|  |  |  |                 ? CheckboxListTile( | 
					
						
							|  |  |  |                     contentPadding: const EdgeInsets.all(0), | 
					
						
							|  |  |  |                     dense: true, | 
					
						
							|  |  |  |                     controlAffinity: ListTileControlAffinity.leading, | 
					
						
							|  |  |  |                     title: Text( | 
					
						
							|  |  |  |                       translate("Do this for all conflicts"), | 
					
						
							|  |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |                     value: _removeCheckboxRemember, | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |                     onChanged: (v) { | 
					
						
							|  |  |  |                       if (v == null) return; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |                       setState(() => _removeCheckboxRemember = v); | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                   ) | 
					
						
							| 
									
										
										
										
											2023-03-01 14:50:50 +01:00
										 |  |  |                 : const SizedBox.shrink() | 
					
						
							| 
									
										
										
										
											2023-02-27 20:56:45 +01:00
										 |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2023-03-01 14:50:50 +01:00
										 |  |  |         actions: [ | 
					
						
							|  |  |  |           dialogButton( | 
					
						
							|  |  |  |             "Cancel", | 
					
						
							|  |  |  |             icon: Icon(Icons.close_rounded), | 
					
						
							|  |  |  |             onPressed: cancel, | 
					
						
							|  |  |  |             isOutline: true, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           dialogButton( | 
					
						
							|  |  |  |             "OK", | 
					
						
							|  |  |  |             icon: Icon(Icons.done_rounded), | 
					
						
							|  |  |  |             onPressed: submit, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         onSubmit: submit, | 
					
						
							|  |  |  |         onCancel: cancel, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     }, useAnimation: false); | 
					
						
							| 
									
										
										
										
											2022-03-12 21:42:05 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void sendRemoveFile(String path, int fileNum) { | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     bind.sessionRemoveFile( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |         sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         actId: JobController.jobID.next(), | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |         path: path, | 
					
						
							|  |  |  |         isRemote: !isLocal, | 
					
						
							|  |  |  |         fileNum: fileNum); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void sendRemoveEmptyDir(String path, int fileNum) { | 
					
						
							| 
									
										
										
										
											2022-10-11 17:25:34 +09:00
										 |  |  |     history.removeWhere((element) => element.contains(path)); | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     bind.sessionRemoveAllEmptyDirs( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |         sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         actId: JobController.jobID.next(), | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |         path: path, | 
					
						
							|  |  |  |         isRemote: !isLocal); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<void> createDir(String path) async { | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     bind.sessionCreateDir( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |         sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         actId: JobController.jobID.next(), | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |         path: path, | 
					
						
							|  |  |  |         isRemote: !isLocal); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | class JobController { | 
					
						
							|  |  |  |   static final JobID jobID = JobID(); | 
					
						
							| 
									
										
										
										
											2023-03-09 00:06:24 +09:00
										 |  |  |   final jobTable = List<JobProgress>.empty(growable: true).obs; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   final jobResultListener = JobResultListener<Map<String, dynamic>>(); | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   final GetSessionID getSessionID; | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |   SessionID get sessionId => getSessionID(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   JobController(this.getSessionID); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   int getJob(int id) { | 
					
						
							|  |  |  |     return jobTable.indexWhere((element) => element.id == id); | 
					
						
							| 
									
										
										
										
											2022-03-29 23:10:43 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   // JobProgress? getJob(int id) {
 | 
					
						
							|  |  |  |   //   return jobTable.firstWhere((element) => element.id == id);
 | 
					
						
							|  |  |  |   // }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // return jobID
 | 
					
						
							|  |  |  |   int add(Entry from, bool isRemoteToLocal) { | 
					
						
							|  |  |  |     final jobID = JobController.jobID.next(); | 
					
						
							|  |  |  |     jobTable.add(JobProgress() | 
					
						
							|  |  |  |       ..fileName = path.basename(from.path) | 
					
						
							|  |  |  |       ..jobName = from.path | 
					
						
							|  |  |  |       ..totalSize = from.size | 
					
						
							|  |  |  |       ..state = JobState.inProgress | 
					
						
							|  |  |  |       ..id = jobID | 
					
						
							|  |  |  |       ..isRemoteToLocal = isRemoteToLocal); | 
					
						
							|  |  |  |     return jobID; | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void tryUpdateJobProgress(Map<String, dynamic> evt) { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       int id = int.parse(evt['id']); | 
					
						
							|  |  |  |       // id = index + 1
 | 
					
						
							|  |  |  |       final jobIndex = getJob(id); | 
					
						
							|  |  |  |       if (jobIndex >= 0 && jobTable.length > jobIndex) { | 
					
						
							|  |  |  |         final job = jobTable[jobIndex]; | 
					
						
							|  |  |  |         job.fileNum = int.parse(evt['file_num']); | 
					
						
							|  |  |  |         job.speed = double.parse(evt['speed']); | 
					
						
							|  |  |  |         job.finishedSize = int.parse(evt['finished_size']); | 
					
						
							|  |  |  |         debugPrint("update job $id with $evt"); | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |         jobTable.refresh(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       } | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |       debugPrint("Failed to tryUpdateJobProgress, evt: ${evt.toString()}"); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void jobDone(Map<String, dynamic> evt) async { | 
					
						
							|  |  |  |     if (jobResultListener.isListening) { | 
					
						
							|  |  |  |       jobResultListener.complete(evt); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int id = int.parse(evt['id']); | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |     final jobIndex = getJob(id); | 
					
						
							|  |  |  |     if (jobIndex != -1) { | 
					
						
							|  |  |  |       final job = jobTable[jobIndex]; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       job.finishedSize = job.totalSize; | 
					
						
							|  |  |  |       job.state = JobState.done; | 
					
						
							|  |  |  |       job.fileNum = int.parse(evt['file_num']); | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |       jobTable.refresh(); | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-11 16:07:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void jobError(Map<String, dynamic> evt) { | 
					
						
							|  |  |  |     final err = evt['err'].toString(); | 
					
						
							|  |  |  |     int jobIndex = getJob(int.parse(evt['id'])); | 
					
						
							|  |  |  |     if (jobIndex != -1) { | 
					
						
							|  |  |  |       final job = jobTable[jobIndex]; | 
					
						
							|  |  |  |       job.state = JobState.error; | 
					
						
							|  |  |  |       job.err = err; | 
					
						
							|  |  |  |       job.fileNum = int.parse(evt['file_num']); | 
					
						
							|  |  |  |       if (err == "skipped") { | 
					
						
							|  |  |  |         job.state = JobState.done; | 
					
						
							|  |  |  |         job.finishedSize = job.totalSize; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |       jobTable.refresh(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     } | 
					
						
							|  |  |  |     debugPrint("jobError $evt"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   Future<void> cancelJob(int id) async { | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |     await bind.sessionCancelJob(sessionId: sessionId, actId: id); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void loadLastJob(Map<String, dynamic> evt) { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     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']; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     final currJobId = JobController.jobID.next(); | 
					
						
							| 
									
										
										
										
											2023-03-03 20:26:13 +01:00
										 |  |  |     String fileName = path.basename(isRemote ? remote : to); | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |     var jobProgress = JobProgress() | 
					
						
							| 
									
										
										
										
											2023-03-03 20:26:13 +01:00
										 |  |  |       ..fileName = fileName | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |       ..jobName = isRemote ? remote : to | 
					
						
							|  |  |  |       ..id = currJobId | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       ..isRemoteToLocal = isRemote | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |       ..fileNum = fileNum | 
					
						
							|  |  |  |       ..remote = remote | 
					
						
							|  |  |  |       ..to = to | 
					
						
							|  |  |  |       ..showHidden = showHidden | 
					
						
							|  |  |  |       ..state = JobState.paused; | 
					
						
							|  |  |  |     jobTable.add(jobProgress); | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     bind.sessionAddJob( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |       sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |       isRemote: isRemote, | 
					
						
							|  |  |  |       includeHidden: showHidden, | 
					
						
							|  |  |  |       actId: currJobId, | 
					
						
							|  |  |  |       path: isRemote ? remote : to, | 
					
						
							|  |  |  |       to: isRemote ? to : remote, | 
					
						
							|  |  |  |       fileNum: fileNum, | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   void resumeJob(int jobId) { | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |     final jobIndex = getJob(jobId); | 
					
						
							|  |  |  |     if (jobIndex != -1) { | 
					
						
							|  |  |  |       final job = jobTable[jobIndex]; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |       bind.sessionResumeJob( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |           sessionId: sessionId, actId: job.id, isRemote: job.isRemoteToLocal); | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |       job.state = JobState.inProgress; | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |       jobTable.refresh(); | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |       debugPrint("jobId $jobId is not exists"); | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void updateFolderFiles(Map<String, dynamic> evt) { | 
					
						
							|  |  |  |     // ret: "{\"id\":1,\"num_entries\":12,\"total_size\":1264822.0}"
 | 
					
						
							|  |  |  |     Map<String, dynamic> info = json.decode(evt['info']); | 
					
						
							|  |  |  |     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(); | 
					
						
							| 
									
										
										
										
											2023-03-09 11:40:06 +09:00
										 |  |  |       jobTable.refresh(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     } | 
					
						
							|  |  |  |     debugPrint("update folder files: $info"); | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  | class JobResultListener<T> { | 
					
						
							|  |  |  |   Completer<T>? _completer; | 
					
						
							|  |  |  |   Timer? _timer; | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |   final int _timeoutSecond = 5; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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 { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |   // Map<String,Completer<FileDirectory>> localTasks = {}; // now we only use read local dir sync
 | 
					
						
							|  |  |  |   Map<String, Completer<FileDirectory>> remoteTasks = {}; | 
					
						
							|  |  |  |   Map<int, Completer<FileDirectory>> readRecursiveTasks = {}; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   final GetSessionID getSessionID; | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |   SessionID get sessionId => getSessionID(); | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   FileFetcher(this.getSessionID); | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |       c.completeError("Failed to read dir, timeout"); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  |     return c.future; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   Future<FileDirectory> registerReadRecursiveTask(int actID) { | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     final tasks = readRecursiveTasks; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     if (tasks.containsKey(actID)) { | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |       throw "Failed to registerRemoveTask, already have same ReadRecursive job"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     final c = Completer<FileDirectory>(); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |     tasks[actID] = c; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Timer(Duration(seconds: 2), () { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       tasks.remove(actID); | 
					
						
							| 
									
										
										
										
											2022-04-04 01:21:44 +08:00
										 |  |  |       if (c.isCompleted) return; | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |       c.completeError("Failed to read dir, timeout"); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  |     return c.future; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tryCompleteTask(String? msg, String? isLocalStr) { | 
					
						
							|  |  |  |     if (msg == null || isLocalStr == null) return; | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     late final Map<Object, Completer<FileDirectory>> tasks; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |       debugPrint("tryCompleteJob err: $e"); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |             sessionId: sessionId, 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( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |             sessionId: sessionId, 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( | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       int actID, String path, bool isLocal, bool showHidden) async { | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |     // 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( | 
					
						
							| 
									
										
										
										
											2023-06-06 07:39:44 +08:00
										 |  |  |           sessionId: sessionId, | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |           actId: actID, | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |           path: path, | 
					
						
							|  |  |  |           isRemote: !isLocal, | 
					
						
							|  |  |  |           showHidden: showHidden); | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |       return registerReadRecursiveTask(actID); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |     } 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) { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |       entries.add(Entry.fromJson(v)); | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											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}) { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     for (var entry in entries) { | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |       entry.path = PathUtil.join(path, entry.name, isWindows); | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |     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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 10:52:29 +09:00
										 |  |  |   bool get isDirectory => entryType < 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool get isDrive => entryType == 3; | 
					
						
							| 
									
										
										
										
											2022-03-11 01:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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: | 
					
						
							| 
									
										
										
										
											2023-11-06 20:12:01 +08:00
										 |  |  |         return translate("Transfer file"); | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |       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; | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   // [isRemote == true] means [remote -> local]
 | 
					
						
							|  |  |  |   // var isRemote = false;
 | 
					
						
							|  |  |  |   // to-do use enum
 | 
					
						
							|  |  |  |   var isRemoteToLocal = false; | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |   var jobName = ""; | 
					
						
							| 
									
										
										
										
											2023-03-03 20:26:13 +01:00
										 |  |  |   var fileName = ""; | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |   var remote = ""; | 
					
						
							|  |  |  |   var to = ""; | 
					
						
							|  |  |  |   var showHidden = false; | 
					
						
							| 
									
										
										
										
											2022-12-05 20:09:48 +08:00
										 |  |  |   var err = ""; | 
					
						
							| 
									
										
										
										
											2023-09-06 16:56:39 +08:00
										 |  |  |   int lastTransferredSize = 0; | 
					
						
							| 
									
										
										
										
											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 = ""; | 
					
						
							| 
									
										
										
										
											2023-03-03 20:26:13 +01:00
										 |  |  |     fileName = ""; | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |     fileCount = 0; | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |     remote = ""; | 
					
						
							|  |  |  |     to = ""; | 
					
						
							| 
									
										
										
										
											2022-12-05 20:09:48 +08:00
										 |  |  |     err = ""; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   String display() { | 
					
						
							|  |  |  |     if (state == JobState.done && err == "skipped") { | 
					
						
							|  |  |  |       return translate("Skipped"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return state.display(); | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |   static final windowsContext = path.Context(style: path.Style.windows); | 
					
						
							|  |  |  |   static final posixContext = path.Context(style: path.Style.posix); | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 00:49:14 +09:00
										 |  |  | class DirectoryOptions { | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |   String home; | 
					
						
							|  |  |  |   bool showHidden; | 
					
						
							|  |  |  |   bool isWindows; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 00:49:14 +09:00
										 |  |  |   DirectoryOptions( | 
					
						
							| 
									
										
										
										
											2022-03-17 21:03:52 +08:00
										 |  |  |       {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-10-17 23:07:40 +09:00
										 |  |  | class SelectedItems { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |   final bool isLocal; | 
					
						
							| 
									
										
										
										
											2023-03-09 19:55:38 +09:00
										 |  |  |   final items = RxList<Entry>.empty(growable: true); | 
					
						
							| 
									
										
										
										
											2022-10-17 23:07:40 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 22:32:55 +09:00
										 |  |  |   SelectedItems({required this.isLocal}); | 
					
						
							| 
									
										
										
										
											2022-10-17 23:07:40 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-09 18:05:09 +09:00
										 |  |  |   void add(Entry e) { | 
					
						
							| 
									
										
										
										
											2022-10-19 11:49:32 +09:00
										 |  |  |     if (e.isDrive) return; | 
					
						
							| 
									
										
										
										
											2023-03-09 19:55:38 +09:00
										 |  |  |     if (!items.contains(e)) { | 
					
						
							|  |  |  |       items.add(e); | 
					
						
							| 
									
										
										
										
											2022-10-17 23:07:40 +09:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-09 18:05:09 +09:00
										 |  |  |   void remove(Entry e) { | 
					
						
							| 
									
										
										
										
											2023-03-09 19:55:38 +09:00
										 |  |  |     items.remove(e); | 
					
						
							| 
									
										
										
										
											2022-10-17 23:07:40 +09:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-09 18:05:09 +09:00
										 |  |  |   void clear() { | 
					
						
							| 
									
										
										
										
											2023-03-09 19:55:38 +09:00
										 |  |  |     items.clear(); | 
					
						
							| 
									
										
										
										
											2022-10-17 23:07:40 +09:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-10-19 10:52:29 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void selectAll(List<Entry> entries) { | 
					
						
							| 
									
										
										
										
											2023-03-09 19:55:38 +09:00
										 |  |  |     items.clear(); | 
					
						
							|  |  |  |     items.addAll(entries); | 
					
						
							| 
									
										
										
										
											2022-10-19 10:52:29 +09:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-09 18:05:09 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-09 19:55:38 +09:00
										 |  |  |   static bool valid(RxList<Entry> items) { | 
					
						
							|  |  |  |     if (items.isNotEmpty) { | 
					
						
							| 
									
										
										
										
											2023-03-09 18:05:09 +09:00
										 |  |  |       // exclude DirDrive type
 | 
					
						
							|  |  |  |       return items.any((item) => !item.isDrive); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-10-17 23:07:40 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 11:24:44 +09:00
										 |  |  | // edited from [https://github.com/DevsOnFlutter/file_manager/blob/c1bf7f0225b15bcb86eba602c60acd5c4da90dd8/lib/file_manager.dart#L22]
 | 
					
						
							| 
									
										
										
										
											2022-07-11 16:07:49 +08:00
										 |  |  | List<Entry> _sortList(List<Entry> list, SortBy sortType, bool ascending) { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |   if (sortType == SortBy.name) { | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  |     // making list of only folders.
 | 
					
						
							| 
									
										
										
										
											2022-10-19 11:24:44 +09:00
										 |  |  |     final dirs = list | 
					
						
							|  |  |  |         .where((element) => element.isDirectory || element.isDrive) | 
					
						
							|  |  |  |         .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-10-19 23:29:45 +09:00
										 |  |  |   } else if (sortType == SortBy.modified) { | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  |     // making the list of Path & DateTime
 | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     List<_PathStat> pathStat = []; | 
					
						
							| 
									
										
										
										
											2022-03-09 22:43:05 +08:00
										 |  |  |     for (Entry e in list) { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |       pathStat.add(_PathStat(e.name, e.lastModified())); | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // sort _pathStat according to date
 | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     pathStat.sort((b, a) => a.dateTime.compareTo(b.dateTime)); | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-09 22:43:05 +08:00
										 |  |  |     // sorting [list] according to [_pathStat]
 | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     list.sort((a, b) => pathStat | 
					
						
							| 
									
										
										
										
											2022-03-09 22:43:05 +08:00
										 |  |  |         .indexWhere((element) => element.path == a.name) | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |         .compareTo(pathStat.indexWhere((element) => element.path == b.name))); | 
					
						
							| 
									
										
										
										
											2022-07-11 16:07:49 +08:00
										 |  |  |     return ascending ? list : list.reversed.toList(); | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09: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-10-19 23:29:45 +09:00
										 |  |  |   } else if (sortType == SortBy.size) { | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  |     // create list of path and size
 | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     Map<String, int> sizeMap = {}; | 
					
						
							| 
									
										
										
										
											2022-03-09 22:43:05 +08:00
										 |  |  |     for (Entry e in list) { | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |       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.
 | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     final List<MapEntry<String, int>> sizeMapList = sizeMap.entries.toList(); | 
					
						
							|  |  |  |     sizeMapList.sort((b, a) => a.value.compareTo(b.value)); | 
					
						
							| 
									
										
										
										
											2022-03-09 17:07:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // sort [list] according to [_sizeMapList]
 | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |     files.sort((a, b) => sizeMapList | 
					
						
							| 
									
										
										
										
											2022-03-09 22:43:05 +08:00
										 |  |  |         .indexWhere((element) => element.key == a.name) | 
					
						
							| 
									
										
										
										
											2022-10-19 23:29:45 +09:00
										 |  |  |         .compareTo(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 []; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /// Define a general queue which can accepts different dialog type.
 | 
					
						
							|  |  |  | ///
 | 
					
						
							|  |  |  | /// [Visibility]
 | 
					
						
							|  |  |  | /// The `_FileDialogType` and `_DialogEvent` are invisible for other models.
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  | enum FileDialogType { overwrite, unknown } | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  | class _FileDialogEvent extends BaseEvent<FileDialogType, Map<String, dynamic>> { | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   WeakReference<FileModel> fileModel; | 
					
						
							|  |  |  |   bool? _overrideConfirm; | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   bool _skip = false; | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _FileDialogEvent(this.fileModel, super.type, super.data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void setOverrideConfirm(bool? confirm) { | 
					
						
							|  |  |  |     _overrideConfirm = confirm; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   void setSkip(bool skip) { | 
					
						
							|  |  |  |     _skip = skip; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   EventCallback<Map<String, dynamic>>? findCallback(FileDialogType type) { | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |     final model = fileModel.target; | 
					
						
							|  |  |  |     if (model == null) { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |       case FileDialogType.overwrite: | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |         return (data) async { | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |           return await model.overrideFileConfirm(data, | 
					
						
							|  |  |  |               overrideConfirm: _overrideConfirm, skip: _skip); | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |         }; | 
					
						
							|  |  |  |       default: | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |         debugPrint("Unknown event type: $type with $data"); | 
					
						
							|  |  |  |         return null; | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  | class FileDialogEventLoop | 
					
						
							|  |  |  |     extends BaseEventLoop<FileDialogType, Map<String, dynamic>> { | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |   bool? _overrideConfirm; | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   bool _skip = false; | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   Future<void> onPreConsume( | 
					
						
							|  |  |  |       BaseEvent<FileDialogType, Map<String, dynamic>> evt) async { | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |     var event = evt as _FileDialogEvent; | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |     event.setOverrideConfirm(_overrideConfirm); | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |     event.setSkip(_skip); | 
					
						
							| 
									
										
										
										
											2023-03-15 17:18:59 +08:00
										 |  |  |     debugPrint( | 
					
						
							| 
									
										
										
										
											2023-03-15 22:44:07 +08:00
										 |  |  |         "FileDialogEventLoop: consuming<jobId: ${evt.data['id']} overrideConfirm: $_overrideConfirm, skip: $_skip>"); | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Future<void> onEventsClear() { | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |     _overrideConfirm = null; | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |     _skip = false; | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |     return super.onEventsClear(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  |   void setOverrideConfirm(bool? confirm) { | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |     _overrideConfirm = confirm; | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-15 15:13:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void setSkip(bool skip) { | 
					
						
							|  |  |  |     _skip = skip; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |