diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 198ceef1..4301f413 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -472,7 +472,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -480,7 +480,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -604,7 +604,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -612,7 +612,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -630,7 +630,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -638,7 +638,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -659,7 +659,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -672,7 +672,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -698,7 +698,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -711,7 +711,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -734,7 +734,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -747,7 +747,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/lib/core/utils/icloud.dart b/lib/core/utils/icloud.dart index a1f846ca..a9e8e638 100644 --- a/lib/core/utils/icloud.dart +++ b/lib/core/utils/icloud.dart @@ -103,6 +103,7 @@ class ICloud { final errs = []; final allFiles = await getAll(); + /// remove files not in relativePaths allFiles.removeWhere((e) => !relativePaths.contains(e.relativePath)); @@ -121,6 +122,7 @@ class ICloud { })); final docPath = await docDir; + /// compare files in iCloud and local mission.addAll(allFiles.map((file) async { final relativePath = file.relativePath; diff --git a/lib/data/model/sftp/req.dart b/lib/data/model/sftp/req.dart index cc8eef6e..9dc6c665 100644 --- a/lib/data/model/sftp/req.dart +++ b/lib/data/model/sftp/req.dart @@ -58,13 +58,18 @@ class SftpReqStatus { @override int get hashCode => id ^ super.hashCode; + void dispose() { + // ignore: deprecated_member_use_from_same_package + worker.dispose(); + completer?.complete(); + } + void onNotify(dynamic event) { switch (event.runtimeType) { case SftpWorkerStatus: status = event; if (status == SftpWorkerStatus.finished) { - worker.dispose(); - completer?.complete(); + dispose(); } break; case double: diff --git a/lib/data/model/sftp/worker.dart b/lib/data/model/sftp/worker.dart index 4fc01f3c..03c6f6c1 100644 --- a/lib/data/model/sftp/worker.dart +++ b/lib/data/model/sftp/worker.dart @@ -20,6 +20,13 @@ class SftpWorker { required this.req, }); + /// Use [@Deprecated] to prevent calling [SftpWorker.dispose] directly + /// + /// Don't delete this method + @Deprecated( + "Use [SftpWorkerStatus.dispose] to dispose the worker, " + "instead of [SftpWorker.dispose]", + ) void dispose() { worker.dispose(); } @@ -77,24 +84,27 @@ Future _download( final client = await genClient(req.spi, privateKey: req.privateKey); mainSendPort.send(SftpWorkerStatus.sshConnectted); - await Directory(req.localPath.substring(0, req.localPath.lastIndexOf('/'))) - .create(recursive: true); - final local = File(req.localPath); - if (await local.exists()) { - await local.delete(); - } - final localFile = local.openWrite(mode: FileMode.append); + /// Create the directory if not exists + final dirPath = req.localPath.substring(0, req.localPath.lastIndexOf('/')); + await Directory(dirPath).create(recursive: true); + + /// Use [FileMode.write] to overwrite the file + final localFile = File(req.localPath).openWrite(mode: FileMode.write); final file = await (await client.sftp()).open(req.remotePath); final size = (await file.stat()).size; if (size == null) { - mainSendPort.send(Exception('can not get file size')); + mainSendPort.send(Exception('can\'t get file size: ${req.remotePath}')); return; } - // Read 10m each time - const defaultChunkSize = 1024 * 1024 * 10; - final chunkSize = size > defaultChunkSize ? defaultChunkSize : size; + mainSendPort.send(size); mainSendPort.send(SftpWorkerStatus.loading); + + // Read 2m each time + // Issue #161 + // The download speed is about 2m/s may due to single core performance + const defaultChunkSize = 1024 * 1024 * 2; + final chunkSize = size > defaultChunkSize ? defaultChunkSize : size; for (var i = 0; i < size; i += chunkSize) { final fileData = file.read(length: chunkSize); await for (var form in fileData) { @@ -102,8 +112,10 @@ Future _download( mainSendPort.send((i + form.length) / size * 100); } } + await localFile.close(); await file.close(); + mainSendPort.send(watch.elapsed); mainSendPort.send(SftpWorkerStatus.finished); } catch (e) { diff --git a/lib/data/provider/sftp.dart b/lib/data/provider/sftp.dart index e3fed7a6..d108de0c 100644 --- a/lib/data/provider/sftp.dart +++ b/lib/data/provider/sftp.dart @@ -23,14 +23,14 @@ class SftpProvider extends ChangeNotifier { @override void dispose() { for (final item in _status) { - item.worker.dispose(); + item.dispose(); } super.dispose(); } void cancel(int id) { final idx = _status.indexWhere((element) => element.id == id); - _status[idx].worker.dispose(); + _status[idx].dispose(); _status.removeAt(idx); notifyListeners(); } diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 3a3dc328..0feb333e 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,9 +2,9 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 542; + static const int build = 545; static const String engine = "3.13.2"; - static const String buildAt = "2023-09-11 22:08:36.399180"; - static const int modifications = 23; + static const String buildAt = "2023-09-11 23:23:58.257948"; + static const int modifications = 6; static const int script = 14; } diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index 2695c08e..df5b0ba8 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -75,7 +75,7 @@ class _LocalStoragePageState extends State { context.pop(); }, ), - title: Text(_s.download), + title: Text(_s.files), actions: [ IconButton( icon: const Icon(Icons.downloading), diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 565753be..3d2d5f44 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -476,9 +476,9 @@ baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -491,9 +491,9 @@ baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -506,9 +506,9 @@ baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 542; + CURRENT_PROJECT_VERSION = 545; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.542; + MARKETING_VERSION = 1.0.545; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0;