diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 42673bc1..bbd90cc7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,7 +1,39 @@ PODS: - countly_flutter (22.09.0): - Flutter + - DKImagePickerController/Core (4.3.4): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.4) + - DKImagePickerController/PhotoGallery (4.3.4): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.4) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery - Flutter - Flutter (1.0.0) - flutter_native_splash (0.0.1): @@ -13,8 +45,12 @@ PODS: - Flutter - r_upgrade (0.0.1): - Flutter + - SDWebImage (5.15.7): + - SDWebImage/Core (= 5.15.7) + - SDWebImage/Core (5.15.7) - share_plus (0.0.1): - Flutter + - SwiftyGif (5.4.4) - url_launcher_ios (0.0.1): - Flutter @@ -29,6 +65,13 @@ DEPENDENCIES: - share_plus (from `.symlinks/plugins/share_plus/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) +SPEC REPOS: + trunk: + - DKImagePickerController + - DKPhotoGallery + - SDWebImage + - SwiftyGif + EXTERNAL SOURCES: countly_flutter: :path: ".symlinks/plugins/countly_flutter/ios" @@ -51,15 +94,19 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: countly_flutter: 135f1a4930f8e26ba223a14201d3f265ea7b4c83 - file_picker: 1d63c4949e05e386da864365f8c13e1e64787675 + DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + file_picker: 63d7a9f5a3b5fe8fa001b1af955065e42a6c7b3e Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 plain_notification_token: b36467dc91939a7b6754267c701bbaca14996ee1 r_upgrade: 44d715c61914cce3d01ea225abffe894fd51c114 + SDWebImage: 25bac438318faf37e35650619ebc288a9061d292 share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 + SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 -PODFILE CHECKSUM: 7fb15c416f8685fca4966867a8da218ec592ec2e +PODFILE CHECKSUM: 8fb0b88ad9ca0fa16f109f46126189158d7c8607 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 606379e7..a3500791 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 295; + CURRENT_PROJECT_VERSION = 300; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -368,7 +368,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.295; + MARKETING_VERSION = 1.0.300; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -491,7 +491,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 295; + CURRENT_PROJECT_VERSION = 300; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -499,7 +499,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.295; + MARKETING_VERSION = 1.0.300; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -516,7 +516,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 295; + CURRENT_PROJECT_VERSION = 300; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -524,7 +524,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.295; + MARKETING_VERSION = 1.0.300; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/core/utils/misc.dart b/lib/core/utils/misc.dart index de4cd0fa..d336835f 100644 --- a/lib/core/utils/misc.dart +++ b/lib/core/utils/misc.dart @@ -26,21 +26,21 @@ Future shareFiles(BuildContext context, List filePaths) async { } else { text = '${filePaths.length} ${S.of(context)!.files}'; } - _app.setMoveBg(false); + _app.setCanMoveBg(false); // ignore: deprecated_member_use await Share.shareFiles(filePaths, text: 'ServerBox -> $text'); - _app.setMoveBg(true); + _app.setCanMoveBg(true); return filePaths.isNotEmpty; } -void copy(String text) { +void copy2Clipboard(String text) { Clipboard.setData(ClipboardData(text: text)); } Future pickOneFile() async { - _app.setMoveBg(false); + _app.setCanMoveBg(false); final result = await FilePicker.platform.pickFiles(type: FileType.any); - _app.setMoveBg(true); + _app.setCanMoveBg(true); return result?.files.single.path; } diff --git a/lib/data/provider/app.dart b/lib/data/provider/app.dart index 62feebc3..138254d6 100644 --- a/lib/data/provider/app.dart +++ b/lib/data/provider/app.dart @@ -12,7 +12,7 @@ class AppProvider extends BusyProvider { notifyListeners(); } - void setMoveBg(bool moveBg) { + void setCanMoveBg(bool moveBg) { _moveBg = moveBg; } } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 99ab0408..ad12bfd3 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -18,10 +18,31 @@ import '../store/server.dart'; import '../store/setting.dart'; typedef ServersMap = Map; +typedef ServerOrder = List; + +extension ServerOrderX on ServerOrder { + void move(int oldIndex, int newIndex) { + if (oldIndex == newIndex) return; + if (oldIndex < newIndex) { + newIndex -= 1; + } + final item = this[oldIndex]; + removeAt(oldIndex); + insert(newIndex, item); + locator().serverOrder.put(this); + } + + void update(String id, String newId) { + final index = indexOf(id); + if (index == -1) return; + this[index] = newId; + } +} class ServerProvider extends BusyProvider { final ServersMap _servers = {}; ServersMap get servers => _servers; + final ServerOrder serverOrder = []; final _limiter = TryLimiter(); @@ -29,14 +50,21 @@ class ServerProvider extends BusyProvider { final _logger = Logger('SERVER'); - final _store = locator(); + final _serverStore = locator(); + final _settingStore = locator(); Future loadLocalData() async { setBusyState(true); - final infos = _store.fetch(); + final infos = _serverStore.fetch(); for (final info in infos) { _servers[info.id] = genServer(info); } + final serverOrder_ = _settingStore.serverOrder.fetch(); + if (serverOrder_ != null) { + serverOrder.addAll(serverOrder_); + } else { + serverOrder.addAll(_servers.keys); + } setBusyState(false); notifyListeners(); } @@ -107,14 +135,18 @@ class ServerProvider extends BusyProvider { void addServer(ServerPrivateInfo spi) { _servers[spi.id] = genServer(spi); notifyListeners(); - _store.put(spi); + _serverStore.put(spi); + serverOrder.add(spi.id); + _settingStore.serverOrder.put(serverOrder); refreshData(spi: spi); } void delServer(String id) { _servers.remove(id); + serverOrder.remove(id); + _settingStore.serverOrder.put(serverOrder); notifyListeners(); - _store.delete(id); + _serverStore.delete(id); } Future updateServer( @@ -122,9 +154,11 @@ class ServerProvider extends BusyProvider { ServerPrivateInfo newSpi, ) async { _servers.remove(old.id); - _store.update(old, newSpi); + _serverStore.update(old, newSpi); _servers[newSpi.id] = genServer(newSpi); _servers[newSpi.id]?.client = await genClient(newSpi); + serverOrder.update(old.id, newSpi.id); + _settingStore.serverOrder.put(serverOrder); await refreshData(spi: newSpi); } diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 9256750a..dc9bb754 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,8 +2,8 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 295; + static const int build = 300; static const String engine = "3.10.0"; - static const String buildAt = "2023-05-11 12:17:12.803987"; - static const int modifications = 3; + static const String buildAt = "2023-05-12 16:42:47.988995"; + static const int modifications = 1; } diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index fb69649f..6ab0baf4 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -39,4 +39,8 @@ class SettingStore extends PersistentStore { /// Backgroud running (Android) StoreProperty get bgRun => property('bgRun', defaultValue: isAndroid); + + // Server order + StoreProperty> get serverOrder => + property('serverOrder', defaultValue: null); } diff --git a/lib/view/page/home.dart b/lib/view/page/home.dart index 79039bc1..0e9e175a 100644 --- a/lib/view/page/home.dart +++ b/lib/view/page/home.dart @@ -103,7 +103,7 @@ class _MyHomePageState extends State return Scaffold( drawer: _buildDrawer(), appBar: AppBar( - title: Text(tabTitleName(context, _selectIndex)), + title: const Text(BuildData.name), actions: [ IconButton( icon: const Icon(Icons.developer_mode, size: 23), diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 753eed9a..5ae9ca57 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -83,7 +83,7 @@ class _ServerPageState extends State await _serverProvider.refreshData(onlyFailed: true), child: Consumer( builder: (_, pro, __) { - if (pro.servers.isEmpty) { + if (pro.serverOrder.isEmpty) { return Center( child: Text( _s.serverTabEmpty, @@ -91,21 +91,16 @@ class _ServerPageState extends State ), ); } - final keys = pro.servers.keys.toList(); - return ListView.separated( + return ReorderableListView( padding: const EdgeInsets.fromLTRB(7, 10, 7, 7), - controller: ScrollController(), physics: const AlwaysScrollableScrollPhysics(), - itemBuilder: (ctx, idx) { - if (idx == pro.servers.length) { - return SizedBox(height: _media.padding.bottom); - } - return _buildEachServerCard(pro.servers[keys[idx]]); - }, - itemCount: pro.servers.length, - separatorBuilder: (_, __) => const SizedBox( - height: 3, - ), + onReorder: (oldIndex, newIndex) => setState(() { + pro.serverOrder.move(oldIndex, newIndex); + }), + children: pro.serverOrder + .where((e) => pro.servers.containsKey(e)) + .map((e) => _buildEachServerCard(pro.servers[e])) + .toList(), ); }, ), @@ -116,21 +111,18 @@ class _ServerPageState extends State if (si == null) { return const SizedBox(); } - return GestureDetector( - onLongPress: () => AppRoute( - ServerEditPage(spi: si.spi), - 'Edit server info page', - ).go(context), - child: RoundRectCard( - Padding( + return RoundRectCard( + GestureDetector( + child: Padding( padding: const EdgeInsets.all(13), child: _buildRealServerCard(si.status, si.spi.name, si.state, si.spi), ), + onTap: () => AppRoute( + ServerDetailPage(si.spi.id), + 'server detail page', + ).go(context), ), - onTap: () => AppRoute( - ServerDetailPage(si.spi.id), - 'server detail page', - ).go(context), + key: Key(si.spi.id), ); } @@ -177,8 +169,8 @@ class _ServerPageState extends State child: Text(ss.failedInfo ?? _s.unknownError), actions: [ TextButton( - onPressed: () => - copy(ss.failedInfo ?? _s.unknownError), + onPressed: () => copy2Clipboard( + ss.failedInfo ?? _s.unknownError), child: Text(_s.copy), ) ], diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index f855f344..90558c2a 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -427,7 +427,7 @@ class _SettingPageState extends State { padding: EdgeInsets.zero, onPressed: () { if (_pushToken != null) { - copy(_pushToken!); + copy2Clipboard(_pushToken!); showSnackBar(context, Text(_s.success)); } else { showSnackBar(context, Text(_s.getPushTokenFailed)); @@ -453,9 +453,10 @@ class _SettingPageState extends State { } Widget _buildFont() { + final fontName = getFileName(_setting.fontPath.fetch()); return ListTile( - title: Text(_s.chooseFontFile), - trailing: Text(getFileName(_setting.fontPath.fetch()) ?? _s.notSelected), + title: Text(_s.choose), + trailing: Text(fontName ?? _s.notSelected), onTap: () { showRoundDialog( context: context, diff --git a/lib/view/page/ssh.dart b/lib/view/page/ssh.dart index 6b5ba2bc..0e3b30b1 100644 --- a/lib/view/page/ssh.dart +++ b/lib/view/page/ssh.dart @@ -222,7 +222,10 @@ class _SSHPageState extends State { _paste(); break; case VirtualKeyFunc.copy: - copy(terminalSelected); + final selected = terminalSelected; + if (selected != null) { + copy2Clipboard(selected); + } break; case VirtualKeyFunc.snippet: showSnippetDialog(context, _s, (s) { @@ -241,10 +244,10 @@ class _SSHPageState extends State { }); } - String get terminalSelected { + String? get terminalSelected { final range = _terminalController.selection; if (range == null) { - return ''; + return null; } return _terminal.buffer.getText(range); } @@ -255,29 +258,30 @@ class _SSHPageState extends State { return; } final selected = terminalSelected; - if (selected.trim().isEmpty) { - // _menuController.show( - // context: context, - // contextMenuBuilder: (context) { - // return TextSelectionToolbar( - // anchorAbove: details.globalPosition, - // anchorBelow: details.globalPosition, - // children: [ - // TextButton( - // child: Text( - // _s.paste, - // style: _menuTextStyle, - // ), - // onPressed: () async { - // _paste(); - // _menuController.remove(); - // }, - // ) - // ], - // ); - // }, - // ); - return; + final children = [ + TextButton( + onPressed: () { + _paste(); + }, + child: Text(_s.paste), + ), + ]; + if (selected?.trim().isNotEmpty ?? false) { + children.add( + TextButton( + child: Text( + _s.copy, + style: _menuTextStyle, + ), + onPressed: () { + _terminalController.setSelection(null); + if (selected != null) { + copy2Clipboard(selected); + } + _menuController.remove(); + }, + ), + ); } _menuController.show( context: context, @@ -285,19 +289,7 @@ class _SSHPageState extends State { return TextSelectionToolbar( anchorAbove: details.globalPosition, anchorBelow: details.globalPosition, - children: [ - TextButton( - child: Text( - _s.copy, - style: _menuTextStyle, - ), - onPressed: () { - _terminalController.setSelection(null); - copy(selected); - _menuController.remove(); - }, - ), - ], + children: children, ); }, ); diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 8bfcdcc6..c740e770 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -10,7 +10,7 @@ PODS: DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) @@ -18,7 +18,7 @@ EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin share_plus: :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos url_launcher_macos: