From ee96f2696e1f1cc315332a5b4ce7945d5c77b909 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Tue, 16 Jan 2024 11:42:30 +0800 Subject: [PATCH] opt.: file view (#249) --- .dart_tool/flutter_gen/gen_l10n/l10n.dart | 12 ++++ .dart_tool/flutter_gen/gen_l10n/l10n_de.dart | 6 ++ .dart_tool/flutter_gen/gen_l10n/l10n_en.dart | 6 ++ .dart_tool/flutter_gen/gen_l10n/l10n_fr.dart | 6 ++ .dart_tool/flutter_gen/gen_l10n/l10n_id.dart | 6 ++ .dart_tool/flutter_gen/gen_l10n/l10n_zh.dart | 12 ++++ ios/Runner.xcodeproj/project.pbxproj | 36 +++++----- lib/core/extension/sftpfile.dart | 2 +- lib/data/res/build_data.dart | 6 +- lib/l10n/app_de.arb | 2 + lib/l10n/app_en.arb | 2 + lib/l10n/app_fr.arb | 2 + lib/l10n/app_id.arb | 2 + lib/l10n/app_zh.arb | 2 + lib/l10n/app_zh_tw.arb | 2 + lib/view/page/server/edit.dart | 6 +- lib/view/page/storage/local.dart | 66 +++++++++++++++++-- lib/view/page/storage/sftp.dart | 69 ++++++++++++++++++-- 18 files changed, 212 insertions(+), 33 deletions(-) diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart index 81dc54dd..cb9b6581 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart @@ -1348,6 +1348,12 @@ abstract class S { /// **'Shutdown'** String get shutdown; + /// No description provided for @size. + /// + /// In en, this message translates to: + /// **'Size'** + String get size; + /// No description provided for @snippet. /// /// In en, this message translates to: @@ -1474,6 +1480,12 @@ abstract class S { /// **'Theme mode'** String get themeMode; + /// No description provided for @time. + /// + /// In en, this message translates to: + /// **'Time'** + String get time; + /// No description provided for @times. /// /// In en, this message translates to: diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart index b126bcc2..63256704 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart @@ -654,6 +654,9 @@ class SDe extends S { @override String get shutdown => 'Abschaltung'; + @override + String get size => 'Größe'; + @override String get snippet => 'Snippet'; @@ -721,6 +724,9 @@ class SDe extends S { @override String get themeMode => 'Themen-Modus'; + @override + String get time => 'Zeit'; + @override String get times => 'x'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart index 92600b10..ca8998e1 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart @@ -654,6 +654,9 @@ class SEn extends S { @override String get shutdown => 'Shutdown'; + @override + String get size => 'Size'; + @override String get snippet => 'Snippet'; @@ -721,6 +724,9 @@ class SEn extends S { @override String get themeMode => 'Theme mode'; + @override + String get time => 'Time'; + @override String get times => 'Times'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart index dc806876..540870e5 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_fr.dart @@ -654,6 +654,9 @@ class SFr extends S { @override String get shutdown => 'Éteindre'; + @override + String get size => 'Taille'; + @override String get snippet => 'Extrait'; @@ -721,6 +724,9 @@ class SFr extends S { @override String get themeMode => 'Mode du thème'; + @override + String get time => 'L\'heure'; + @override String get times => 'Fois'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart index 5bac835a..439d097c 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart @@ -654,6 +654,9 @@ class SId extends S { @override String get shutdown => 'Matikan'; + @override + String get size => 'Ukuran'; + @override String get snippet => 'Snippet'; @@ -721,6 +724,9 @@ class SId extends S { @override String get themeMode => 'Mode tema'; + @override + String get time => 'Waktu'; + @override String get times => 'Waktu'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart index 7f629856..923df7a7 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart @@ -654,6 +654,9 @@ class SZh extends S { @override String get shutdown => '关机'; + @override + String get size => '大小'; + @override String get snippet => '代码片段'; @@ -721,6 +724,9 @@ class SZh extends S { @override String get themeMode => '主题模式'; + @override + String get time => '时间'; + @override String get times => '次'; @@ -1476,6 +1482,9 @@ class SZhTw extends SZh { @override String get shutdown => '关机'; + @override + String get size => '大小'; + @override String get snippet => '程式片段'; @@ -1543,6 +1552,9 @@ class SZhTw extends SZh { @override String get themeMode => '主題模式'; + @override + String get time => '時間'; + @override String get times => '次'; diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7b44ee55..13d2487a 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 = 703; + CURRENT_PROJECT_VERSION = 704; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -596,7 +596,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -730,7 +730,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -758,7 +758,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; 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.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; 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.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; 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.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -902,7 +902,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -943,7 +943,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.703; + MARKETING_VERSION = 1.0.704; 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 = 703; + CURRENT_PROJECT_VERSION = 704; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -981,7 +981,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.703; + MARKETING_VERSION = 1.0.704; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; diff --git a/lib/core/extension/sftpfile.dart b/lib/core/extension/sftpfile.dart index 3e1f867d..9db3bb56 100644 --- a/lib/core/extension/sftpfile.dart +++ b/lib/core/extension/sftpfile.dart @@ -1,6 +1,6 @@ import 'package:dartssh2/dartssh2.dart'; -extension SftpFile on SftpFileMode { +extension SftpFileX on SftpFileMode { String get str { final user = _getRoleMode(userRead, userWrite, userExecute); final group = _getRoleMode(groupRead, groupWrite, groupExecute); diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index c0e592fb..07f84695 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 = 703; + static const int build = 704; static const String engine = "3.16.7"; - static const String buildAt = "2024-01-14 19:40:49"; - static const int modifications = 6; + static const String buildAt = "2024-01-15 18:40:44"; + static const int modifications = 3; static const int script = 34; } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 2c8d8cc4..c3f466ec 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -208,6 +208,7 @@ "sftpSSHConnected": "SFTP Verbunden", "showDistLogo": "Distributionslogo anzeigen", "shutdown": "Abschaltung", + "size": "Größe", "snippet": "Snippet", "speed": "Tempo", "spentTime": "Benötigte Zeit: {time}", @@ -229,6 +230,7 @@ "textScalerTip": "1.0 => 100% (Originalgröße), funktioniert nur auf der Serverseite Teil der Schrift, nicht empfohlen zu ändern.", "theme": "Themen", "themeMode": "Themen-Modus", + "time": "Zeit", "times": "x", "traffic": "Durchflussmenge", "ttl": "ttl", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 5395218f..d405c006 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -208,6 +208,7 @@ "sftpSSHConnected": "SFTP Connected", "showDistLogo": "Show distribution logo", "shutdown": "Shutdown", + "size": "Size", "snippet": "Snippet", "speed": "Speed", "spentTime": "Spent time: {time}", @@ -229,6 +230,7 @@ "textScalerTip": "1.0 => 100% (original size), only works on server page part of the font, not recommended to change.", "theme": "Theme", "themeMode": "Theme mode", + "time": "Time", "times": "Times", "traffic": "Traffic", "ttl": "ttl", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index d70ed2cd..b283c369 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -208,6 +208,7 @@ "sftpSSHConnected": "SFTP connecté", "showDistLogo": "Afficher le logo de la distribution", "shutdown": "Éteindre", + "size": "Taille", "snippet": "Extrait", "speed": "Vitesse", "spentTime": "Temps écoulé : {time}", @@ -229,6 +230,7 @@ "textScalerTip": "1.0 => 100% (taille d'origine), fonctionne uniquement sur la partie police de caractères de la page du serveur, il n'est pas recommandé de la modifier.", "theme": "Thème", "themeMode": "Mode du thème", + "time": "L'heure", "times": "Fois", "traffic": "Trafic", "ttl": "ttl", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 9674dc87..5eafbf74 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -208,6 +208,7 @@ "sftpSSHConnected": "Sftp terhubung", "showDistLogo": "Tampilkan logo distribusi", "shutdown": "Matikan", + "size": "Ukuran", "snippet": "Snippet", "speed": "Kecepatan", "spentTime": "Menghabiskan waktu: {time}", @@ -229,6 +230,7 @@ "textScalerTip": "1.0 => 100% (ukuran asli), hanya berfungsi pada bagian halaman server font, tidak disarankan untuk diubah.", "theme": " Tema", "themeMode": "Mode tema", + "time": "Waktu", "times": "Waktu", "traffic": "Lalu lintas", "ttl": "ttl", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 6286e261..2af2911d 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -208,6 +208,7 @@ "sftpSSHConnected": "SFTP 已连接...", "showDistLogo": "显示发行版 Logo", "shutdown": "关机", + "size": "大小", "snippet": "代码片段", "speed": "速度", "spentTime": "耗时: {time}", @@ -229,6 +230,7 @@ "textScalerTip": "1.0 => 100%(原大小),仅作用于服务器页面部分字体,不建议修改。", "theme": "主题", "themeMode": "主题模式", + "time": "时间", "times": "次", "traffic": "流量", "ttl": "缓存时间", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 63f97eb5..a5b46320 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -208,6 +208,7 @@ "sftpSSHConnected": "SFTP 已連接...", "showDistLogo": "顯示發行版 Logo", "shutdown": "关机", + "size": "大小", "snippet": "程式片段", "speed": "速度", "spentTime": "耗時: {time}", @@ -229,6 +230,7 @@ "textScalerTip": "1.0 => 100%(原大小),僅作用於伺服器頁面部分字體,不建議修改。", "theme": "主題", "themeMode": "主題模式", + "time": "時間", "times": "次", "traffic": "流量", "ttl": "緩存時間", diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index a320f42c..a34fa8f7 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -132,7 +132,7 @@ class _ServerEditPageState extends State { () => delScripts = !delScripts, ), controlAffinity: ListTileControlAffinity.leading, - subtitle: Text(l10n.deleteScripts), + title: Text(l10n.deleteScripts), tileColor: Colors.transparent, contentPadding: EdgeInsets.zero, ) @@ -142,13 +142,15 @@ class _ServerEditPageState extends State { actions: [ TextButton( onPressed: () async { + context.pop(); if (delScripts) { + context.showLoadingDialog(); const cmd = 'rm ${ShellFunc.srvBoxDir}/mobile_v*.sh'; await widget.spi?.server?.client?.run(cmd); + context.pop(); } Pros.server.delServer(widget.spi!.id); - context.pop(); context.pop(true); }, child: Text(l10n.ok, style: UIs.textRed), diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index 83596eae..3ad07f1c 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -39,6 +39,8 @@ class LocalStoragePage extends StatefulWidget { class _LocalStoragePageState extends State { LocalPath? _path; + final _sortType = ValueNotifier(_SortType.name); + @override void initState() { super.initState(); @@ -73,12 +75,44 @@ class _LocalStoragePageState extends State { IconButton( icon: const Icon(Icons.downloading), onPressed: () => AppRoute.sftpMission().go(context), - ) + ), + ValueListenableBuilder<_SortType>( + valueListenable: _sortType, + builder: (context, value, child) { + return PopupMenuButton<_SortType>( + icon: const Icon(Icons.sort), + itemBuilder: (context) { + return [ + PopupMenuItem( + value: _SortType.name, + child: Text(l10n.name), + ), + PopupMenuItem( + value: _SortType.size, + child: Text(l10n.size), + ), + PopupMenuItem( + value: _SortType.time, + child: Text(l10n.time), + ), + ]; + }, + onSelected: (value) { + _sortType.value = value; + }, + ); + }, + ), ], ), body: FadeIn( key: UniqueKey(), - child: _buildBody(), + child: ValueListenableBuilder( + valueListenable: _sortType, + builder: (_, val, __) { + return _buildBody(); + }, + ), ), bottomNavigationBar: SafeArea(child: _buildPath()), ); @@ -129,7 +163,8 @@ class _LocalStoragePageState extends State { ); } final dir = Directory(_path!.path); - final files = dir.listSync(); + final tempFiles = dir.listSync(); + final files = _sortType.value.sort(tempFiles); return ListView.builder( itemCount: files.length, padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 7), @@ -142,7 +177,7 @@ class _LocalStoragePageState extends State { return CardX( child: ListTile( leading: isDir - ? const Icon(Icons.folder) + ? const Icon(Icons.folder_open) : const Icon(Icons.insert_drive_file), title: Text(fileName), subtitle: isDir @@ -350,3 +385,26 @@ class _LocalStoragePageState extends State { ); } } + +enum _SortType { + name, + size, + time, + ; + + List sort(List files) { + switch (this) { + case _SortType.name: + files.sort((a, b) => a.path.compareTo(b.path)); + break; + case _SortType.size: + files.sort((a, b) => a.statSync().size.compareTo(b.statSync().size)); + break; + case _SortType.time: + files.sort( + (a, b) => a.statSync().modified.compareTo(b.statSync().modified)); + break; + } + return files; + } +} diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index 8f6c7ed7..d4b75f3d 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -50,6 +50,8 @@ class _SftpPageState extends State with AfterLayoutMixin { final _status = SftpBrowserStatus(); late final _client = widget.spi.server?.client; + final _sortType = ValueNotifier(_SortType.name); + @override Widget build(BuildContext context) { return Scaffold( @@ -67,6 +69,33 @@ class _SftpPageState extends State with AfterLayoutMixin { icon: const Icon(Icons.downloading), onPressed: () => AppRoute.sftpMission().go(context), ), + ValueListenableBuilder<_SortType>( + valueListenable: _sortType, + builder: (context, value, child) { + return PopupMenuButton<_SortType>( + icon: const Icon(Icons.sort), + itemBuilder: (context) { + return [ + PopupMenuItem( + value: _SortType.name, + child: Text(l10n.name), + ), + PopupMenuItem( + value: _SortType.size, + child: Text(l10n.size), + ), + PopupMenuItem( + value: _SortType.time, + child: Text(l10n.time), + ), + ]; + }, + onSelected: (value) { + _sortType.value = value; + }, + ); + }, + ), ], ), body: _buildFileView(), @@ -244,10 +273,16 @@ class _SftpPageState extends State with AfterLayoutMixin { return RefreshIndicator( child: FadeIn( key: Key(widget.spi.name + _status.path!.path), - child: ListView.builder( - itemCount: _status.files!.length, - padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3), - itemBuilder: (_, index) => _buildItem(_status.files![index]), + child: ValueListenableBuilder( + valueListenable: _sortType, + builder: (_, sortType, __) { + final files = sortType.sort(_status.files!); + return ListView.builder( + itemCount: files.length, + padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3), + itemBuilder: (_, index) => _buildItem(files[index]), + ); + }, ), ), onRefresh: () => _listDir(), @@ -263,7 +298,7 @@ class _SftpPageState extends State with AfterLayoutMixin { ); return CardX( child: ListTile( - leading: Icon(isDir ? Icons.folder : Icons.insert_drive_file), + leading: Icon(isDir ? Icons.folder_outlined : Icons.insert_drive_file), title: Text(file.filename), trailing: trailing, subtitle: isDir @@ -755,3 +790,27 @@ String _getTime(int? unixMill) { .toString() .replaceFirst('.000', ''); } + +enum _SortType { + name, + time, + size, + ; + + List sort(List files) { + switch (this) { + case _SortType.name: + files.sort((a, b) => a.filename.compareTo(b.filename)); + break; + case _SortType.time: + files.sort( + (a, b) => (a.attr.modifyTime ?? 0).compareTo(b.attr.modifyTime ?? 0), + ); + break; + case _SortType.size: + files.sort((a, b) => (a.attr.size ?? 0).compareTo(b.attr.size ?? 0)); + break; + } + return files; + } +}