diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ea3e8d31..4649fddd 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -586,7 +586,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -596,7 +596,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -720,7 +720,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -730,7 +730,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -748,7 +748,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -758,7 +758,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -779,7 +779,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -792,7 +792,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -818,7 +818,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -831,7 +831,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -854,7 +854,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -867,7 +867,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -890,7 +890,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -902,7 +902,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; @@ -931,7 +931,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -943,7 +943,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; @@ -969,7 +969,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 569; + CURRENT_PROJECT_VERSION = 570; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -981,7 +981,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; diff --git a/lib/core/route.dart b/lib/core/route.dart index 4c0d3594..6602a8e2 100644 --- a/lib/core/route.dart +++ b/lib/core/route.dart @@ -135,7 +135,7 @@ class AppRoute { key: key, spi: spi, initPath: initPath, - selectPath: isSelect, + isSelect: isSelect, ), 'sftp'); } diff --git a/lib/core/utils/misc.dart b/lib/core/utils/misc.dart index e07ddc0b..99b7a4b3 100644 --- a/lib/core/utils/misc.dart +++ b/lib/core/utils/misc.dart @@ -1,15 +1,13 @@ import 'dart:io'; -import 'package:crypto/crypto.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; import 'package:plain_notification_token/plain_notification_token.dart'; import 'package:share_plus/share_plus.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/data/res/provider.dart'; -Future shareFiles(BuildContext context, List filePaths) async { +Future shareFiles(List filePaths) async { for (final filePath in filePaths) { if (!await File(filePath).exists()) { return false; @@ -23,7 +21,7 @@ Future shareFiles(BuildContext context, List filePaths) async { } Providers.app.moveBg = false; // ignore: deprecated_member_use - await Share.shareFiles(filePaths, subject: 'ServerBox -> $text'); + await Share.shareFiles(filePaths, subject: text); Providers.app.moveBg = true; return filePaths.isNotEmpty; } @@ -59,23 +57,7 @@ String? getFileName(String? path) { return path.split('/').last; } -/// Return fmt: 2021-01-01 00:00:00 -String getTime(int? unixMill) { - return DateTime.fromMillisecondsSinceEpoch((unixMill ?? 0) * 1000) - .toString() - .replaceFirst('.000', ''); -} - /// Join two path with `/` String pathJoin(String path1, String path2) { return path1 + (path1.endsWith('/') ? '' : '/') + path2; } - -Future getFileSha256(String path) async { - final file = File(path); - if (!(await file.exists())) { - return null; - } - final digest = await sha256.bind(file.openRead()).first; - return digest.toString(); -} diff --git a/lib/data/provider/docker.dart b/lib/data/provider/docker.dart index 02952974..9789551b 100644 --- a/lib/data/provider/docker.dart +++ b/lib/data/provider/docker.dart @@ -50,7 +50,7 @@ class DockerProvider extends ChangeNotifier { Future refresh() async { var raw = ''; await client!.execWithPwd( - AppShellFuncType.docker.exec, + ShellFunc.docker.exec, context: context, onStdout: (data, _) => raw = '$raw$data', ); diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 05368735..78af7520 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 = 569; - static const String engine = "3.13.4"; - static const String buildAt = "2023-09-21 20:09:12"; - static const int modifications = 2; - static const int script = 16; + static const int build = 570; + static const String engine = "3.13.5"; + static const String buildAt = "2023-09-21 10:20:10"; + static const int modifications = 4; + static const int script = 17; } diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart index 1b2cdc59..2be994bd 100644 --- a/lib/view/page/backup.dart +++ b/lib/view/page/backup.dart @@ -64,7 +64,7 @@ class BackupPage extends StatelessWidget { Icons.save, () async { await Backup.backup(); - await shareFiles(context, [await Paths.bak]); + await shareFiles([await Paths.bak]); }, ) ], diff --git a/lib/view/page/docker.dart b/lib/view/page/docker.dart index 521b8c3a..991afb8f 100644 --- a/lib/view/page/docker.dart +++ b/lib/view/page/docker.dart @@ -44,7 +44,7 @@ class _DockerManagePageState extends State { @override void initState() { super.initState(); - final client = widget.spi.findServer?.client; + final client = widget.spi.server?.client; if (client == null) { return; } diff --git a/lib/view/page/full_screen.dart b/lib/view/page/full_screen.dart index 96dd6f26..25366154 100644 --- a/lib/view/page/full_screen.dart +++ b/lib/view/page/full_screen.dart @@ -136,10 +136,9 @@ class _FullScreenPageState extends State with AfterLayoutMixin { } return PageView.builder( controller: _pageController, - itemCount: pro.servers.length, + itemCount: pro.serverOrder.length, itemBuilder: (_, idx) { - final id = pro.serverOrder[idx]; - final s = pro.servers[id]; + final s = pro.pick(id: pro.serverOrder[idx]); if (s == null) { return Center(child: Text(l10n.noClient)); } diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart index 37f3e24a..e053f8ec 100644 --- a/lib/view/page/ping.dart +++ b/lib/view/page/ping.dart @@ -166,7 +166,7 @@ class _PingPageState extends State return; } - if (Providers.server.servers.isEmpty) { + if (Providers.server.serverOrder.isEmpty) { context.showSnackBar(l10n.pingNoServer); return; } @@ -177,7 +177,7 @@ class _PingPageState extends State return; } - await Future.wait(Providers.server.servers.values.map((e) async { + await Future.wait(Providers.server.servers.map((e) async { if (e.client == null) { return; } @@ -197,7 +197,7 @@ class _PingPageState extends State @override Future> afterFirstLayout(BuildContext context) async { - if (Providers.server.servers.isEmpty) { + if (Providers.server.serverOrder.isEmpty) { await Providers.server.loadLocalData(); await Providers.server.refreshData(); } diff --git a/lib/view/page/process.dart b/lib/view/page/process.dart index c44bfcac..ee61935d 100644 --- a/lib/view/page/process.dart +++ b/lib/view/page/process.dart @@ -8,7 +8,6 @@ import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/uint8list.dart'; import 'package:toolbox/core/utils/misc.dart'; -import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; import '../../data/model/app/shell_func.dart'; @@ -45,7 +44,7 @@ class _ProcessPageState extends State { @override void initState() { super.initState(); - _client = Providers.server.servers[widget.spi.id]?.client; + _client = widget.spi.server?.client; final duration = Duration(seconds: Stores.setting.serverStatusUpdateInterval.fetch()); _timer = Timer.periodic(duration, (_) => _refresh()); @@ -59,7 +58,7 @@ class _ProcessPageState extends State { Future _refresh() async { if (mounted) { - final result = await _client?.run(AppShellFuncType.process.exec).string; + final result = await _client?.run(ShellFunc.process.exec).string; if (result == null || result.isEmpty) { context.showSnackBar(l10n.noResult); return; diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index 2eea2d6b..055b2775 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -68,7 +68,7 @@ class _ServerDetailPageState extends State @override Widget build(BuildContext context) { return Consumer(builder: (_, provider, __) { - final s = provider.servers[widget.spi.id]; + final s = widget.spi.server; if (s == null) { return Scaffold( body: Center( diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 43a31a91..5a8f863a 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -127,7 +127,7 @@ class _ServerPageState extends State if (index == count - 1) return UIs.height77; if (buildTags) index--; - return _buildEachServerCard(provider.servers[filtered[index]]); + return _buildEachServerCard(provider.pick(id: filtered[index])); }, ); } @@ -246,14 +246,14 @@ class _ServerPageState extends State children: [ IconButton( onPressed: () => srv.client?.execWithPwd( - AppShellFuncType.shutdown.cmd, + ShellFunc.shutdown.cmd, context: context, ), icon: const Icon(Icons.power_off), ), IconButton( onPressed: () => srv.client?.execWithPwd( - AppShellFuncType.reboot.cmd, + ShellFunc.reboot.cmd, context: context, ), icon: const Icon(Icons.refresh), @@ -456,16 +456,16 @@ class _ServerPageState extends State @override Future afterFirstLayout(BuildContext context) async { await GetIt.I.allReady(); - if (Providers.server.servers.isEmpty) { + if (Providers.server.serverOrder.isEmpty) { await Providers.server.loadLocalData(); } Providers.server.startAutoRefresh(); } List _filterServers(ServerProvider pro) => pro.serverOrder - .where((e) => pro.servers.containsKey(e)) + .where((e) => pro.serverOrder.contains(e)) .where((e) => - _tag == null || (pro.servers[e]?.spi.tags?.contains(_tag) ?? false)) + _tag == null || (pro.pick(id: e)?.spi.tags?.contains(_tag) ?? false)) .toList(); String _getTopRightStr( diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart index fa09e049..1a9d42b9 100644 --- a/lib/view/page/setting/entry.dart +++ b/lib/view/page/setting/entry.dart @@ -310,10 +310,13 @@ class _SettingPageState extends State { Widget _buildAppColor() { return ListTile( trailing: ClipOval( - child: Container( - color: primaryColor, - height: 27, - width: 27, + child: ValueBuilder( + listenable: _selectedColorValue, + build: () => Container( + color: primaryColor, + height: 27, + width: 27, + ), ), ), title: Text(l10n.primaryColorSeed), @@ -368,9 +371,11 @@ class _SettingPageState extends State { context.showSnackBar(l10n.failed); return; } + // Change [primaryColor] first, then change [_selectedColorValue], + // So the [ValueBuilder] will be triggered with the new value + primaryColor = color; _selectedColorValue.value = color.value; _setting.primaryColor.put(_selectedColorValue.value); - primaryColor = color; context.pop(); RebuildNodes.app.rebuild(); } diff --git a/lib/view/page/setting/srv_seq.dart b/lib/view/page/setting/srv_seq.dart index 9d88627f..11591fc5 100644 --- a/lib/view/page/setting/srv_seq.dart +++ b/lib/view/page/setting/srv_seq.dart @@ -47,7 +47,7 @@ class _ServerOrderPageState extends State { } Widget _buildItem(int index, String id) { - final spi = Providers.server.servers[id]?.spi; + final spi = Providers.server.pick(id: id)?.spi; if (spi == null) { return const SizedBox(); } diff --git a/lib/view/page/snippet/list.dart b/lib/view/page/snippet/list.dart index 685e286d..b6c458ab 100644 --- a/lib/view/page/snippet/list.dart +++ b/lib/view/page/snippet/list.dart @@ -130,7 +130,7 @@ class _SnippetListPageState extends State { final servers = await showDialog>( context: context, builder: (_) => TagPicker( - items: Providers.server.servers.values.toList(), + items: Providers.server.servers.toList(), tags: Providers.server.tags.toSet(), ), ); diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index 6c7e3958..9bb6bea0 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -289,7 +289,7 @@ class _LocalStoragePageState extends State { ], ); final id = ids[idx]; - final spi = Providers.server.servers[id]?.spi; + final spi = Providers.server.pick(id: id)?.spi; if (spi == null) { return; } @@ -313,7 +313,7 @@ class _LocalStoragePageState extends State { leading: const Icon(Icons.open_in_new), title: Text(l10n.open), onTap: () { - shareFiles(context, [file.absolute.path]); + shareFiles([file.absolute.path]); }, ), ], diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index a6e06128..60da42d0 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -33,12 +33,12 @@ import '../../widget/two_line_text.dart'; class SftpPage extends StatefulWidget { final ServerPrivateInfo spi; final String? initPath; - final bool selectPath; + final bool isSelect; const SftpPage({ Key? key, required this.spi, - required this.selectPath, + required this.isSelect, this.initPath, }) : super(key: key); @@ -47,20 +47,8 @@ class SftpPage extends StatefulWidget { } class _SftpPageState extends State with AfterLayoutMixin { - final SftpBrowserStatus _status = SftpBrowserStatus(); - - SSHClient? _client; - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - } - - @override - void initState() { - super.initState(); - _client = Providers.server.servers[widget.spi.id]?.client; - } + final _status = SftpBrowserStatus(); + late final _client = widget.spi.server?.client; @override Widget build(BuildContext context) { @@ -69,9 +57,7 @@ class _SftpPageState extends State with AfterLayoutMixin { leading: IconButton( icon: const BackButtonIcon(), onPressed: () { - if (_status.path != null) { - _status.path!.update('/'); - } + _status.path?.update('/'); context.pop(); }, ), @@ -102,7 +88,7 @@ class _SftpPageState extends State with AfterLayoutMixin { } Widget _buildBottom() { - final children = widget.selectPath + final children = widget.isSelect ? [ IconButton( onPressed: () => context.pop(_status.path?.path), @@ -195,13 +181,15 @@ class _SftpPageState extends State with AfterLayoutMixin { mainAxisSize: MainAxisSize.min, children: [ ListTile( - leading: const Icon(Icons.folder), - title: Text(l10n.createFolder), - onTap: () => _mkdir(context)), + leading: const Icon(Icons.folder), + title: Text(l10n.createFolder), + onTap: _mkdir, + ), ListTile( - leading: const Icon(Icons.insert_drive_file), - title: Text(l10n.createFile), - onTap: () => _newFile(context)), + leading: const Icon(Icons.insert_drive_file), + title: Text(l10n.createFile), + onTap: _newFile, + ), ], ), )), @@ -242,7 +230,7 @@ class _SftpPageState extends State with AfterLayoutMixin { } _status.path?.update(p); - final suc = await _listDir(path: p); + final suc = await _listDir(); if (suc && Stores.setting.recordHistory.fetch()) { Stores.history.sftpPath.add(p); } @@ -285,7 +273,7 @@ class _SftpPageState extends State with AfterLayoutMixin { Widget _buildItem(SftpName file) { final isDir = file.attr.isDirectory; final trailing = Text( - '${getTime(file.attr.modifyTime)}\n${file.attr.mode?.str ?? ''}', + '${_getTime(file.attr.modifyTime)}\n${file.attr.mode?.str ?? ''}', style: UIs.textGrey, textAlign: TextAlign.right, ); @@ -302,26 +290,26 @@ class _SftpPageState extends State with AfterLayoutMixin { onTap: () { if (isDir) { _status.path?.update(file.filename); - _listDir(path: _status.path?.path); + _listDir(); } else { - _onItemPress(context, file, true); + _onItemPress(file, true); } }, - onLongPress: () => _onItemPress(context, file, !isDir), + onLongPress: () => _onItemPress(file, !isDir), )); } - void _onItemPress(BuildContext context, SftpName file, bool notDir) { + void _onItemPress(SftpName file, bool notDir) { final children = [ ListTile( leading: const Icon(Icons.delete), title: Text(l10n.delete), - onTap: () => _delete(context, file), + onTap: () => _delete(file), ), ListTile( leading: const Icon(Icons.abc), title: Text(l10n.rename), - onTap: () => _rename(context, file), + onTap: () => _rename(file), ), ]; if (notDir) { @@ -329,19 +317,19 @@ class _SftpPageState extends State with AfterLayoutMixin { ListTile( leading: const Icon(Icons.edit), title: Text(l10n.edit), - onTap: () => _edit(context, file), + onTap: () => _edit(file), ), ListTile( leading: const Icon(Icons.download), title: Text(l10n.download), - onTap: () => _download(context, file), + onTap: () => _download(file), ), // Only show decompress option when the file is a compressed file if (_canDecompress(file.filename)) ListTile( leading: const Icon(Icons.folder_zip), title: Text(l10n.decompress), - onTap: () => _decompress(context, file), + onTap: () => _decompress(file), ), ]); } @@ -353,7 +341,7 @@ class _SftpPageState extends State with AfterLayoutMixin { ); } - Future _edit(BuildContext context, SftpName name) async { + Future _edit(SftpName name) async { final size = name.attr.size; if (size == null || size > Miscs.editorMaxSize) { context.showSnackBar(l10n.fileTooLarge( @@ -387,7 +375,7 @@ class _SftpPageState extends State with AfterLayoutMixin { } } - void _download(BuildContext context, SftpName name) { + void _download(SftpName name) { context.showRoundDialog( title: Text(l10n.attention), child: Text('${l10n.dl2Local(name.filename)}\n${l10n.keepForeground}'), @@ -418,7 +406,7 @@ class _SftpPageState extends State with AfterLayoutMixin { ); } - void _delete(BuildContext context, SftpName file) { + void _delete(SftpName file) { context.pop(); final isDir = file.attr.isDirectory; final useRmrf = Stores.setting.sftpRmrfDir.fetch(); @@ -469,7 +457,7 @@ class _SftpPageState extends State with AfterLayoutMixin { ); } - void _mkdir(BuildContext context) { + void _mkdir() { context.pop(); final textController = TextEditingController(); context.showRoundDialog( @@ -510,7 +498,7 @@ class _SftpPageState extends State with AfterLayoutMixin { ); } - void _newFile(BuildContext context) { + void _newFile() { context.pop(); final textController = TextEditingController(); context.showRoundDialog( @@ -550,7 +538,7 @@ class _SftpPageState extends State with AfterLayoutMixin { ); } - void _rename(BuildContext context, SftpName file) { + void _rename(SftpName file) { context.pop(); final textController = TextEditingController(); context.showRoundDialog( @@ -588,7 +576,7 @@ class _SftpPageState extends State with AfterLayoutMixin { ); } - Future _decompress(BuildContext context, SftpName name) async { + Future _decompress(SftpName name) async { context.pop(); final absPath = _getRemotePath(name); final cmd = _getDecompressCmd(absPath); @@ -621,15 +609,18 @@ class _SftpPageState extends State with AfterLayoutMixin { } /// Only return true if the path is changed - Future _listDir({String? path, SSHClient? client}) async { + Future _listDir() async { context.showLoadingDialog(); - if (client != null) { - final sftpc = await client.sftp(); + if (_status.client == null) { + final sftpc = await _client?.sftp(); _status.client = sftpc; } try { - final listPath = path ?? _status.path?.path ?? '/'; - final fs = await _status.client!.listdir(listPath); + final listPath = _status.path?.path ?? '/'; + final fs = await _status.client?.listdir(listPath); + if (fs == null) { + return false; + } fs.sort((a, b) => a.filename.compareTo(b.filename)); /// Issue #97 @@ -676,16 +667,15 @@ class _SftpPageState extends State with AfterLayoutMixin { } Future _backward() async { - if (_status.path!.undo()) { + if (_status.path?.undo() ?? false) { await _listDir(); } } @override FutureOr afterFirstLayout(BuildContext context) { - final p_ = widget.initPath ?? '/'; - _status.path = AbsolutePath(p_); - _listDir(path: p_, client: _client); + _status.path = AbsolutePath(widget.initPath ?? '/'); + _listDir(); } } @@ -754,3 +744,10 @@ const _extCmdMap = { 'obscpio': 'cpio -idmvF FILE', 'zpaq': 'zpaq x FILE', }; + +/// Return fmt: 2021-01-01 00:00:00 +String _getTime(int? unixMill) { + return DateTime.fromMillisecondsSinceEpoch((unixMill ?? 0) * 1000) + .toString() + .replaceFirst('.000', ''); +} diff --git a/lib/view/page/storage/sftp_mission.dart b/lib/view/page/storage/sftp_mission.dart index aa01a42c..b765e9ad 100644 --- a/lib/view/page/storage/sftp_mission.dart +++ b/lib/view/page/storage/sftp_mission.dart @@ -72,7 +72,7 @@ class _SftpMissionPageState extends State { }, icon: const Icon(Icons.file_open)), IconButton( - onPressed: () => shareFiles(context, [status.req.localPath]), + onPressed: () => shareFiles([status.req.localPath]), icon: const Icon(Icons.open_in_new), ) ], diff --git a/lib/view/widget/server_func_btns.dart b/lib/view/widget/server_func_btns.dart index ada5bf03..581382d1 100644 --- a/lib/view/widget/server_func_btns.dart +++ b/lib/view/widget/server_func_btns.dart @@ -188,7 +188,7 @@ Future _gotoSSH( } bool _checkClient(BuildContext context, String id) { - final server = Providers.server.servers[id]; + final server = Providers.server.pick(id: id); if (server == null || server.client == null) { context.showSnackBar(l10n.waitConnection); return false; @@ -197,7 +197,7 @@ bool _checkClient(BuildContext context, String id) { } Future _onPkg(BuildContext context, ServerPrivateInfo spi) async { - final server = spi.findServer; + final server = spi.server; if (server == null) { context.showSnackBar(l10n.noClient); return; diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 06d332f6..357f777f 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 = 569; + CURRENT_PROJECT_VERSION = 570; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; 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 = 569; + CURRENT_PROJECT_VERSION = 570; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; 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 = 569; + CURRENT_PROJECT_VERSION = 570; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.569; + MARKETING_VERSION = 1.0.570; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/pubspec.lock b/pubspec.lock index ad15aa21..48b92f73 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -211,7 +211,7 @@ packages: source: hosted version: "0.3.3+5" crypto: - dependency: "direct main" + dependency: transitive description: name: crypto sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab diff --git a/pubspec.yaml b/pubspec.yaml index ca0c0a20..75a4c686 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,7 +45,6 @@ dependencies: flutter_highlight: ^0.7.0 code_text_field: ^1.1.0 shared_preferences: ^2.1.1 - crypto: ^3.0.3 macos_window_utils: ^1.2.0 dynamic_color: ^1.6.6 icloud_storage: ^2.2.0