123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- import 'dart:collection';
- import 'dart:convert';
- import 'package:flutter/material.dart';
- import 'package:flutter_hbb/common.dart';
- import 'package:flutter_hbb/models/model.dart';
- import 'package:flutter_hbb/models/server_model.dart';
- import 'package:get/get.dart';
- import 'file_model.dart';
- class CmFileModel {
- final WeakReference<FFI> parent;
- final currentJobTable = RxList<CmFileLog>();
- final _jobTables = HashMap<int, RxList<CmFileLog>>.fromEntries([]);
- Stopwatch stopwatch = Stopwatch();
- int _lastElapsed = 0;
- CmFileModel(this.parent);
- void updateCurrentClientId(int id) {
- if (_jobTables[id] == null) {
- _jobTables[id] = RxList<CmFileLog>();
- }
- Future.delayed(Duration.zero, () {
- currentJobTable.value = _jobTables[id]!;
- });
- }
- onFileTransferLog(Map<String, dynamic> evt) {
- if (evt['transfer'] != null) {
- _onFileTransfer(evt['transfer']);
- } else if (evt['remove'] != null) {
- _onFileRemove(evt['remove']);
- } else if (evt['create_dir'] != null) {
- _onDirCreate(evt['create_dir']);
- } else if (evt['rename'] != null) {
- _onRename(evt['rename']);
- }
- }
- _onFileTransfer(dynamic log) {
- try {
- dynamic d = jsonDecode(log);
- if (!stopwatch.isRunning) stopwatch.start();
- bool calcSpeed = stopwatch.elapsedMilliseconds - _lastElapsed >= 1000;
- if (calcSpeed) {
- _lastElapsed = stopwatch.elapsedMilliseconds;
- }
- if (d is List<dynamic>) {
- for (var l in d) {
- _dealOneJob(l, calcSpeed);
- }
- } else {
- _dealOneJob(d, calcSpeed);
- }
- currentJobTable.refresh();
- } catch (e) {
- debugPrint("onFileTransferLog:$e");
- }
- }
- _dealOneJob(dynamic l, bool calcSpeed) {
- final data = TransferJobSerdeData.fromJson(l);
- var jobTable = _jobTables[data.connId];
- if (jobTable == null) {
- debugPrint("jobTable should not be null");
- return;
- }
- CmFileLog? job = jobTable.firstWhereOrNull((e) => e.id == data.id);
- if (job == null) {
- job = CmFileLog();
- jobTable.add(job);
- _addUnread(data.connId);
- }
- job.id = data.id;
- job.action =
- data.isRemote ? CmFileAction.remoteToLocal : CmFileAction.localToRemote;
- job.fileName = data.path;
- job.totalSize = data.totalSize;
- job.finishedSize = data.finishedSize;
- if (job.finishedSize > data.totalSize) {
- job.finishedSize = data.totalSize;
- }
- if (job.finishedSize > 0) {
- if (job.finishedSize < job.totalSize) {
- job.state = JobState.inProgress;
- } else {
- job.state = JobState.done;
- }
- }
- if (data.done) {
- job.state = JobState.done;
- } else if (data.cancel || data.error == 'skipped') {
- job.state = JobState.done;
- job.err = 'skipped';
- } else if (data.error.isNotEmpty) {
- job.state = JobState.error;
- job.err = data.error;
- }
- if (calcSpeed) {
- job.speed = (data.transferred - job.lastTransferredSize) * 1.0;
- job.lastTransferredSize = data.transferred;
- }
- jobTable.refresh();
- }
- _onFileRemove(dynamic log) {
- try {
- dynamic d = jsonDecode(log);
- FileActionLog data = FileActionLog.fromJson(d);
- Client? client =
- gFFI.serverModel.clients.firstWhereOrNull((e) => e.id == data.connId);
- var jobTable = _jobTables[data.connId];
- if (jobTable == null) {
- debugPrint("jobTable should not be null");
- return;
- }
- int removeUnreadCount = 0;
- if (data.dir) {
- bool isChild(String parent, String child) {
- if (child.startsWith(parent) && child.length > parent.length) {
- final suffix = child.substring(parent.length);
- return suffix.startsWith('/') || suffix.startsWith('\\');
- }
- return false;
- }
- removeUnreadCount = jobTable
- .where((e) =>
- e.action == CmFileAction.remove &&
- isChild(data.path, e.fileName))
- .length;
- jobTable.removeWhere((e) =>
- e.action == CmFileAction.remove && isChild(data.path, e.fileName));
- }
- jobTable.add(CmFileLog()
- ..id = data.id
- ..fileName = data.path
- ..action = CmFileAction.remove
- ..state = JobState.done);
- final currentSelectedTab =
- gFFI.serverModel.tabController.state.value.selectedTabInfo;
- if (!(gFFI.chatModel.isShowCMSidePage &&
- currentSelectedTab.key == data.connId.toString())) {
- // Wrong number if unreadCount changes during deletion, which rarely happens
- RxInt? rx = client?.unreadChatMessageCount;
- if (rx != null) {
- if (rx.value >= removeUnreadCount) {
- rx.value -= removeUnreadCount;
- }
- rx.value += 1;
- }
- }
- jobTable.refresh();
- } catch (e) {
- debugPrint('$e');
- }
- }
- _onDirCreate(dynamic log) {
- try {
- dynamic d = jsonDecode(log);
- FileActionLog data = FileActionLog.fromJson(d);
- var jobTable = _jobTables[data.connId];
- if (jobTable == null) {
- debugPrint("jobTable should not be null");
- return;
- }
- jobTable.add(CmFileLog()
- ..id = data.id
- ..fileName = data.path
- ..action = CmFileAction.createDir
- ..state = JobState.done);
- _addUnread(data.connId);
- jobTable.refresh();
- } catch (e) {
- debugPrint('$e');
- }
- }
- _onRename(dynamic log) {
- try {
- dynamic d = jsonDecode(log);
- FileRenamenLog data = FileRenamenLog.fromJson(d);
- var jobTable = _jobTables[data.connId];
- if (jobTable == null) {
- debugPrint("jobTable should not be null");
- return;
- }
- final fileName = '${data.path} -> ${data.newName}';
- jobTable.add(CmFileLog()
- ..id = 0
- ..fileName = fileName
- ..action = CmFileAction.rename
- ..state = JobState.done);
- _addUnread(data.connId);
- jobTable.refresh();
- } catch (e) {
- debugPrint('$e');
- }
- }
- _addUnread(int connId) {
- Client? client =
- gFFI.serverModel.clients.firstWhereOrNull((e) => e.id == connId);
- final currentSelectedTab =
- gFFI.serverModel.tabController.state.value.selectedTabInfo;
- if (!(gFFI.chatModel.isShowCMSidePage &&
- currentSelectedTab.key == connId.toString())) {
- client?.unreadChatMessageCount.value += 1;
- }
- }
- }
- enum CmFileAction {
- none,
- remoteToLocal,
- localToRemote,
- remove,
- createDir,
- rename,
- }
- class CmFileLog {
- JobState state = JobState.none;
- var id = 0;
- var speed = 0.0;
- var finishedSize = 0;
- var totalSize = 0;
- CmFileAction action = CmFileAction.none;
- var fileName = "";
- var err = "";
- int lastTransferredSize = 0;
- String display() {
- if (state == JobState.done && err == "skipped") {
- return translate("Skipped");
- }
- return state.display();
- }
- bool isTransfer() {
- return action == CmFileAction.remoteToLocal ||
- action == CmFileAction.localToRemote;
- }
- }
- class TransferJobSerdeData {
- int connId;
- int id;
- String path;
- bool isRemote;
- int totalSize;
- int finishedSize;
- int transferred;
- bool done;
- bool cancel;
- String error;
- TransferJobSerdeData({
- required this.connId,
- required this.id,
- required this.path,
- required this.isRemote,
- required this.totalSize,
- required this.finishedSize,
- required this.transferred,
- required this.done,
- required this.cancel,
- required this.error,
- });
- TransferJobSerdeData.fromJson(dynamic d)
- : this(
- connId: d['connId'] ?? 0,
- id: int.tryParse(d['id'].toString()) ?? 0,
- path: d['path'] ?? '',
- isRemote: d['isRemote'] ?? false,
- totalSize: d['totalSize'] ?? 0,
- finishedSize: d['finishedSize'] ?? 0,
- transferred: d['transferred'] ?? 0,
- done: d['done'] ?? false,
- cancel: d['cancel'] ?? false,
- error: d['error'] ?? '',
- );
- }
- class FileActionLog {
- int id = 0;
- int connId = 0;
- String path = '';
- bool dir = false;
- FileActionLog({
- required this.connId,
- required this.id,
- required this.path,
- required this.dir,
- });
- FileActionLog.fromJson(dynamic d)
- : this(
- connId: d['connId'] ?? 0,
- id: d['id'] ?? 0,
- path: d['path'] ?? '',
- dir: d['dir'] ?? false,
- );
- }
- class FileRenamenLog {
- int connId = 0;
- String path = '';
- String newName = '';
- FileRenamenLog({
- required this.connId,
- required this.path,
- required this.newName,
- });
- FileRenamenLog.fromJson(dynamic d)
- : this(
- connId: d['connId'] ?? 0,
- path: d['path'] ?? '',
- newName: d['newName'] ?? '',
- );
- }
|