opt desktop file manager status list (#9117)
* Show delete file/dir log * Show full path rather than base file name * Show files count * Opt status card layout * Change selected color to accent Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
parent
2a0fd55af7
commit
8745fcbb6a
@ -173,10 +173,25 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
/// transfer status list
|
/// transfer status list
|
||||||
/// watch transfer status
|
/// watch transfer status
|
||||||
Widget statusList() {
|
Widget statusList() {
|
||||||
|
Widget getIcon(JobProgress job) {
|
||||||
|
final color = Theme.of(context).tabBarTheme.labelColor;
|
||||||
|
switch (job.type) {
|
||||||
|
case JobType.deleteDir:
|
||||||
|
case JobType.deleteFile:
|
||||||
|
return Icon(Icons.delete_outline, color: color);
|
||||||
|
default:
|
||||||
|
return Transform.rotate(
|
||||||
|
angle: job.isRemoteToLocal ? pi : 0,
|
||||||
|
child: Icon(Icons.arrow_forward_ios, color: color),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
statusListView(List<JobProgress> jobs) => ListView.builder(
|
statusListView(List<JobProgress> jobs) => ListView.builder(
|
||||||
controller: ScrollController(),
|
controller: ScrollController(),
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final item = jobs[index];
|
final item = jobs[index];
|
||||||
|
final status = item.getStatus();
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 5),
|
padding: const EdgeInsets.only(bottom: 5),
|
||||||
child: generateCard(
|
child: generateCard(
|
||||||
@ -186,15 +201,8 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Transform.rotate(
|
getIcon(item)
|
||||||
angle: item.isRemoteToLocal ? pi : 0,
|
.marginSymmetric(horizontal: 10, vertical: 12),
|
||||||
child: SvgPicture.asset("assets/arrow.svg",
|
|
||||||
colorFilter: svgColor(
|
|
||||||
Theme.of(context).tabBarTheme.labelColor)),
|
|
||||||
).paddingOnly(left: 15),
|
|
||||||
const SizedBox(
|
|
||||||
width: 16.0,
|
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -204,44 +212,24 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
waitDuration: Duration(milliseconds: 500),
|
waitDuration: Duration(milliseconds: 500),
|
||||||
message: item.jobName,
|
message: item.jobName,
|
||||||
child: Text(
|
child: Text(
|
||||||
item.fileName,
|
item.jobName,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
).paddingSymmetric(vertical: 10),
|
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
'${translate("Total")} ${readableFileSize(item.totalSize.toDouble())}',
|
Tooltip(
|
||||||
|
waitDuration: Duration(milliseconds: 500),
|
||||||
|
message: status,
|
||||||
|
child: Text(status,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: MyTheme.darkGray,
|
color: MyTheme.darkGray,
|
||||||
),
|
)).marginOnly(top: 6),
|
||||||
),
|
),
|
||||||
Offstage(
|
Offstage(
|
||||||
offstage: item.state != JobState.inProgress,
|
offstage: item.type != JobType.transfer ||
|
||||||
child: Text(
|
item.state != JobState.inProgress,
|
||||||
'${translate("Speed")} ${readableFileSize(item.speed)}/s',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: MyTheme.darkGray,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Offstage(
|
|
||||||
offstage: item.state == JobState.inProgress,
|
|
||||||
child: Text(
|
|
||||||
translate(
|
|
||||||
item.display(),
|
|
||||||
),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: MyTheme.darkGray,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Offstage(
|
|
||||||
offstage: item.state != JobState.inProgress,
|
|
||||||
child: LinearPercentIndicator(
|
child: LinearPercentIndicator(
|
||||||
padding: EdgeInsets.only(right: 15),
|
|
||||||
animateFromLastPercent: true,
|
animateFromLastPercent: true,
|
||||||
center: Text(
|
center: Text(
|
||||||
'${(item.finishedSize / item.totalSize * 100).toStringAsFixed(0)}%',
|
'${(item.finishedSize / item.totalSize * 100).toStringAsFixed(0)}%',
|
||||||
@ -251,7 +239,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
progressColor: MyTheme.accent,
|
progressColor: MyTheme.accent,
|
||||||
backgroundColor: Theme.of(context).hoverColor,
|
backgroundColor: Theme.of(context).hoverColor,
|
||||||
lineHeight: kDesktopFileTransferRowHeight,
|
lineHeight: kDesktopFileTransferRowHeight,
|
||||||
).paddingSymmetric(vertical: 15),
|
).paddingSymmetric(vertical: 8),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -276,7 +264,6 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
),
|
),
|
||||||
MenuButton(
|
MenuButton(
|
||||||
tooltip: translate("Delete"),
|
tooltip: translate("Delete"),
|
||||||
padding: EdgeInsets.only(right: 15),
|
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
"assets/close.svg",
|
"assets/close.svg",
|
||||||
colorFilter: svgColor(Colors.white),
|
colorFilter: svgColor(Colors.white),
|
||||||
@ -289,11 +276,11 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
hoverColor: MyTheme.accent80,
|
hoverColor: MyTheme.accent80,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
).marginAll(12),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).paddingSymmetric(vertical: 10),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -1007,7 +994,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
child: Obx(() => Container(
|
child: Obx(() => Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: selectedItems.items.contains(entry)
|
color: selectedItems.items.contains(entry)
|
||||||
? Theme.of(context).hoverColor
|
? MyTheme.button
|
||||||
: Theme.of(context).cardColor,
|
: Theme.of(context).cardColor,
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(5.0),
|
Radius.circular(5.0),
|
||||||
@ -1050,6 +1037,11 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(entry.name.nonBreaking,
|
child: Text(entry.name.nonBreaking,
|
||||||
|
style: TextStyle(
|
||||||
|
color: selectedItems.items
|
||||||
|
.contains(entry)
|
||||||
|
? Colors.white
|
||||||
|
: null),
|
||||||
overflow:
|
overflow:
|
||||||
TextOverflow.ellipsis))
|
TextOverflow.ellipsis))
|
||||||
]),
|
]),
|
||||||
@ -1111,7 +1103,10 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: MyTheme.darkGray,
|
color: selectedItems.items
|
||||||
|
.contains(entry)
|
||||||
|
? Colors.white70
|
||||||
|
: MyTheme.darkGray,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
@ -1131,7 +1126,11 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
sizeStr,
|
sizeStr,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10, color: MyTheme.darkGray),
|
fontSize: 10,
|
||||||
|
color:
|
||||||
|
selectedItems.items.contains(entry)
|
||||||
|
? Colors.white70
|
||||||
|
: MyTheme.darkGray),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -451,7 +451,7 @@ class FileController {
|
|||||||
final isWindows = otherSideData.options.isWindows;
|
final isWindows = otherSideData.options.isWindows;
|
||||||
final showHidden = otherSideData.options.showHidden;
|
final showHidden = otherSideData.options.showHidden;
|
||||||
for (var from in items.items) {
|
for (var from in items.items) {
|
||||||
final jobID = jobController.add(from, isRemoteToLocal);
|
final jobID = jobController.addTransferJob(from, isRemoteToLocal);
|
||||||
bind.sessionSendFiles(
|
bind.sessionSendFiles(
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
actId: jobID,
|
actId: jobID,
|
||||||
@ -494,13 +494,21 @@ class FileController {
|
|||||||
fd.format(isWindows);
|
fd.format(isWindows);
|
||||||
dialogManager?.dismissAll();
|
dialogManager?.dismissAll();
|
||||||
if (fd.entries.isEmpty) {
|
if (fd.entries.isEmpty) {
|
||||||
|
var deleteJobId = jobController.addDeleteDirJob(item, !isLocal, 0);
|
||||||
final confirm = await showRemoveDialog(
|
final confirm = await showRemoveDialog(
|
||||||
translate(
|
translate(
|
||||||
"Are you sure you want to delete this empty directory?"),
|
"Are you sure you want to delete this empty directory?"),
|
||||||
item.name,
|
item.name,
|
||||||
false);
|
false);
|
||||||
if (confirm == true) {
|
if (confirm == true) {
|
||||||
sendRemoveEmptyDir(item.path, 0);
|
sendRemoveEmptyDir(
|
||||||
|
item.path,
|
||||||
|
0,
|
||||||
|
deleteJobId,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
jobController.updateJobStatus(deleteJobId,
|
||||||
|
error: "cancel", state: JobState.done);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -508,6 +516,13 @@ class FileController {
|
|||||||
} else {
|
} else {
|
||||||
entries = [];
|
entries = [];
|
||||||
}
|
}
|
||||||
|
int deleteJobId;
|
||||||
|
if (item.isDirectory) {
|
||||||
|
deleteJobId =
|
||||||
|
jobController.addDeleteDirJob(item, !isLocal, entries.length);
|
||||||
|
} else {
|
||||||
|
deleteJobId = jobController.addDeleteFileJob(item, !isLocal);
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < entries.length; i++) {
|
for (var i = 0; i < entries.length; i++) {
|
||||||
final dirShow = item.isDirectory
|
final dirShow = item.isDirectory
|
||||||
@ -522,24 +537,32 @@ class FileController {
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
if (confirm == true) {
|
if (confirm == true) {
|
||||||
sendRemoveFile(entries[i].path, i);
|
sendRemoveFile(entries[i].path, i, deleteJobId);
|
||||||
final res = await jobController.jobResultListener.start();
|
final res = await jobController.jobResultListener.start();
|
||||||
// handle remove res;
|
// handle remove res;
|
||||||
if (item.isDirectory &&
|
if (item.isDirectory &&
|
||||||
res['file_num'] == (entries.length - 1).toString()) {
|
res['file_num'] == (entries.length - 1).toString()) {
|
||||||
sendRemoveEmptyDir(item.path, i);
|
sendRemoveEmptyDir(item.path, i, deleteJobId);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
jobController.updateJobStatus(deleteJobId,
|
||||||
|
file_num: i, error: "cancel");
|
||||||
}
|
}
|
||||||
if (_removeCheckboxRemember) {
|
if (_removeCheckboxRemember) {
|
||||||
if (confirm == true) {
|
if (confirm == true) {
|
||||||
for (var j = i + 1; j < entries.length; j++) {
|
for (var j = i + 1; j < entries.length; j++) {
|
||||||
sendRemoveFile(entries[j].path, j);
|
sendRemoveFile(entries[j].path, j, deleteJobId);
|
||||||
final res = await jobController.jobResultListener.start();
|
final res = await jobController.jobResultListener.start();
|
||||||
if (item.isDirectory &&
|
if (item.isDirectory &&
|
||||||
res['file_num'] == (entries.length - 1).toString()) {
|
res['file_num'] == (entries.length - 1).toString()) {
|
||||||
sendRemoveEmptyDir(item.path, i);
|
sendRemoveEmptyDir(item.path, i, deleteJobId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
jobController.updateJobStatus(deleteJobId,
|
||||||
|
error: "cancel",
|
||||||
|
file_num: entries.length,
|
||||||
|
state: JobState.done);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -618,22 +641,19 @@ class FileController {
|
|||||||
}, useAnimation: false);
|
}, useAnimation: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendRemoveFile(String path, int fileNum) {
|
void sendRemoveFile(String path, int fileNum, int actId) {
|
||||||
bind.sessionRemoveFile(
|
bind.sessionRemoveFile(
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
actId: JobController.jobID.next(),
|
actId: actId,
|
||||||
path: path,
|
path: path,
|
||||||
isRemote: !isLocal,
|
isRemote: !isLocal,
|
||||||
fileNum: fileNum);
|
fileNum: fileNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendRemoveEmptyDir(String path, int fileNum) {
|
void sendRemoveEmptyDir(String path, int fileNum, int actId) {
|
||||||
history.removeWhere((element) => element.contains(path));
|
history.removeWhere((element) => element.contains(path));
|
||||||
bind.sessionRemoveAllEmptyDirs(
|
bind.sessionRemoveAllEmptyDirs(
|
||||||
sessionId: sessionId,
|
sessionId: sessionId, actId: actId, path: path, isRemote: !isLocal);
|
||||||
actId: JobController.jobID.next(),
|
|
||||||
path: path,
|
|
||||||
isRemote: !isLocal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createDir(String path) async {
|
Future<void> createDir(String path) async {
|
||||||
@ -729,14 +749,11 @@ class JobController {
|
|||||||
return jobTable.indexWhere((element) => element.id == id);
|
return jobTable.indexWhere((element) => element.id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// JobProgress? getJob(int id) {
|
|
||||||
// return jobTable.firstWhere((element) => element.id == id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return jobID
|
// return jobID
|
||||||
int add(Entry from, bool isRemoteToLocal) {
|
int addTransferJob(Entry from, bool isRemoteToLocal) {
|
||||||
final jobID = JobController.jobID.next();
|
final jobID = JobController.jobID.next();
|
||||||
jobTable.add(JobProgress()
|
jobTable.add(JobProgress()
|
||||||
|
..type = JobType.transfer
|
||||||
..fileName = path.basename(from.path)
|
..fileName = path.basename(from.path)
|
||||||
..jobName = from.path
|
..jobName = from.path
|
||||||
..totalSize = from.size
|
..totalSize = from.size
|
||||||
@ -746,6 +763,33 @@ class JobController {
|
|||||||
return jobID;
|
return jobID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int addDeleteFileJob(Entry file, bool isRemote) {
|
||||||
|
final jobID = JobController.jobID.next();
|
||||||
|
jobTable.add(JobProgress()
|
||||||
|
..type = JobType.deleteFile
|
||||||
|
..fileName = path.basename(file.path)
|
||||||
|
..jobName = file.path
|
||||||
|
..totalSize = file.size
|
||||||
|
..state = JobState.none
|
||||||
|
..id = jobID
|
||||||
|
..isRemoteToLocal = isRemote);
|
||||||
|
return jobID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int addDeleteDirJob(Entry file, bool isRemote, int fileCount) {
|
||||||
|
final jobID = JobController.jobID.next();
|
||||||
|
jobTable.add(JobProgress()
|
||||||
|
..type = JobType.deleteDir
|
||||||
|
..fileName = path.basename(file.path)
|
||||||
|
..jobName = file.path
|
||||||
|
..fileCount = fileCount
|
||||||
|
..totalSize = file.size
|
||||||
|
..state = JobState.none
|
||||||
|
..id = jobID
|
||||||
|
..isRemoteToLocal = isRemote);
|
||||||
|
return jobID;
|
||||||
|
}
|
||||||
|
|
||||||
void tryUpdateJobProgress(Map<String, dynamic> evt) {
|
void tryUpdateJobProgress(Map<String, dynamic> evt) {
|
||||||
try {
|
try {
|
||||||
int id = int.parse(evt['id']);
|
int id = int.parse(evt['id']);
|
||||||
@ -756,6 +800,7 @@ class JobController {
|
|||||||
job.fileNum = int.parse(evt['file_num']);
|
job.fileNum = int.parse(evt['file_num']);
|
||||||
job.speed = double.parse(evt['speed']);
|
job.speed = double.parse(evt['speed']);
|
||||||
job.finishedSize = int.parse(evt['finished_size']);
|
job.finishedSize = int.parse(evt['finished_size']);
|
||||||
|
job.recvJobRes = true;
|
||||||
debugPrint("update job $id with $evt");
|
debugPrint("update job $id with $evt");
|
||||||
jobTable.refresh();
|
jobTable.refresh();
|
||||||
}
|
}
|
||||||
@ -764,20 +809,48 @@ class JobController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void jobDone(Map<String, dynamic> evt) async {
|
Future<bool> jobDone(Map<String, dynamic> evt) async {
|
||||||
if (jobResultListener.isListening) {
|
if (jobResultListener.isListening) {
|
||||||
jobResultListener.complete(evt);
|
jobResultListener.complete(evt);
|
||||||
return;
|
// return;
|
||||||
}
|
}
|
||||||
|
int id = -1;
|
||||||
int id = int.parse(evt['id']);
|
int? fileNum = 0;
|
||||||
|
double? speed = 0;
|
||||||
|
try {
|
||||||
|
id = int.parse(evt['id']);
|
||||||
|
} catch (_) {}
|
||||||
final jobIndex = getJob(id);
|
final jobIndex = getJob(id);
|
||||||
if (jobIndex != -1) {
|
if (jobIndex == -1) return true;
|
||||||
final job = jobTable[jobIndex];
|
final job = jobTable[jobIndex];
|
||||||
job.finishedSize = job.totalSize;
|
job.recvJobRes = true;
|
||||||
|
if (job.type == JobType.deleteFile) {
|
||||||
job.state = JobState.done;
|
job.state = JobState.done;
|
||||||
job.fileNum = int.parse(evt['file_num']);
|
} else if (job.type == JobType.deleteDir) {
|
||||||
|
try {
|
||||||
|
fileNum = int.tryParse(evt['file_num']);
|
||||||
|
} catch (_) {}
|
||||||
|
if (fileNum != null) {
|
||||||
|
if (fileNum < job.fileNum) return true; // file_num can be 0 at last
|
||||||
|
job.fileNum = fileNum;
|
||||||
|
if (fileNum >= job.fileCount - 1) {
|
||||||
|
job.state = JobState.done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
fileNum = int.tryParse(evt['file_num']);
|
||||||
|
speed = double.tryParse(evt['speed']);
|
||||||
|
} catch (_) {}
|
||||||
|
if (fileNum != null) job.fileNum = fileNum;
|
||||||
|
if (speed != null) job.speed = speed;
|
||||||
|
job.state = JobState.done;
|
||||||
|
}
|
||||||
jobTable.refresh();
|
jobTable.refresh();
|
||||||
|
if (job.type == JobType.deleteDir) {
|
||||||
|
return job.state == JobState.done;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,16 +861,52 @@ class JobController {
|
|||||||
final job = jobTable[jobIndex];
|
final job = jobTable[jobIndex];
|
||||||
job.state = JobState.error;
|
job.state = JobState.error;
|
||||||
job.err = err;
|
job.err = err;
|
||||||
job.fileNum = int.parse(evt['file_num']);
|
job.recvJobRes = true;
|
||||||
|
if (job.type == JobType.transfer) {
|
||||||
|
int? fileNum = int.tryParse(evt['file_num']);
|
||||||
|
if (fileNum != null) job.fileNum = fileNum;
|
||||||
if (err == "skipped") {
|
if (err == "skipped") {
|
||||||
job.state = JobState.done;
|
job.state = JobState.done;
|
||||||
job.finishedSize = job.totalSize;
|
job.finishedSize = job.totalSize;
|
||||||
}
|
}
|
||||||
|
} else if (job.type == JobType.deleteDir) {
|
||||||
|
if (jobResultListener.isListening) {
|
||||||
|
jobResultListener.complete(evt);
|
||||||
|
}
|
||||||
|
int? fileNum = int.tryParse(evt['file_num']);
|
||||||
|
if (fileNum != null) job.fileNum = fileNum;
|
||||||
|
} else if (job.type == JobType.deleteFile) {
|
||||||
|
if (jobResultListener.isListening) {
|
||||||
|
jobResultListener.complete(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
jobTable.refresh();
|
jobTable.refresh();
|
||||||
}
|
}
|
||||||
debugPrint("jobError $evt");
|
debugPrint("jobError $evt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateJobStatus(int id,
|
||||||
|
{int? file_num, String? error, JobState? state}) {
|
||||||
|
final jobIndex = getJob(id);
|
||||||
|
if (jobIndex < 0) return;
|
||||||
|
final job = jobTable[jobIndex];
|
||||||
|
job.recvJobRes = true;
|
||||||
|
if (file_num != null) {
|
||||||
|
job.fileNum = file_num;
|
||||||
|
}
|
||||||
|
if (error != null) {
|
||||||
|
job.err = error;
|
||||||
|
job.state = JobState.error;
|
||||||
|
}
|
||||||
|
if (state != null) {
|
||||||
|
job.state = state;
|
||||||
|
}
|
||||||
|
if (job.type == JobType.deleteFile && error == null) {
|
||||||
|
job.state = JobState.done;
|
||||||
|
}
|
||||||
|
jobTable.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> cancelJob(int id) async {
|
Future<void> cancelJob(int id) async {
|
||||||
await bind.sessionCancelJob(sessionId: sessionId, actId: id);
|
await bind.sessionCancelJob(sessionId: sessionId, actId: id);
|
||||||
}
|
}
|
||||||
@ -814,6 +923,7 @@ class JobController {
|
|||||||
final currJobId = JobController.jobID.next();
|
final currJobId = JobController.jobID.next();
|
||||||
String fileName = path.basename(isRemote ? remote : to);
|
String fileName = path.basename(isRemote ? remote : to);
|
||||||
var jobProgress = JobProgress()
|
var jobProgress = JobProgress()
|
||||||
|
..type = JobType.transfer
|
||||||
..fileName = fileName
|
..fileName = fileName
|
||||||
..jobName = isRemote ? remote : to
|
..jobName = isRemote ? remote : to
|
||||||
..id = currJobId
|
..id = currJobId
|
||||||
@ -1088,8 +1198,12 @@ extension JobStateDisplay on JobState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum JobType { none, transfer, deleteFile, deleteDir }
|
||||||
|
|
||||||
class JobProgress {
|
class JobProgress {
|
||||||
|
JobType type = JobType.none;
|
||||||
JobState state = JobState.none;
|
JobState state = JobState.none;
|
||||||
|
var recvJobRes = false;
|
||||||
var id = 0;
|
var id = 0;
|
||||||
var fileNum = 0;
|
var fileNum = 0;
|
||||||
var speed = 0.0;
|
var speed = 0.0;
|
||||||
@ -1109,7 +1223,9 @@ class JobProgress {
|
|||||||
int lastTransferredSize = 0;
|
int lastTransferredSize = 0;
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
|
type = JobType.none;
|
||||||
state = JobState.none;
|
state = JobState.none;
|
||||||
|
recvJobRes = false;
|
||||||
id = 0;
|
id = 0;
|
||||||
fileNum = 0;
|
fileNum = 0;
|
||||||
speed = 0;
|
speed = 0;
|
||||||
@ -1123,11 +1239,81 @@ class JobProgress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String display() {
|
String display() {
|
||||||
|
if (type == JobType.transfer) {
|
||||||
if (state == JobState.done && err == "skipped") {
|
if (state == JobState.done && err == "skipped") {
|
||||||
return translate("Skipped");
|
return translate("Skipped");
|
||||||
}
|
}
|
||||||
|
} else if (type == JobType.deleteFile) {
|
||||||
|
if (err == "cancel") {
|
||||||
|
return translate("Cancel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return state.display();
|
return state.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getStatus() {
|
||||||
|
int handledFileCount = recvJobRes ? fileNum + 1 : fileNum;
|
||||||
|
if (handledFileCount >= fileCount) {
|
||||||
|
handledFileCount = fileCount;
|
||||||
|
}
|
||||||
|
if (state == JobState.done) {
|
||||||
|
handledFileCount = fileCount;
|
||||||
|
finishedSize = totalSize;
|
||||||
|
}
|
||||||
|
final filesStr = "$handledFileCount/$fileCount files";
|
||||||
|
final sizeStr = totalSize > 0 ? readableFileSize(totalSize.toDouble()) : "";
|
||||||
|
final sizePercentStr = totalSize > 0 && finishedSize > 0
|
||||||
|
? "${readableFileSize(finishedSize.toDouble())} / ${readableFileSize(totalSize.toDouble())}"
|
||||||
|
: "";
|
||||||
|
if (type == JobType.deleteFile) {
|
||||||
|
return display();
|
||||||
|
} else if (type == JobType.deleteDir) {
|
||||||
|
var res = '';
|
||||||
|
if (state == JobState.done || state == JobState.error) {
|
||||||
|
res = display();
|
||||||
|
}
|
||||||
|
if (filesStr.isNotEmpty) {
|
||||||
|
if (res.isNotEmpty) {
|
||||||
|
res += " ";
|
||||||
|
}
|
||||||
|
res += filesStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeStr.isNotEmpty) {
|
||||||
|
if (res.isNotEmpty) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += sizeStr;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else if (type == JobType.transfer) {
|
||||||
|
var res = "";
|
||||||
|
if (state != JobState.inProgress && state != JobState.none) {
|
||||||
|
res += display();
|
||||||
|
}
|
||||||
|
if (filesStr.isNotEmpty) {
|
||||||
|
if (res.isNotEmpty) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += filesStr;
|
||||||
|
}
|
||||||
|
if (sizeStr.isNotEmpty && state != JobState.inProgress) {
|
||||||
|
if (res.isNotEmpty) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += sizeStr;
|
||||||
|
}
|
||||||
|
if (sizePercentStr.isNotEmpty && state == JobState.inProgress) {
|
||||||
|
if (res.isNotEmpty) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += sizePercentStr;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PathStat {
|
class _PathStat {
|
||||||
|
@ -304,8 +304,13 @@ class FfiModel with ChangeNotifier {
|
|||||||
} else if (name == 'job_progress') {
|
} else if (name == 'job_progress') {
|
||||||
parent.target?.fileModel.jobController.tryUpdateJobProgress(evt);
|
parent.target?.fileModel.jobController.tryUpdateJobProgress(evt);
|
||||||
} else if (name == 'job_done') {
|
} else if (name == 'job_done') {
|
||||||
parent.target?.fileModel.jobController.jobDone(evt);
|
bool? refresh =
|
||||||
|
await parent.target?.fileModel.jobController.jobDone(evt);
|
||||||
|
if (refresh == true) {
|
||||||
|
// many job done for delete directory
|
||||||
|
// todo: refresh may not work when confirm delete local directory
|
||||||
parent.target?.fileModel.refreshAll();
|
parent.target?.fileModel.refreshAll();
|
||||||
|
}
|
||||||
} else if (name == 'job_error') {
|
} else if (name == 'job_error') {
|
||||||
parent.target?.fileModel.jobController.jobError(evt);
|
parent.target?.fileModel.jobController.jobError(evt);
|
||||||
} else if (name == 'override_file_confirm') {
|
} else if (name == 'override_file_confirm') {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user