diff --git a/analysis_options.yaml b/analysis_options.yaml index 2c7afe2b..77e849e0 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -24,6 +24,7 @@ linter: rules: library_private_types_in_public_api: false use_build_context_synchronously: false + depend_on_referenced_packages: false prefer_final_locals: true unnecessary_parenthesis: true implicit_call_tearoffs: true diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ec9372dd..2b0e38f7 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -690,7 +690,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -700,7 +700,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -826,7 +826,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -836,7 +836,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -854,7 +854,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -864,7 +864,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -885,7 +885,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -898,7 +898,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -924,7 +924,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -937,7 +937,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -960,7 +960,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -973,7 +973,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -996,7 +996,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1008,7 +1008,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; @@ -1037,7 +1037,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1049,7 +1049,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; @@ -1075,7 +1075,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_PREVIEWS = YES; @@ -1087,7 +1087,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_NAME = ServerBox; diff --git a/lib/app.dart b/lib/app.dart index b2db5c4f..20cfd108 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,12 +1,9 @@ import 'package:dynamic_color/dynamic_color.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:toolbox/core/analysis.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/locale.dart'; import 'package:toolbox/core/utils/ui.dart'; import 'package:toolbox/data/res/build_data.dart'; -import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/rebuild.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/view/page/home/home.dart'; @@ -21,7 +18,7 @@ class MyApp extends StatelessWidget { listenable: RebuildNodes.app, builder: (_, __) { if (!Stores.setting.useSystemPrimaryColor.fetch()) { - primaryColor = Color(Stores.setting.primaryColor.fetch()); + UIs.colorSeed = Color(Stores.setting.primaryColor.fetch()); return _buildApp(); } return DynamicColorBuilder( @@ -36,9 +33,9 @@ class MyApp extends StatelessWidget { colorScheme: dark, ); if (context.isDark && light != null) { - primaryColor = light.primary; + UIs.primaryColor = light.primary; } else if (!context.isDark && dark != null) { - primaryColor = dark.primary; + UIs.primaryColor = dark.primary; } return _buildApp(light: lightTheme, dark: darkTheme); }, @@ -59,12 +56,12 @@ class MyApp extends StatelessWidget { light ??= ThemeData( useMaterial3: true, - colorSchemeSeed: primaryColor, + colorSchemeSeed: UIs.colorSeed, ); dark ??= ThemeData( useMaterial3: true, brightness: Brightness.dark, - colorSchemeSeed: primaryColor, + colorSchemeSeed: UIs.colorSeed, ); return MaterialApp( @@ -88,7 +85,10 @@ class MyApp extends StatelessWidget { void _setup(BuildContext context) async { setTransparentNavigationBar(context); - Analysis.init(); + Analysis.init( + 'https://countly.lolli.tech', + '0772e65c696709f879d87db77ae1a811259e3eb9', + ); } ThemeData _getAmoledTheme(ThemeData darkTheme) => darkTheme.copyWith( diff --git a/lib/core/analysis.dart b/lib/core/analysis.dart deleted file mode 100644 index 1caaad57..00000000 --- a/lib/core/analysis.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'dart:async'; - -import 'package:countly_flutter/countly_flutter.dart'; -import 'package:toolbox/core/build_mode.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/data/res/store.dart'; - -class Analysis { - static const _url = 'https://countly.lolli.tech'; - static const _key = '0772e65c696709f879d87db77ae1a811259e3eb9'; - - static bool enabled = false; - - static Future init() async { - if (enabled) return; - if (!BuildMode.isRelease) return; - if (!Stores.setting.collectUsage.fetch()) return; - if (isAndroid || isIOS) { - enabled = true; - final config = CountlyConfig(_url, _key) - .setLoggingEnabled(false) - .enableCrashReporting(); - await Countly.initWithConfig(config); - await Countly.giveAllConsent(); - } - } - - static void recordView(String view) { - if (enabled) { - Countly.instance.views.startView(view); - } - } - - static void recordException(Object exception, [bool fatal = false]) { - if (enabled) { - Countly.logException(exception.toString(), !fatal, null); - } - } -} diff --git a/lib/core/build_mode.dart b/lib/core/build_mode.dart deleted file mode 100644 index 1cc8f982..00000000 --- a/lib/core/build_mode.dart +++ /dev/null @@ -1,25 +0,0 @@ -/// See: https://github.com/flutter/flutter/issues/11392 -/// -enum _BuildMode { - release, - debug, - profile, -} - -final _buildMode = () { - if (const bool.fromEnvironment('dart.vm.product')) { - return _BuildMode.release; - } - var result = _BuildMode.profile; - assert(() { - result = _BuildMode.debug; - return true; - }()); - return result; -}(); - -class BuildMode { - static bool isDebug = (_buildMode == _BuildMode.debug); - static bool isProfile = (_buildMode == _BuildMode.profile); - static bool isRelease = (_buildMode == _BuildMode.release); -} diff --git a/lib/core/extension/colorx.dart b/lib/core/extension/colorx.dart deleted file mode 100644 index 003339f6..00000000 --- a/lib/core/extension/colorx.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter/material.dart'; - -const _interactiveStates = { - MaterialState.pressed, - MaterialState.hovered, - MaterialState.focused, - MaterialState.selected -}; - -extension ColorX on Color { - String get toHex { - final redStr = red.toRadixString(16).padLeft(2, '0'); - final greenStr = green.toRadixString(16).padLeft(2, '0'); - final blueStr = blue.toRadixString(16).padLeft(2, '0'); - return '#$redStr$greenStr$blueStr'; - } - - bool get isBrightColor { - return getBrightnessFromColor == Brightness.light; - } - - Brightness get getBrightnessFromColor { - return ThemeData.estimateBrightnessForColor(this); - } - - MaterialStateProperty get materialStateColor { - return MaterialStateProperty.resolveWith((states) { - if (states.any(_interactiveStates.contains)) { - return this; - } - return null; - }); - } - - MaterialColor get materialColor => MaterialColor( - value, - { - 50: withOpacity(0.05), - 100: withOpacity(0.1), - 200: withOpacity(0.2), - 300: withOpacity(0.3), - 400: withOpacity(0.4), - 500: withOpacity(0.5), - 600: withOpacity(0.6), - 700: withOpacity(0.7), - 800: withOpacity(0.8), - 900: withOpacity(0.9), - }, - ); -} diff --git a/lib/core/extension/context/common.dart b/lib/core/extension/context/common.dart deleted file mode 100644 index 30ba715f..00000000 --- a/lib/core/extension/context/common.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; - -extension ContextX on BuildContext { - void pop([T? result]) { - Navigator.of(this).pop(result); - } - - bool get canPop => Navigator.of(this).canPop(); - - bool get isDark => Theme.of(this).brightness == Brightness.dark; -} diff --git a/lib/core/extension/context/dialog.dart b/lib/core/extension/context/dialog.dart deleted file mode 100644 index 4736d0a2..00000000 --- a/lib/core/extension/context/dialog.dart +++ /dev/null @@ -1,232 +0,0 @@ -import 'dart:async'; - -import 'package:choice/choice.dart'; -import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/choice_chip.dart'; -import 'package:toolbox/view/widget/tag.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; - -import '../../../data/res/ui.dart'; -import '../../../view/widget/input_field.dart'; - -extension DialogX on BuildContext { - Future showRoundDialog({ - Widget? child, - List? actions, - Widget? title, - bool barrierDismiss = true, - void Function(BuildContext)? onContext, - }) async { - return await showDialog( - context: this, - barrierDismissible: barrierDismiss, - builder: (ctx) { - onContext?.call(ctx); - return AlertDialog( - title: title, - content: child, - actions: actions, - actionsPadding: const EdgeInsets.all(17), - ); - }, - ); - } - - Future showLoadingDialog({ - required Future Function() fn, - bool barrierDismiss = false, - }) async { - BuildContext? ctx; - showRoundDialog( - child: UIs.centerSizedLoading, - barrierDismiss: barrierDismiss, - onContext: (c) => ctx = c, - ); - - try { - return await fn(); - } catch (e) { - rethrow; - } finally { - /// Wait for context to be unmounted - await Future.delayed(const Duration(milliseconds: 100)); - if (ctx?.mounted == true) { - ctx?.pop(); - } - } - } - - static final _recoredPwd = {}; - - /// Show a dialog to input password - /// - /// [hostId] set it to null to skip remembering the password - Future showPwdDialog({ - String? hostId, - String? title, - String? label, - }) async { - if (!mounted) return null; - return await showRoundDialog( - title: Text(title ?? hostId ?? l10n.pwd), - child: Input( - controller: TextEditingController(text: _recoredPwd[hostId]), - autoFocus: true, - type: TextInputType.visiblePassword, - obscureText: true, - onSubmitted: (val) { - pop(val); - if (hostId != null && Stores.setting.rememberPwdInMem.fetch()) { - _recoredPwd[hostId] = val; - } - }, - label: label ?? l10n.pwd, - ), - ); - } - - Future?> showPickDialog({ - required List items, - String Function(T)? name, - bool multi = true, - List? initial, - bool clearable = false, - List? actions, - }) async { - var vals = initial ?? []; - final sure = await showRoundDialog( - title: Text(l10n.choose), - child: SingleChildScrollView( - child: Choice( - onChanged: (value) => vals = value, - multiple: multi, - clearable: clearable, - value: vals, - builder: (state, _) { - return Wrap( - children: List.generate( - items.length, - (index) { - final item = items[index]; - if (item == null) return UIs.placeholder; - return ChoiceChipX( - label: name?.call(item) ?? item.toString(), - state: state, - value: item, - ); - }, - ), - ); - }, - ), - ), - actions: [ - if (actions != null) ...actions, - TextButton( - onPressed: () => pop(true), - child: Text(l10n.ok), - ), - ], - ); - if (sure == true && vals.isNotEmpty) { - return vals; - } - return null; - } - - Future showPickSingleDialog({ - required List items, - String Function(T)? name, - T? initial, - bool clearable = false, - List? actions, - }) async { - final vals = await showPickDialog( - items: items, - name: name, - multi: false, - initial: initial == null ? null : [initial], - actions: actions, - ); - if (vals != null && vals.isNotEmpty) { - return vals.first; - } - return null; - } - - Future?> showPickWithTagDialog({ - required List Function(String? tag) itemsBuilder, - required ValueNotifier> tags, - String Function(T)? name, - List? initial, - bool clearable = false, - bool multi = false, - List? actions, - }) async { - var vals = initial ?? []; - final tag = ValueNotifier(null); - final sure = await showRoundDialog( - title: Text(l10n.choose), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListenableBuilder( - listenable: tag, - builder: (_, __) => TagSwitcher( - tags: tags, - width: 300, - initTag: tag.value, - onTagChanged: (e) => tag.value = e, - ), - ), - const Divider(), - SingleChildScrollView( - child: ValBuilder( - listenable: tag, - builder: (val) { - final items = itemsBuilder(val); - return Choice( - onChanged: (value) => vals = value, - multiple: multi, - clearable: clearable, - value: vals, - builder: (state, _) { - return Wrap( - children: List.generate( - items.length, - (index) { - final item = items[index]; - if (item == null) return UIs.placeholder; - return ChoiceChipX( - label: name?.call(item) ?? item.toString(), - state: state, - value: item, - ); - }, - ), - ); - }, - ); - }, - ), - ) - ], - ), - actions: [ - if (actions != null) ...actions, - TextButton( - onPressed: () => pop(true), - child: Text(l10n.ok), - ), - ], - ); - if (sure == true && vals.isNotEmpty) { - return vals; - } - return null; - } -} diff --git a/lib/core/extension/context/snackbar.dart b/lib/core/extension/context/snackbar.dart deleted file mode 100644 index b77bd994..00000000 --- a/lib/core/extension/context/snackbar.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter/material.dart'; - -extension SnackBarX on BuildContext { - void showSnackBar(String text) => - ScaffoldMessenger.of(this).showSnackBar(SnackBar( - content: Text(text), - behavior: SnackBarBehavior.floating, - )); - - void showSnackBarWithAction( - String content, - String action, - GestureTapCallback onTap, - ) { - ScaffoldMessenger.of(this).showSnackBar(SnackBar( - content: Text(content), - behavior: SnackBarBehavior.floating, - action: SnackBarAction( - label: action, - onPressed: onTap, - ), - )); - } -} diff --git a/lib/core/extension/datetime.dart b/lib/core/extension/datetime.dart deleted file mode 100644 index b6af20ec..00000000 --- a/lib/core/extension/datetime.dart +++ /dev/null @@ -1,15 +0,0 @@ -extension DateTimeX on DateTime { - String get hourMinute { - return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}'; - } - - /// Format: 2021-01-01-0000 - String get numStr { - final year = this.year.toString(); - final month = this.month.toString().padLeft(2, '0'); - final day = this.day.toString().padLeft(2, '0'); - final hour = this.hour.toString().padLeft(2, '0'); - final minute = this.minute.toString().padLeft(2, '0'); - return '$year-$month-$day-$hour$minute'; - } -} diff --git a/lib/core/extension/duration.dart b/lib/core/extension/duration.dart deleted file mode 100644 index fcfc2787..00000000 --- a/lib/core/extension/duration.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:toolbox/core/extension/context/locale.dart'; - -extension DurationX on Duration { - String get toStr { - final days = inDays; - if (days > 0) { - return '$days ${l10n.day}'; - } - final hours = inHours % 24; - if (hours > 0) { - return '$hours ${l10n.hour}'; - } - final minutes = inMinutes % 60; - if (minutes > 0) { - return '$minutes ${l10n.minute}'; - } - final seconds = inSeconds % 60; - return '$seconds ${l10n.second}'; - } -} diff --git a/lib/core/extension/enum.dart b/lib/core/extension/enum.dart deleted file mode 100644 index 10119f63..00000000 --- a/lib/core/extension/enum.dart +++ /dev/null @@ -1,12 +0,0 @@ -extension EnumListX on List { - T fromIndex(int index, [T? defaultValue]) { - try { - return this[index]; - } catch (e) { - if (defaultValue != null) { - return defaultValue; - } - throw Exception('Invalid index: $index'); - } - } -} diff --git a/lib/core/extension/listx.dart b/lib/core/extension/listx.dart deleted file mode 100644 index 32af008f..00000000 --- a/lib/core/extension/listx.dart +++ /dev/null @@ -1,37 +0,0 @@ -extension ListX on List { - List joinWith(T item, [bool self = true]) { - final list = self ? this : List.from(this); - for (var i = length - 1; i > 0; i--) { - list.insert(i, item); - } - return list; - } - - List combine(List other, [bool self = true]) { - final list = self ? this : List.from(this); - for (var i = 0; i < length; i++) { - list[i] = other[i]; - } - return list; - } - - T? get firstOrNull => isEmpty ? null : first; - - T? get lastOrNull => isEmpty ? null : last; - - T? firstWhereOrNull(bool Function(T element) test) { - try { - return firstWhere(test); - } catch (_) { - return null; - } - } - - T? lastWhereOrNull(bool Function(T element) test) { - try { - return lastWhere(test); - } catch (_) { - return null; - } - } -} diff --git a/lib/core/extension/locale.dart b/lib/core/extension/locale.dart deleted file mode 100644 index eb0fc504..00000000 --- a/lib/core/extension/locale.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter/material.dart'; - -extension LocaleX on Locale { - String get code { - if (countryCode == null) { - return languageCode; - } - return '${languageCode}_$countryCode'; - } -} - -extension String2Locale on String { - Locale? get toLocale { - // Issue #151 - if (isEmpty) { - return null; - } - final parts = split('_'); - if (parts.length == 1) { - return Locale(parts[0]); - } - return Locale(parts[0], parts[1]); - } -} diff --git a/lib/core/extension/media_queryx.dart b/lib/core/extension/media_queryx.dart deleted file mode 100644 index b02c815c..00000000 --- a/lib/core/extension/media_queryx.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/widgets.dart'; - -extension MideaQueryX on MediaQueryData { - bool get useDoubleColumn => size.width > 639; -} diff --git a/lib/core/extension/numx.dart b/lib/core/extension/numx.dart deleted file mode 100644 index 2fe0e538..00000000 --- a/lib/core/extension/numx.dart +++ /dev/null @@ -1,40 +0,0 @@ -extension NumX on num { - String get bytes2Str { - const suffix = ['B', 'KB', 'MB', 'GB', 'TB']; - double value = toDouble(); - int squareTimes = 0; - for (; value / 1024 > 1 && squareTimes < suffix.length - 1; squareTimes++) { - value /= 1024; - } - var finalValue = value.toStringAsFixed(1); - if (finalValue.endsWith('.0')) { - finalValue = finalValue.replaceFirst('.0', ''); - } - return '$finalValue ${suffix[squareTimes]}'; - } - - String get kb2Str => (this * 1024).bytes2Str; -} - -extension BigIntX on BigInt { - String get bytes2Str { - const suffix = ['B', 'KB', 'MB', 'GB', 'TB']; - double value = toDouble(); - int squareTimes = 0; - for (; value / 1024 > 1 && squareTimes < suffix.length - 1; squareTimes++) { - value /= 1024; - } - var finalValue = value.toStringAsFixed(1); - if (finalValue.endsWith('.0')) { - finalValue = finalValue.replaceFirst('.0', ''); - } - return '$finalValue ${suffix[squareTimes]}'; - } - - String get kb2Str => (this * BigInt.from(1024)).bytes2Str; -} - -extension IntX on int { - Duration secondsToDuration() => Duration(seconds: this); - DateTime get tsToDateTime => DateTime.fromMillisecondsSinceEpoch(this * 1000); -} diff --git a/lib/core/extension/order.dart b/lib/core/extension/order.dart deleted file mode 100644 index 200225b5..00000000 --- a/lib/core/extension/order.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:toolbox/core/extension/listx.dart'; -import 'package:toolbox/core/persistant_store.dart'; - -typedef _OnMove = void Function(List); - -extension OrderX on List { - void move( - int oldIndex, - int newIndex, { - StorePropertyBase>? property, - _OnMove? onMove, - }) { - if (oldIndex == newIndex) return; - if (oldIndex < newIndex) { - newIndex -= 1; - } - final item = this[oldIndex]; - removeAt(oldIndex); - insert(newIndex, item); - property?.put(this); - onMove?.call(this); - } - - void update(T id, T newId) { - final index = indexOf(id); - if (index == -1) return; - this[index] = newId; - } - - int index(T id) { - return indexOf(id); - } - - void moveByItem( - int o, - int n, { - /// The list after filtering. - /// - /// It's used to find the index of the item. - List? filtered, - StorePropertyBase>? property, - _OnMove? onMove, - }) { - if (o == n) return; - if (o < n) { - n -= 1; - } - final index = indexOf((filtered ?? this)[o]); - if (index == -1) return; - var newIndex = indexOf((filtered ?? this)[n]); - if (newIndex == -1) return; - if (o < n) { - newIndex += 1; - } - move(index, newIndex, property: property, onMove: onMove); - } - - /// order: ['d', 'b', 'e'] - /// this: ['a', 'b', 'c', 'd']\ - /// result: ['d', 'b', 'a', 'c']\ - /// return: ['e'] - List reorder({ - required List order, - required bool Function(T, String) finder, - }) { - final newOrder = []; - final missed = []; - final surplus = []; - for (final id in order.toSet()) { - final item = firstWhereOrNull((element) => finder(element, id)); - if (item == null) { - surplus.add(id); - } else { - newOrder.add(item); - } - } - for (final item in this) { - if (!newOrder.contains(item)) { - missed.add(item); - } - } - clear(); - addAll(newOrder); - addAll(missed); - return surplus; - } - - /// Dart uses memory address to compare objects by default. - /// This method compares the values of the objects. - bool equals(List other) { - if (length != other.length) return false; - for (var i = 0; i < length; i++) { - if (this[i] != other[i]) return false; - } - return true; - } -} diff --git a/lib/core/extension/ssh_client.dart b/lib/core/extension/ssh_client.dart index e7771fec..cddca03e 100644 --- a/lib/core/extension/ssh_client.dart +++ b/lib/core/extension/ssh_client.dart @@ -2,10 +2,8 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:dartssh2/dartssh2.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/widgets.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; -import 'package:toolbox/core/extension/stringx.dart'; -import 'package:toolbox/core/extension/uint8list.dart'; import '../../data/res/misc.dart'; @@ -81,7 +79,7 @@ extension SSHClientX on SSHClient { isRequestingPwd = true; final user = Miscs.pwdRequestWithUserReg.firstMatch(data)?.group(1); if (context == null) return; - final pwd = await context.showPwdDialog(title: user, hostId: id); + final pwd = await context.showPwdDialog(title: user, id: id); if (pwd == null || pwd.isEmpty) { session.kill(SSHSignal.TERM); } else { diff --git a/lib/core/extension/stringx.dart b/lib/core/extension/stringx.dart deleted file mode 100644 index 30818685..00000000 --- a/lib/core/extension/stringx.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -extension StringX on String { - /// Format: `#8b2252` or `8b2252` - Color? get hexToColor { - final hexCode = replaceAll('#', ''); - final val = int.tryParse('FF$hexCode', radix: 16); - if (val == null) { - return null; - } - return Color(val); - } - - Uint8List get uint8List => Uint8List.fromList(utf8.encode(this)); - - /// Upper the first letter. - String get upperFirst { - if (isEmpty) { - return this; - } - final runes = codeUnits; - if (runes[0] >= 97 && runes[0] <= 122) { - final origin = String.fromCharCode(runes[0]); - final upper = origin.toUpperCase(); - return replaceFirst(origin, upper); - } - return this; - } -} - -extension StringXX on String? { - String? get selfIfNotNullEmpty => this?.isEmpty == true ? null : this; -} diff --git a/lib/core/extension/uint8list.dart b/lib/core/extension/uint8list.dart deleted file mode 100644 index 63d991fa..00000000 --- a/lib/core/extension/uint8list.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -extension FutureUint8ListX on Future { - Future get string async => utf8.decode(await this); - Future get byteData async => (await this).buffer.asByteData(); -} - -extension Uint8ListX on Uint8List { - String get string => utf8.decode(this); -} diff --git a/lib/core/extension/widget.dart b/lib/core/extension/widget.dart deleted file mode 100644 index 23070b8d..00000000 --- a/lib/core/extension/widget.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:toolbox/view/widget/cardx.dart'; - -extension WidgetX on Widget { - Widget get card { - return CardX(child: this); - } -} diff --git a/lib/core/persistant_store.dart b/lib/core/persistant_store.dart deleted file mode 100644 index 9f4d886c..00000000 --- a/lib/core/persistant_store.dart +++ /dev/null @@ -1,242 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:hive_flutter/hive_flutter.dart'; -import 'package:logging/logging.dart'; -import 'package:toolbox/core/utils/misc.dart'; - -// abstract final class SecureStore { -// static const _secureStorage = FlutterSecureStorage(); - -// static HiveAesCipher? _cipher; - -// static const _hiveKey = 'hive_key'; - -// static Future init() async { -// final encryptionKeyString = await _secureStorage.read(key: _hiveKey); -// if (encryptionKeyString == null) { -// final key = Hive.generateSecureKey(); -// await _secureStorage.write( -// key: _hiveKey, -// value: base64UrlEncode(key), -// ); -// } -// final key = await _secureStorage.read(key: _hiveKey); -// if (key == null) { -// throw Exception('Failed to init SecureStore'); -// } -// final encryptionKeyUint8List = base64Url.decode(key); -// _cipher = HiveAesCipher(encryptionKeyUint8List); -// } -// } - -final _logger = Logger('Store'); - -class PersistentStore { - late final Box box; - - final String boxName; - - PersistentStore(this.boxName); - - Future init() async => box = await Hive.openBox( - boxName, - //encryptionCipher: SecureStore._cipher, - ); - - _StoreProperty property( - String key, - T defaultValue, { - bool updateLastModified = true, - }) { - return _StoreProperty( - box, - key, - defaultValue, - updateLastModified: updateLastModified, - ); - } - - _StoreListProperty listProperty( - String key, - List defaultValue, { - bool updateLastModified = true, - }) { - return _StoreListProperty( - box, - key, - defaultValue, - updateLastModified: updateLastModified, - ); - } -} - -extension BoxX on Box { - static const _internalPreffix = '_sbi_'; - - /// Last modified timestamp - static const String lastModifiedKey = '${_internalPreffix}lastModified'; - int? get lastModified { - final val = get(lastModifiedKey); - if (val == null || val is! int) { - final time = timeStamp; - put(lastModifiedKey, time); - return time; - } - return val; - } - - Future updateLastModified([int? time]) => put( - lastModifiedKey, - time ?? timeStamp, - ); - - /// Convert db to json - Map toJson({bool includeInternal = true}) { - final json = {}; - for (final key in keys) { - if (key is String && - key.startsWith(_internalPreffix) && - !includeInternal) { - continue; - } - json[key] = get(key); - } - return json; - } -} - -abstract class StorePropertyBase { - ValueListenable listenable(); - T fetch(); - Future put(T value); - Future delete(); -} - -class _StoreProperty implements StorePropertyBase { - _StoreProperty( - this._box, - this._key, - this.defaultValue, { - this.updateLastModified = true, - }); - - final Box _box; - final String _key; - T defaultValue; - bool updateLastModified; - - @override - ValueListenable listenable() { - return PropertyListenable(_box, _key, defaultValue); - } - - @override - T fetch() { - final stored = _box.get(_key, defaultValue: defaultValue); - if (stored is! T) { - _logger.warning('StoreProperty("$_key") is: ${stored.runtimeType}'); - return defaultValue; - } - return stored; - } - - @override - Future put(T value) { - if (updateLastModified) _box.updateLastModified(); - return _box.put(_key, value); - } - - @override - Future delete() { - return _box.delete(_key); - } -} - -class _StoreListProperty implements StorePropertyBase> { - _StoreListProperty( - this._box, - this._key, - this.defaultValue, { - this.updateLastModified = true, - }); - - final Box _box; - final String _key; - List defaultValue; - bool updateLastModified; - - @override - ValueListenable> listenable() { - return PropertyListenable>(_box, _key, defaultValue); - } - - @override - List fetch() { - final val = _box.get(_key, defaultValue: defaultValue)!; - try { - if (val is! List) { - final exception = 'StoreListProperty("$_key") is: ${val.runtimeType}'; - _logger.warning(exception); - throw Exception(exception); - } - return List.from(val); - } catch (_) { - return defaultValue; - } - } - - @override - Future put(List value) { - if (updateLastModified) _box.updateLastModified(); - return _box.put(_key, value); - } - - @override - Future delete() { - return _box.delete(_key); - } -} - -class PropertyListenable extends ValueListenable { - PropertyListenable(this.box, this.key, this.defaultValue); - - final Box box; - final String key; - T? defaultValue; - - final List _listeners = []; - StreamSubscription? _subscription; - - @override - void addListener(VoidCallback listener) { - _subscription ??= box.watch().listen((event) { - if (key == event.key) { - for (var listener in _listeners) { - listener(); - } - } - }); - - _listeners.add(listener); - } - - @override - void removeListener(VoidCallback listener) { - _listeners.remove(listener); - - if (_listeners.isEmpty) { - _subscription?.cancel(); - _subscription = null; - } - } - - @override - T get value { - final val = box.get(key, defaultValue: defaultValue); - if (val == null || val is! T) { - return defaultValue!; - } - return val; - } -} diff --git a/lib/core/route.dart b/lib/core/route.dart index f6ac80bb..358d46ab 100644 --- a/lib/core/route.dart +++ b/lib/core/route.dart @@ -1,6 +1,5 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/analysis.dart'; import 'package:toolbox/data/model/server/private_key_info.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/res/store.dart'; @@ -35,14 +34,13 @@ import '../view/page/snippet/list.dart'; import '../view/page/storage/sftp.dart'; import '../view/page/storage/sftp_mission.dart'; -class AppRoute { +class AppRoutes { final Widget page; final String title; - AppRoute(this.page, this.title); + AppRoutes(this.page, this.title); Future go(BuildContext context) { - Analysis.recordView(title); return Navigator.push( context, Stores.setting.cupertinoRoute.fetch() @@ -61,49 +59,49 @@ class AppRoute { return Future.value(null); } - static AppRoute serverDetail({Key? key, required ServerPrivateInfo spi}) { - return AppRoute(ServerDetailPage(key: key, spi: spi), 'server_detail'); + static AppRoutes serverDetail({Key? key, required ServerPrivateInfo spi}) { + return AppRoutes(ServerDetailPage(key: key, spi: spi), 'server_detail'); } - static AppRoute serverTab({Key? key}) { - return AppRoute(ServerPage(key: key), 'server_tab'); + static AppRoutes serverTab({Key? key}) { + return AppRoutes(ServerPage(key: key), 'server_tab'); } - static AppRoute serverEdit({Key? key, ServerPrivateInfo? spi}) { - return AppRoute( + static AppRoutes serverEdit({Key? key, ServerPrivateInfo? spi}) { + return AppRoutes( ServerEditPage(spi: spi), 'server_${spi == null ? 'add' : 'edit'}', ); } - static AppRoute keyEdit({Key? key, PrivateKeyInfo? pki}) { - return AppRoute( + static AppRoutes keyEdit({Key? key, PrivateKeyInfo? pki}) { + return AppRoutes( PrivateKeyEditPage(pki: pki), 'key_${pki == null ? 'add' : 'edit'}', ); } - static AppRoute keyList({Key? key}) { - return AppRoute(PrivateKeysListPage(key: key), 'key_detail'); + static AppRoutes keyList({Key? key}) { + return AppRoutes(PrivateKeysListPage(key: key), 'key_detail'); } - static AppRoute snippetEdit({Key? key, Snippet? snippet}) { - return AppRoute( + static AppRoutes snippetEdit({Key? key, Snippet? snippet}) { + return AppRoutes( SnippetEditPage(snippet: snippet), 'snippet_${snippet == null ? 'add' : 'edit'}', ); } - static AppRoute snippetList({Key? key}) { - return AppRoute(SnippetListPage(key: key), 'snippet_detail'); + static AppRoutes snippetList({Key? key}) { + return AppRoutes(SnippetListPage(key: key), 'snippet_detail'); } - static AppRoute ssh({ + static AppRoutes ssh({ Key? key, required ServerPrivateInfo spi, String? initCmd, }) { - return AppRoute( + return AppRoutes( SSHPage( key: key, spi: spi, @@ -113,13 +111,13 @@ class AppRoute { ); } - static AppRoute sshVirtKeySetting({Key? key}) { - return AppRoute(SSHVirtKeySettingPage(key: key), 'ssh_virt_key_setting'); + static AppRoutes sshVirtKeySetting({Key? key}) { + return AppRoutes(SSHVirtKeySettingPage(key: key), 'ssh_virt_key_setting'); } - static AppRoute localStorage( + static AppRoutes localStorage( {Key? key, bool isPickFile = false, String? initDir}) { - return AppRoute( + return AppRoutes( LocalStoragePage( key: key, isPickFile: isPickFile, @@ -128,16 +126,16 @@ class AppRoute { 'local_storage'); } - static AppRoute sftpMission({Key? key}) { - return AppRoute(SftpMissionPage(key: key), 'sftp_mission'); + static AppRoutes sftpMission({Key? key}) { + return AppRoutes(SftpMissionPage(key: key), 'sftp_mission'); } - static AppRoute sftp( + static AppRoutes sftp( {Key? key, required ServerPrivateInfo spi, String? initPath, bool isSelect = false}) { - return AppRoute( + return AppRoutes( SftpPage( key: key, spi: spi, @@ -147,28 +145,28 @@ class AppRoute { 'sftp'); } - static AppRoute backup({Key? key}) { - return AppRoute(BackupPage(key: key), 'backup'); + static AppRoutes backup({Key? key}) { + return AppRoutes(BackupPage(key: key), 'backup'); } - static AppRoute debug({Key? key}) { - return AppRoute(DebugPage(key: key), 'debug'); + static AppRoutes debug({Key? key}) { + return AppRoutes(DebugPage(key: key), 'debug'); } - static AppRoute docker({Key? key, required ServerPrivateInfo spi}) { - return AppRoute(ContainerPage(key: key, spi: spi), 'docker'); + static AppRoutes docker({Key? key, required ServerPrivateInfo spi}) { + return AppRoutes(ContainerPage(key: key, spi: spi), 'docker'); } /// - Pop true if the text is changed & [path] is not null /// - Pop text if [path] is null - static AppRoute editor({ + static AppRoutes editor({ Key? key, String? path, String? text, String? langCode, String? title, }) { - return AppRoute( + return AppRoutes( EditorPage( key: key, path: path, @@ -179,45 +177,45 @@ class AppRoute { 'editor'); } - // static AppRoute fullscreen({Key? key}) { - // return AppRoute(FullScreenPage(key: key), 'fullscreen'); + // static AppRoutes fullscreen({Key? key}) { + // return AppRoutes(FullScreenPage(key: key), 'fullscreen'); // } - static AppRoute home({Key? key}) { - return AppRoute(HomePage(key: key), 'home'); + static AppRoutes home({Key? key}) { + return AppRoutes(HomePage(key: key), 'home'); } - static AppRoute ping({Key? key}) { - return AppRoute(PingPage(key: key), 'ping'); + static AppRoutes ping({Key? key}) { + return AppRoutes(PingPage(key: key), 'ping'); } - static AppRoute process({Key? key, required ServerPrivateInfo spi}) { - return AppRoute(ProcessPage(key: key, spi: spi), 'process'); + static AppRoutes process({Key? key, required ServerPrivateInfo spi}) { + return AppRoutes(ProcessPage(key: key, spi: spi), 'process'); } - static AppRoute settings({Key? key}) { - return AppRoute(SettingPage(key: key), 'setting'); + static AppRoutes settings({Key? key}) { + return AppRoutes(SettingPage(key: key), 'setting'); } - static AppRoute serverOrder({Key? key}) { - return AppRoute(ServerOrderPage(key: key), 'server_order'); + static AppRoutes serverOrder({Key? key}) { + return AppRoutes(ServerOrderPage(key: key), 'server_order'); } - static AppRoute serverDetailOrder({Key? key}) { - return AppRoute(ServerDetailOrderPage(key: key), 'server_detail_order'); + static AppRoutes serverDetailOrder({Key? key}) { + return AppRoutes(ServerDetailOrderPage(key: key), 'server_detail_order'); } - static AppRoute iosSettings({Key? key}) { - return AppRoute(IOSSettingsPage(key: key), 'ios_setting'); + static AppRoutes iosSettings({Key? key}) { + return AppRoutes(IOSSettingsPage(key: key), 'ios_setting'); } - static AppRoute androidSettings({Key? key}) { - return AppRoute(AndroidSettingsPage(key: key), 'android_setting'); + static AppRoutes androidSettings({Key? key}) { + return AppRoutes(AndroidSettingsPage(key: key), 'android_setting'); } - static AppRoute snippetResult( + static AppRoutes snippetResult( {Key? key, required List results}) { - return AppRoute( + return AppRoutes( SnippetResultPage( key: key, results: results, @@ -225,15 +223,15 @@ class AppRoute { 'snippet_result'); } - static AppRoute iperf({Key? key, required ServerPrivateInfo spi}) { - return AppRoute(IPerfPage(key: key, spi: spi), 'iperf'); + static AppRoutes iperf({Key? key, required ServerPrivateInfo spi}) { + return AppRoutes(IPerfPage(key: key, spi: spi), 'iperf'); } - static AppRoute serverFuncBtnsOrder({Key? key}) { - return AppRoute(ServerFuncBtnsOrderPage(key: key), 'server_func_btns_seq'); + static AppRoutes serverFuncBtnsOrder({Key? key}) { + return AppRoutes(ServerFuncBtnsOrderPage(key: key), 'server_func_btns_seq'); } - static AppRoute pve({Key? key, required ServerPrivateInfo spi}) { - return AppRoute(PvePage(key: key, spi: spi), 'pve'); + static AppRoutes pve({Key? key, required ServerPrivateInfo spi}) { + return AppRoutes(PvePage(key: key, spi: spi), 'pve'); } } diff --git a/lib/core/update.dart b/lib/core/update.dart deleted file mode 100644 index 59e46eed..00000000 --- a/lib/core/update.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/utils/misc.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/core/utils/ui.dart'; -import 'package:toolbox/data/model/app/update.dart'; -import 'package:toolbox/data/res/build_data.dart'; -import 'package:toolbox/data/res/logger.dart'; -import 'package:toolbox/data/res/provider.dart'; -import 'package:toolbox/data/service/app.dart'; -import 'package:toolbox/locator.dart'; - -Future isFileAvailable(String url) async { - try { - final resp = await Dio().head(url); - return resp.statusCode == 200; - } catch (e) { - Loggers.app.warning('HEAD update file failed', e); - return false; - } -} - -Future doUpdate(BuildContext context, {bool force = false}) async { - final update = await locator().getUpdate(); - - final newest = update.build.last.current; - if (newest == null) { - Loggers.app.warning('Update not available on ${OS.type}'); - return; - } - - Pros.app.newestBuild = newest; - - if (!force && newest <= BuildData.build) { - Loggers.app.info('Update ignored: ${BuildData.build} >= $newest'); - return; - } - Loggers.app.info('Update available: $newest'); - - final url = update.url.current!; - - if (isFileUrl(url) && !await isFileAvailable(url)) { - Loggers.app.warning('Update file not available'); - return; - } - - final min = update.build.min.current; - - if (min != null && min > BuildData.build) { - context.showRoundDialog( - child: Text(l10n.updateTipTooLow(newest)), - actions: [ - TextButton( - onPressed: () => _doUpdate(update, context), - child: Text(l10n.ok), - ) - ], - ); - return; - } - - context.showSnackBarWithAction( - '${l10n.updateTip(newest)} \n${update.changelog.current}', - l10n.update, - () => _doUpdate(update, context), - ); -} - -Future _doUpdate(AppUpdate update, BuildContext context) async { - final url = update.url.current; - if (url == null) { - Loggers.app.warning('Update url is null'); - context.showSnackBar(l10n.failed); - return; - } - - await openUrl(url); -} diff --git a/lib/core/utils/function.dart b/lib/core/utils/function.dart deleted file mode 100644 index ab0267b6..00000000 --- a/lib/core/utils/function.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter/material.dart'; - -abstract final class Funcs { - static const int _defaultDurationTime = 377; - static const String _defaultThrottleId = 'default'; - static final Map startTimeMap = { - _defaultThrottleId: 0 - }; - - static void throttle( - VoidCallback? func, { - String id = _defaultThrottleId, - int duration = _defaultDurationTime, - Function? continueClick, - }) { - final currentTime = DateTime.now().millisecondsSinceEpoch; - if (currentTime - (startTimeMap[id] ?? 0) > duration) { - func?.call(); - startTimeMap[id] = DateTime.now().millisecondsSinceEpoch; - } else { - continueClick?.call(); - } - } -} diff --git a/lib/core/utils/misc.dart b/lib/core/utils/misc.dart index 48e93dc2..1ed6b98e 100644 --- a/lib/core/utils/misc.dart +++ b/lib/core/utils/misc.dart @@ -1,14 +1,6 @@ -import 'package:file_picker/file_picker.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:plain_notification_token/plain_notification_token.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/data/res/provider.dart'; -Future pickOneFile() async { - Pros.app.moveBg = false; - final result = await FilePicker.platform.pickFiles(type: FileType.any); - Pros.app.moveBg = true; - return result?.files.single.path; -} Future getToken() async { if (isIOS) { @@ -29,22 +21,3 @@ String? getFileName(String? path) { } return path.split('/').last; } - -/// Join two path with `/` -String pathJoin(String path1, String path2) { - return path1 + (path1.endsWith('/') ? '' : '/') + path2; -} - -/// Check if a url is a file url (ends with a file extension) -bool isFileUrl(String url) => url.split('/').last.contains('.'); - -int get timeStamp => DateTime.now().millisecondsSinceEpoch; - -bool isBaseType(Object? obj) { - return obj is String || - obj is int || - obj is double || - obj is bool || - obj is List || - obj is Map; -} diff --git a/lib/core/utils/platform/auth.dart b/lib/core/utils/platform/auth.dart deleted file mode 100644 index 1c032b8f..00000000 --- a/lib/core/utils/platform/auth.dart +++ /dev/null @@ -1,104 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/services.dart'; -import 'package:local_auth/local_auth.dart'; -// ignore: depend_on_referenced_packages -import 'package:local_auth_android/local_auth_android.dart'; -// ignore: depend_on_referenced_packages -import 'package:local_auth_ios/types/auth_messages_ios.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:local_auth/error_codes.dart' as errs; -import 'package:toolbox/data/res/store.dart'; - -abstract final class BioAuth { - static final _auth = LocalAuthentication(); - - static final isPlatformSupported = isAndroid || isIOS || isWindows; - - static bool _isAuthing = false; - - static Future get isAvail async { - if (!isPlatformSupported) return false; - if (!await _auth.canCheckBiometrics) { - return false; - } - final biometrics = await _auth.getAvailableBiometrics(); - - /// [biometrics] on Android and Windows is returned with error - /// Handle it specially - if (isAndroid || isWindows) return biometrics.isNotEmpty; - return biometrics.contains(BiometricType.face) || - biometrics.contains(BiometricType.fingerprint); - } - - static Future go([int count = 0]) async { - if (Stores.setting.useBioAuth.fetch()) { - if (!_isAuthing) { - _isAuthing = true; - final val = await goWithResult(); - _isAuthing = false; - switch (val) { - case AuthResult.success: - break; - case AuthResult.fail: - case AuthResult.cancel: - go(count + 1); - break; - case AuthResult.notAvail: - Stores.setting.useBioAuth.put(false); - break; - } - } - } - } - - static Future goWithResult() async { - if (!await isAvail) return AuthResult.notAvail; - try { - await _auth.stopAuthentication(); - final reuslt = await _auth.authenticate( - localizedReason: l10n.authRequired, - options: const AuthenticationOptions( - biometricOnly: true, - stickyAuth: true, - ), - authMessages: [ - AndroidAuthMessages( - biometricHint: l10n.bioAuth, - biometricNotRecognized: l10n.failed, - biometricRequiredTitle: l10n.authRequired, - biometricSuccess: l10n.success, - cancelButton: l10n.cancel, - ), - IOSAuthMessages( - lockOut: l10n.authRequired, - cancelButton: l10n.ok, - ), - ]); - if (reuslt) { - return AuthResult.success; - } - return AuthResult.fail; - } on PlatformException catch (e) { - switch (e.code) { - case errs.notEnrolled: - return AuthResult.notAvail; - case errs.lockedOut: - case errs.permanentlyLockedOut: - exit(0); - } - return AuthResult.cancel; - } - } -} - -enum AuthResult { - success, - // Not match - fail, - // User cancel - cancel, - // Device doesn't support biometrics - notAvail, -} diff --git a/lib/core/utils/platform/base.dart b/lib/core/utils/platform/base.dart deleted file mode 100644 index 31ead358..00000000 --- a/lib/core/utils/platform/base.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:toolbox/core/extension/stringx.dart'; - -enum OS { - android, - ios, - linux, - macos, - windows, - web, - fuchsia, - unknown; - - static final type = () { - if (kIsWeb) { - return OS.web; - } - if (Platform.isAndroid) { - return OS.android; - } - if (Platform.isIOS) { - return OS.ios; - } - if (Platform.isLinux) { - return OS.linux; - } - if (Platform.isMacOS) { - return OS.macos; - } - if (Platform.isWindows) { - return OS.windows; - } - if (Platform.isFuchsia) { - return OS.fuchsia; - } - return OS.unknown; - }(); - - @override - String toString() => switch (this) { - OS.macos => 'macOS', - OS.ios => 'iOS', - final val => val.name.upperFirst, - }; -} - -final isAndroid = OS.type == OS.android; -final isIOS = OS.type == OS.ios; -final isLinux = OS.type == OS.linux; -final isMacOS = OS.type == OS.macos; -final isWindows = OS.type == OS.windows; -final isWeb = OS.type == OS.web; -final isMobile = OS.type == OS.ios || OS.type == OS.android; -final isDesktop = - OS.type == OS.linux || OS.type == OS.macos || OS.type == OS.windows; diff --git a/lib/core/utils/platform/path.dart b/lib/core/utils/platform/path.dart deleted file mode 100644 index 93cf90c8..00000000 --- a/lib/core/utils/platform/path.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'dart:io'; - -import 'package:toolbox/core/utils/platform/base.dart'; - -final _pathSep = Platform.pathSeparator; -String get pathSeparator => _pathSep; - -/// Available only on desktop, -/// return null on mobile -String? getHomeDir() { - final envVars = Platform.environment; - if (isMacOS || isLinux) { - return envVars['HOME']; - } else if (isWindows) { - return envVars['UserProfile']; - } - return null; -} - -/// Join two paths with platform specific separator -String joinPath(String path1, String path2) { - if (isWindows) { - return path1 + (path1.endsWith('\\') ? '' : '\\') + path2; - } - return path1 + (path1.endsWith('/') ? '' : '/') + path2; -} diff --git a/lib/core/utils/platform/perm.dart b/lib/core/utils/platform/perm.dart deleted file mode 100644 index 3bf56a43..00000000 --- a/lib/core/utils/platform/perm.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:permission_handler/permission_handler.dart'; - -abstract final class PermUtils { - static Future request(Permission permission) async { - final status = await permission.status; - if (status.isGranted) { - return true; - } else { - final result = await permission.request(); - return result.isGranted; - } - } -} diff --git a/lib/core/utils/share.dart b/lib/core/utils/share.dart deleted file mode 100644 index c96edfee..00000000 --- a/lib/core/utils/share.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/services.dart'; -import 'package:share_plus/share_plus.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/data/res/provider.dart'; - -abstract final class Shares { - static Future files(List filePaths) async { - for (final filePath in filePaths) { - if (!await File(filePath).exists()) { - return false; - } - } - var text = ''; - if (filePaths.length == 1) { - text = filePaths.first.split('/').last; - } else { - text = '${filePaths.length} ${l10n.files}'; - } - Pros.app.moveBg = false; - // ignore: deprecated_member_use - await Share.shareFiles(filePaths, subject: text); - Pros.app.moveBg = true; - return filePaths.isNotEmpty; - } - - static Future text(String text) async { - Pros.app.moveBg = false; - await Share.share(text); - Pros.app.moveBg = true; - return true; - } - - static void copy(String text) { - Clipboard.setData(ClipboardData(text: text)); - } - - static Future paste([String type = 'text/plain']) async { - final data = await Clipboard.getData(type); - return data?.text; - } -} diff --git a/lib/core/utils/ssh_auth.dart b/lib/core/utils/ssh_auth.dart index a9113dce..8db8db26 100644 --- a/lib/core/utils/ssh_auth.dart +++ b/lib/core/utils/ssh_auth.dart @@ -1,7 +1,7 @@ import 'dart:async'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/res/provider.dart'; @@ -14,6 +14,7 @@ abstract final class KeybordInteractive { try { final res = await (ctx ?? Pros.app.ctx)?.showPwdDialog( title: '2FA ${l10n.pwd}', + id: spi.id, label: spi.id, ); return res == null ? null : [res]; diff --git a/lib/core/utils/sync/icloud.dart b/lib/core/utils/sync/icloud.dart index 255d76e9..99862ec8 100644 --- a/lib/core/utils/sync/icloud.dart +++ b/lib/core/utils/sync/icloud.dart @@ -2,13 +2,13 @@ import 'dart:async'; import 'dart:io'; import 'package:computer/computer.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:icloud_storage/icloud_storage.dart'; import 'package:logging/logging.dart'; import 'package:toolbox/data/model/app/backup.dart'; import 'package:toolbox/data/model/app/sync.dart'; import '../../../data/model/app/error.dart'; -import '../../../data/res/path.dart'; abstract final class ICloud { static const _containerId = 'iCloud.tech.lolli.serverbox'; @@ -31,7 +31,7 @@ abstract final class ICloud { try { await ICloudStorage.upload( containerId: _containerId, - filePath: localPath ?? '${await Paths.doc}/$relativePath', + filePath: localPath ?? '${Paths.doc}/$relativePath', destinationRelativePath: relativePath, onProgress: (stream) { stream.listen( @@ -85,7 +85,7 @@ abstract final class ICloud { await ICloudStorage.download( containerId: _containerId, relativePath: relativePath, - destinationFilePath: localPath ?? '${await Paths.doc}/$relativePath', + destinationFilePath: localPath ?? '${Paths.doc}/$relativePath', onProgress: (stream) { stream.listen( null, @@ -139,7 +139,7 @@ abstract final class ICloud { } })); - final docPath = await Paths.doc; + final docPath = Paths.doc; /// compare files in iCloud and local missions.addAll(allFiles.map((file) async { @@ -205,7 +205,7 @@ abstract final class ICloud { return; } - final dlFile = await File(await Paths.bak).readAsString(); + final dlFile = await File(Paths.bakPath).readAsString(); final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile); await dlBak.restore(); diff --git a/lib/core/utils/sync/webdav.dart b/lib/core/utils/sync/webdav.dart index e27ce97c..708748a7 100644 --- a/lib/core/utils/sync/webdav.dart +++ b/lib/core/utils/sync/webdav.dart @@ -1,10 +1,10 @@ import 'dart:io'; import 'package:computer/computer.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:logging/logging.dart'; import 'package:toolbox/data/model/app/backup.dart'; import 'package:toolbox/data/model/app/error.dart'; -import 'package:toolbox/data/res/path.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:webdav_client/webdav_client.dart'; @@ -37,7 +37,7 @@ abstract final class Webdav { }) async { try { await _client.writeFile( - localPath ?? '${await Paths.doc}/$relativePath', + localPath ?? '${Paths.doc}/$relativePath', _prefix + relativePath, ); } catch (e, s) { @@ -64,7 +64,7 @@ abstract final class Webdav { try { await _client.readFile( _prefix + relativePath, - localPath ?? '${await Paths.doc}/$relativePath', + localPath ?? '${Paths.doc}/$relativePath', ); } catch (e) { _logger.warning('Download $relativePath failed'); @@ -104,7 +104,7 @@ abstract final class Webdav { } try { - final dlFile = await File(await Paths.bak).readAsString(); + final dlFile = await File(Paths.bakPath).readAsString(); final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile); await dlBak.restore(); } catch (e) { diff --git a/lib/core/utils/ui.dart b/lib/core/utils/ui.dart index 068f81f8..356ba50d 100644 --- a/lib/core/utils/ui.dart +++ b/lib/core/utils/ui.dart @@ -1,14 +1,12 @@ import 'dart:async'; import 'dart:io'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; +import 'package:toolbox/core/utils/misc.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'misc.dart'; -import '../extension/uint8list.dart'; - Future openUrl(String url) async { return await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication); } diff --git a/lib/data/model/app/backup.dart b/lib/data/model/app/backup.dart index c04e8600..fe45e595 100644 --- a/lib/data/model/app/backup.dart +++ b/lib/data/model/app/backup.dart @@ -1,13 +1,11 @@ import 'dart:convert'; import 'dart:io'; +import 'package:fl_lib/fl_lib.dart'; import 'package:logging/logging.dart'; -import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/data/model/server/private_key_info.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/model/server/snippet.dart'; -import 'package:toolbox/data/res/logger.dart'; -import 'package:toolbox/data/res/path.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/rebuild.dart'; import 'package:toolbox/data/res/store.dart'; @@ -76,7 +74,7 @@ class Backup { static Future backup([String? name]) async { final result = _diyEncrypt(json.encode(Backup.loadFromStore().toJson())); - final path = '${await Paths.doc}/${name ?? Paths.bakName}'; + final path = '${Paths.doc}/${name ?? 'srvbox_bak.json'}'; await File(path).writeAsString(result); return path; } diff --git a/lib/data/model/app/dynamic_color.dart b/lib/data/model/app/dynamic_color.dart deleted file mode 100644 index bd799e12..00000000 --- a/lib/data/model/app/dynamic_color.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:toolbox/core/extension/context/common.dart'; - -class DynamicColor { - /// 白天模式显示的颜色 - final Color light; - - /// 暗黑模式显示的颜色 - final Color dark; - - const DynamicColor(this.light, this.dark); - - Color resolve(BuildContext context) => context.isDark ? dark : light; -} diff --git a/lib/data/model/app/menu/base.dart b/lib/data/model/app/menu/base.dart index 8fb116a1..70d58a5c 100644 --- a/lib/data/model/app/menu/base.dart +++ b/lib/data/model/app/menu/base.dart @@ -1,15 +1,18 @@ import 'package:flutter/material.dart'; abstract class PopMenu { - static PopupMenuItem build(T t, IconData icon, String text) { + static PopupMenuItem build( + T t, + IconData icon, + String text, { + double? iconSize, + }) { return PopupMenuItem( value: t, child: Row( children: [ - Icon(icon), - const SizedBox( - width: 10, - ), + Icon(icon, size: iconSize), + const SizedBox(width: 10), Text(text), ], ), diff --git a/lib/data/model/app/menu/container.dart b/lib/data/model/app/menu/container.dart index 59b551ee..ff2fcf68 100644 --- a/lib/data/model/app/menu/container.dart +++ b/lib/data/model/app/menu/container.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/data/model/app/menu/base.dart'; enum ContainerMenu { start, @@ -64,10 +63,4 @@ enum ContainerMenu { // return s.stats; } } - - PopupMenuItem get widget => PopMenu.build( - this, - icon, - toStr, - ); } diff --git a/lib/data/model/app/menu/server_func.dart b/lib/data/model/app/menu/server_func.dart index f92a5374..67612589 100644 --- a/lib/data/model/app/menu/server_func.dart +++ b/lib/data/model/app/menu/server_func.dart @@ -34,14 +34,14 @@ enum ServerFuncBtn { snippet, ].map((e) => e.index).toList(); - Icon icon([double? sizeDiff]) => switch (this) { - sftp => Icon(Icons.insert_drive_file, size: 15 + (sizeDiff ?? 0)), - snippet => Icon(Icons.code, size: 15 + (sizeDiff ?? 0)), - pkg => Icon(Icons.system_security_update, size: 15 + (sizeDiff ?? 0)), - container => Icon(FontAwesome.docker_brand, size: 14 + (sizeDiff ?? 0)), - process => Icon(Icons.list_alt_outlined, size: 15 + (sizeDiff ?? 0)), - terminal => Icon(Icons.terminal, size: 15 + (sizeDiff ?? 0)), - iperf => Icon(Icons.speed, size: 15 + (sizeDiff ?? 0)), + IconData get icon => switch (this) { + sftp => Icons.insert_drive_file, + snippet => Icons.code, + pkg => Icons.system_security_update, + container => FontAwesome.docker_brand, + process => Icons.list_alt_outlined, + terminal => Icons.terminal, + iperf => Icons.speed, }; String get toStr => switch (this) { diff --git a/lib/data/model/app/path_with_prefix.dart b/lib/data/model/app/path_with_prefix.dart index df39ca75..77b74541 100644 --- a/lib/data/model/app/path_with_prefix.dart +++ b/lib/data/model/app/path_with_prefix.dart @@ -1,4 +1,4 @@ -import 'package:toolbox/core/utils/platform/path.dart'; +import 'package:fl_lib/fl_lib.dart'; /// It's used on platform's file system. /// So use [Platform.pathSeparator] to join path. @@ -23,7 +23,7 @@ class LocalPath { _path = '/'; return; } - _path = joinPath(_path, newPath); + _path = _path.joinPath(newPath); } bool get canBack => path != '$_prefixPath/'; diff --git a/lib/data/model/app/server_detail_card.dart b/lib/data/model/app/server_detail_card.dart index a2c4a3cc..22077a82 100644 --- a/lib/data/model/app/server_detail_card.dart +++ b/lib/data/model/app/server_detail_card.dart @@ -1,7 +1,7 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:icons_plus/icons_plus.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/listx.dart'; import 'package:toolbox/data/model/app/version_related.dart'; import 'package:toolbox/data/res/store.dart'; diff --git a/lib/data/model/app/update.dart b/lib/data/model/app/update.dart deleted file mode 100644 index 6cc4882a..00000000 --- a/lib/data/model/app/update.dart +++ /dev/null @@ -1,140 +0,0 @@ -/* -{ - "changelog": { - "mac": "xxx", - "ios": "xxx", - "android": "" - }, - "build": { - "min": { - "mac": 1, - "ios": 1, - "android": 1 - }, - "last": { - "mac": 1, - "ios": 1, - "android": 1 - } - }, - "url": { - "mac": "https://apps.apple.com/app/id1586449703", - "ios": "https://apps.apple.com/app/id1586449703", - "android": "https://cdn3.cust.app/uploads/ServerBox_262_Arm64.apk" - } -} -*/ - -import 'dart:convert'; - -import 'package:toolbox/core/utils/platform/base.dart'; - -class AppUpdate { - const AppUpdate({ - required this.changelog, - required this.build, - required this.url, - }); - - final AppUpdatePlatformSpecific changelog; - final Build build; - final AppUpdatePlatformSpecific url; - - factory AppUpdate.fromRawJson(String str) => - AppUpdate.fromJson(json.decode(str)); - - String toRawJson() => json.encode(toJson()); - - factory AppUpdate.fromJson(Map json) => AppUpdate( - changelog: AppUpdatePlatformSpecific.fromJson(json["changelog"]), - build: Build.fromJson(json["build"]), - url: AppUpdatePlatformSpecific.fromJson(json["url"]), - ); - - Map toJson() => { - "changelog": changelog.toJson(), - "build": build.toJson(), - "url": url.toJson(), - }; -} - -class Build { - Build({ - required this.min, - required this.last, - }); - - final AppUpdatePlatformSpecific min; - final AppUpdatePlatformSpecific last; - - factory Build.fromRawJson(String str) => Build.fromJson(json.decode(str)); - - String toRawJson() => json.encode(toJson()); - - factory Build.fromJson(Map json) => Build( - min: AppUpdatePlatformSpecific.fromJson(json["min"]), - last: AppUpdatePlatformSpecific.fromJson(json["last"]), - ); - - Map toJson() => { - "min": min.toJson(), - "last": last.toJson(), - }; -} - -class AppUpdatePlatformSpecific { - AppUpdatePlatformSpecific({ - required this.mac, - required this.ios, - required this.android, - required this.windows, - required this.linux, - }); - - final T mac; - final T ios; - final T android; - final T windows; - final T linux; - - factory AppUpdatePlatformSpecific.fromRawJson(String str) => - AppUpdatePlatformSpecific.fromJson(json.decode(str)); - - String toRawJson() => json.encode(toJson()); - - factory AppUpdatePlatformSpecific.fromJson(Map json) => - AppUpdatePlatformSpecific( - mac: json["mac"], - ios: json["ios"], - android: json["android"], - windows: json["windows"], - linux: json["linux"], - ); - - Map toJson() => { - "mac": mac, - "ios": ios, - "android": android, - "windows": windows, - "linux": linux, - }; - - T? get current { - switch (OS.type) { - case OS.macos: - return mac; - case OS.ios: - return ios; - case OS.android: - return android; - case OS.windows: - return windows; - case OS.linux: - return linux; - - /// Not implemented yet. - case OS.web || OS.fuchsia || OS.unknown: - return null; - } - } -} diff --git a/lib/data/model/container/image.dart b/lib/data/model/container/image.dart index 86bdb295..95add2fa 100644 --- a/lib/data/model/container/image.dart +++ b/lib/data/model/container/image.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:toolbox/core/extension/numx.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/data/model/container/type.dart'; abstract final class ContainerImg { diff --git a/lib/data/model/container/ps.dart b/lib/data/model/container/ps.dart index c8c012bb..c5b2541a 100644 --- a/lib/data/model/container/ps.dart +++ b/lib/data/model/container/ps.dart @@ -1,7 +1,7 @@ import 'dart:convert'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/numx.dart'; import 'package:toolbox/data/model/container/type.dart'; abstract final class ContainerPs { diff --git a/lib/data/model/server/battery.dart b/lib/data/model/server/battery.dart index 7272f765..b2928399 100644 --- a/lib/data/model/server/battery.dart +++ b/lib/data/model/server/battery.dart @@ -1,4 +1,5 @@ -import 'package:toolbox/data/res/logger.dart'; + +import 'package:fl_lib/fl_lib.dart'; /// raw dat from server: /// ```text @@ -92,7 +93,7 @@ abstract final class Batteries { if (onlyLiPoly && !bat.isLiPoly) continue; batteries.add(bat); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } oneBatLines.clear(); } else { diff --git a/lib/data/model/server/disk.dart b/lib/data/model/server/disk.dart index fffc9a03..920d1d5b 100644 --- a/lib/data/model/server/disk.dart +++ b/lib/data/model/server/disk.dart @@ -1,5 +1,4 @@ -import 'package:toolbox/core/extension/listx.dart'; -import 'package:toolbox/core/extension/numx.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/data/model/server/time_seq.dart'; import '../../res/misc.dart'; diff --git a/lib/data/model/server/memory.dart b/lib/data/model/server/memory.dart index fb144951..624e7fc5 100644 --- a/lib/data/model/server/memory.dart +++ b/lib/data/model/server/memory.dart @@ -1,4 +1,4 @@ -import 'package:toolbox/core/extension/listx.dart'; +import 'package:fl_lib/fl_lib.dart'; class Memory { final int total; diff --git a/lib/data/model/server/net_speed.dart b/lib/data/model/server/net_speed.dart index 133d9aeb..cedfd225 100644 --- a/lib/data/model/server/net_speed.dart +++ b/lib/data/model/server/net_speed.dart @@ -1,4 +1,4 @@ -import 'package:toolbox/core/extension/numx.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'time_seq.dart'; diff --git a/lib/data/model/server/proc.dart b/lib/data/model/server/proc.dart index 60956247..dad0d2f5 100644 --- a/lib/data/model/server/proc.dart +++ b/lib/data/model/server/proc.dart @@ -1,4 +1,4 @@ -import 'package:toolbox/data/res/logger.dart'; +import 'package:fl_lib/fl_lib.dart'; import '../../../data/res/misc.dart'; @@ -142,7 +142,7 @@ class PsResult { procs.add(Proc.parse(line, map)); } catch (e, trace) { errs.add('$line: $e'); - Loggers.parse.warning('Process failed', e, trace); + Loggers.app.warning('Process failed', e, trace); } } diff --git a/lib/data/model/server/pve.dart b/lib/data/model/server/pve.dart index 77f6430a..a37a89c4 100644 --- a/lib/data/model/server/pve.dart +++ b/lib/data/model/server/pve.dart @@ -1,7 +1,5 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/duration.dart'; -import 'package:toolbox/core/extension/numx.dart'; -import 'package:toolbox/core/extension/order.dart'; enum PveResType { lxc, @@ -132,7 +130,12 @@ final class PveLxc extends PveResIface implements PveCtrlIface { @override String get summary { if (available) { - return uptime.secondsToDuration().toStr; + return uptime.secondsToDuration().toAgoStr( + day: l10n.day, + hour: l10n.hour, + minute: l10n.minute, + second: l10n.second, + ); } return l10n.stopped; } @@ -210,7 +213,12 @@ final class PveQemu extends PveResIface implements PveCtrlIface { @override String get summary { if (available) { - return uptime.secondsToDuration().toStr; + return uptime.secondsToDuration().toAgoStr( + day: l10n.day, + hour: l10n.hour, + minute: l10n.minute, + second: l10n.second, + ); } return l10n.stopped; } @@ -260,7 +268,12 @@ final class PveNode extends PveResIface { String get topRight { if (isRunning) { - return uptime.secondsToDuration().toStr; + return uptime.secondsToDuration().toAgoStr( + day: l10n.day, + hour: l10n.hour, + minute: l10n.minute, + second: l10n.second, + ); } return l10n.stopped; } diff --git a/lib/data/model/server/sensors.dart b/lib/data/model/server/sensors.dart index 089208c2..55c9ae56 100644 --- a/lib/data/model/server/sensors.dart +++ b/lib/data/model/server/sensors.dart @@ -1,5 +1,5 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/data/res/logger.dart'; final class SensorAdaptor { final String raw; diff --git a/lib/data/model/server/server.dart b/lib/data/model/server/server.dart index ab767827..62bb4b90 100644 --- a/lib/data/model/server/server.dart +++ b/lib/data/model/server/server.dart @@ -1,6 +1,6 @@ import 'package:dartssh2/dartssh2.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/listx.dart'; import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/server/battery.dart'; diff --git a/lib/data/model/server/server_status_update_req.dart b/lib/data/model/server/server_status_update_req.dart index ac79fa09..21153185 100644 --- a/lib/data/model/server/server_status_update_req.dart +++ b/lib/data/model/server/server_status_update_req.dart @@ -1,9 +1,9 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/data/model/server/battery.dart'; import 'package:toolbox/data/model/server/nvdia.dart'; import 'package:toolbox/data/model/server/sensors.dart'; import 'package:toolbox/data/model/server/server.dart'; import 'package:toolbox/data/model/server/system.dart'; -import 'package:toolbox/data/res/logger.dart'; import '../app/shell_func.dart'; import 'cpu.dart'; @@ -45,7 +45,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { final net = NetSpeed.parse(StatusCmdType.net.find(segments), time); req.ss.netSpeed.update(net); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -56,7 +56,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { req.ss.more[StatusCmdType.sys] = sys; } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -65,14 +65,14 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { req.ss.more[StatusCmdType.host] = host; } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { final cpus = SingleCpuCore.parse(StatusCmdType.cpu.find(segments)); req.ss.cpu.update(cpus); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -81,7 +81,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { StatusCmdType.tempVal.find(segments), ); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -90,20 +90,20 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { req.ss.tcp = tcp; } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { req.ss.disk = Disk.parse(StatusCmdType.disk.find(segments)); req.ss.diskUsage = DiskUsage.parse(req.ss.disk); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { req.ss.mem = Memory.parse(StatusCmdType.mem.find(segments)); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -112,26 +112,26 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { req.ss.more[StatusCmdType.uptime] = uptime; } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { req.ss.swap = Swap.parse(StatusCmdType.mem.find(segments)); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { final diskio = DiskIO.parse(StatusCmdType.diskio.find(segments), time); req.ss.diskIO.update(diskio); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { req.ss.nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments)); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -144,7 +144,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { req.ss.batteries.addAll(batteries); } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -154,7 +154,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { req.ss.sensors.addAll(sensors); } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { @@ -164,7 +164,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { req.ss.customCmds[key] = value; } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } return req.ss; @@ -179,25 +179,25 @@ Future _getBsdStatus(ServerStatusUpdateReq req) async { final net = NetSpeed.parseBsd(BSDStatusCmdType.net.find(segments), time); req.ss.netSpeed.update(net); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { req.ss.more[StatusCmdType.sys] = BSDStatusCmdType.sys.find(segments); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { req.ss.cpu = parseBsdCpu(BSDStatusCmdType.cpu.find(segments)); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } // try { // req.ss.mem = parseBsdMem(BSDStatusCmdType.mem.find(segments)); // } catch (e, s) { - // Loggers.parse.warning(e, s); + // Loggers.app.warning(e, s); // } try { @@ -206,13 +206,13 @@ Future _getBsdStatus(ServerStatusUpdateReq req) async { req.ss.more[StatusCmdType.uptime] = uptime; } } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } try { req.ss.disk = Disk.parse(BSDStatusCmdType.disk.find(segments)); } catch (e, s) { - Loggers.parse.warning(e, s); + Loggers.app.warning(e, s); } return req.ss; } diff --git a/lib/data/model/sftp/absolute_path.dart b/lib/data/model/sftp/absolute_path.dart index 11c92d25..360c6522 100644 --- a/lib/data/model/sftp/absolute_path.dart +++ b/lib/data/model/sftp/absolute_path.dart @@ -1,4 +1,4 @@ -import 'package:toolbox/core/utils/misc.dart'; +import 'package:fl_lib/fl_lib.dart'; class AbsolutePath { String _path; @@ -24,7 +24,7 @@ class AbsolutePath { _path = newPath; return; } - _path = pathJoin(_path, newPath); + _path = _path.joinPath(newPath, seperator: '/'); } bool undo() { diff --git a/lib/data/model/sftp/req.dart b/lib/data/model/sftp/req.dart index 493c5a6d..860007a7 100644 --- a/lib/data/model/sftp/req.dart +++ b/lib/data/model/sftp/req.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:toolbox/data/res/logger.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/data/res/store.dart'; import '../../../core/utils/server.dart'; diff --git a/lib/data/provider/container.dart b/lib/data/provider/container.dart index d99b6d46..55b08a8d 100644 --- a/lib/data/provider/container.dart +++ b/lib/data/provider/container.dart @@ -2,17 +2,15 @@ import 'dart:async'; import 'dart:convert'; import 'package:dartssh2/dartssh2.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/listx.dart'; import 'package:toolbox/core/extension/ssh_client.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/container/image.dart'; import 'package:toolbox/data/model/container/ps.dart'; import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/container/type.dart'; -import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/core/extension/uint8list.dart'; final _dockerNotFound = RegExp(r"command not found|Unknown command|Command '\w+' not found"); @@ -105,7 +103,7 @@ class ContainerProvider extends ChangeNotifier { type: ContainerErrType.segmentsNotMatch, message: 'Container segments: ${segments.length}', ); - Loggers.parse.warning('Container segments: ${segments.length}\n$raw'); + Loggers.app.warning('Container segments: ${segments.length}\n$raw'); notifyListeners(); return; } @@ -119,7 +117,7 @@ class ContainerProvider extends ChangeNotifier { type: ContainerErrType.invalidVersion, message: '$e', ); - Loggers.parse.warning('Container version failed', e, trace); + Loggers.app.warning('Container version failed', e, trace); } finally { notifyListeners(); } @@ -135,7 +133,7 @@ class ContainerProvider extends ChangeNotifier { type: ContainerErrType.parsePs, message: '$e', ); - Loggers.parse.warning('Container ps failed', e, trace); + Loggers.app.warning('Container ps failed', e, trace); } finally { notifyListeners(); } @@ -151,7 +149,7 @@ class ContainerProvider extends ChangeNotifier { type: ContainerErrType.parseImages, message: '$e', ); - Loggers.parse.warning('Container images failed', e, trace); + Loggers.app.warning('Container images failed', e, trace); } finally { notifyListeners(); } @@ -177,7 +175,7 @@ class ContainerProvider extends ChangeNotifier { type: ContainerErrType.parseStats, message: '$e', ); - Loggers.parse.warning('Parse docker stats: $statsRaw', e, trace); + Loggers.app.warning('Parse docker stats: $statsRaw', e, trace); } finally { notifyListeners(); } diff --git a/lib/data/provider/debug.dart b/lib/data/provider/debug.dart index 68727a41..a073fa91 100644 --- a/lib/data/provider/debug.dart +++ b/lib/data/provider/debug.dart @@ -1,7 +1,6 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; -import 'package:toolbox/core/extension/datetime.dart'; -import 'package:toolbox/data/res/ui.dart'; import '../../data/res/misc.dart'; diff --git a/lib/data/provider/pve.dart b/lib/data/provider/pve.dart index 84c56e17..64fc9c21 100644 --- a/lib/data/provider/pve.dart +++ b/lib/data/provider/pve.dart @@ -4,12 +4,12 @@ import 'dart:io'; import 'package:computer/computer.dart'; import 'package:dio/dio.dart'; import 'package:dio/io.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/server/pve.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; -import 'package:toolbox/data/res/logger.dart'; typedef PveCtrlFunc = Future Function(String node, String id); diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index e304098b..e06bbfce 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -3,22 +3,17 @@ import 'dart:io'; import 'package:computer/computer.dart'; import 'package:dartssh2/dartssh2.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/ssh_client.dart'; -import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/core/utils/ssh_auth.dart'; -import 'package:toolbox/core/utils/platform/path.dart'; import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/server/system.dart'; import 'package:toolbox/data/model/sftp/req.dart'; -import 'package:toolbox/data/res/logger.dart'; -import 'package:toolbox/data/res/path.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; -import '../../core/extension/order.dart'; -import '../../core/extension/uint8list.dart'; import '../../core/utils/server.dart'; import '../model/server/server.dart'; import '../model/server/server_private_info.dart'; @@ -344,7 +339,7 @@ class ServerProvider extends ChangeNotifier { Loggers.app.warning('Write script to ${spi.name} by shell', e); /// by sftp - final localPath = joinPath(await Paths.doc, 'install.sh'); + final localPath = Paths.doc.joinPath('install.sh'); final file = File(localPath); try { file.writeAsBytes(scriptRaw); @@ -455,7 +450,7 @@ class ServerProvider extends ChangeNotifier { message: 'Parse failed: $e\n\n$raw', ); _setServerState(s, ServerConn.failed); - Loggers.parse.warning('Server status', e, trace); + Loggers.app.warning('Server status', e, trace); return; } diff --git a/lib/data/provider/snippet.dart b/lib/data/provider/snippet.dart index 7fa6cad4..280d37c4 100644 --- a/lib/data/provider/snippet.dart +++ b/lib/data/provider/snippet.dart @@ -1,11 +1,10 @@ import 'dart:convert'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/data/model/server/snippet.dart'; import 'package:toolbox/data/res/store.dart'; -import '../../core/extension/order.dart'; - class SnippetProvider extends ChangeNotifier { late List _snippets; List get snippets => _snippets; diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index b802ce1a..4a118d94 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 = 893; + static const int build = 896; static const String engine = "3.19.6"; - static const String buildAt = "2024-05-10 20:57:55"; - static const int modifications = 8; + static const String buildAt = "2024-05-12 15:46:37"; + static const int modifications = 3; static const int script = 47; } diff --git a/lib/data/res/color.dart b/lib/data/res/color.dart deleted file mode 100644 index 1f2675a3..00000000 --- a/lib/data/res/color.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../model/app/dynamic_color.dart'; - -var primaryColor = const Color(0xff8b2252); - -abstract final class DynamicColors { - static const content = DynamicColor(Colors.black87, Colors.white70); - static const bg = DynamicColor(Colors.white, Colors.black); - static const progress = DynamicColor(Colors.black12, Colors.white10); -} diff --git a/lib/data/res/logger.dart b/lib/data/res/logger.dart deleted file mode 100644 index c738e428..00000000 --- a/lib/data/res/logger.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:logging/logging.dart'; - -abstract final class Loggers { - static final root = Logger('Root'); - static final app = Logger('App'); - static final parse = Logger('Parse'); -} diff --git a/lib/data/res/path.dart b/lib/data/res/path.dart deleted file mode 100644 index 79d8d9d9..00000000 --- a/lib/data/res/path.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'dart:io'; - -import 'package:path_provider/path_provider.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/core/utils/platform/path.dart'; - -abstract final class Paths { - static String? _docDir; - static String? _sftpDir; - static String? _fontDir; - - static Future get doc async { - if (_docDir != null) { - return _docDir!; - } - if (isAndroid) { - final dir = await getExternalStorageDirectory(); - if (dir != null) { - _docDir = dir.path; - return dir.path; - } - // fallthrough to getApplicationDocumentsDirectory - } - final dir = await getApplicationDocumentsDirectory(); - _docDir = dir.path; - return dir.path; - } - - static Future get sftp async { - if (_sftpDir != null) { - return _sftpDir!; - } - _sftpDir = '${await doc}/sftp'; - final dir = Directory(_sftpDir!); - await dir.create(recursive: true); - return _sftpDir!; - } - - static Future get font async { - if (_fontDir != null) { - return _fontDir!; - } - _fontDir = '${await doc}/font'; - final dir = Directory(_fontDir!); - await dir.create(recursive: true); - return _fontDir!; - } - - static const String bakName = 'srvbox_bak.json'; - - static Future get bak async => '${await doc}/$bakName'; - - static Future get dl async => joinPath(await doc, 'dl'); -} diff --git a/lib/data/res/provider.dart b/lib/data/res/provider.dart index ab84f30b..2fd135f9 100644 --- a/lib/data/res/provider.dart +++ b/lib/data/res/provider.dart @@ -4,15 +4,14 @@ import 'package:toolbox/data/provider/private_key.dart'; import 'package:toolbox/data/provider/server.dart'; import 'package:toolbox/data/provider/sftp.dart'; import 'package:toolbox/data/provider/snippet.dart'; -import 'package:toolbox/locator.dart'; abstract final class Pros { - static final app = locator(); - static final debug = locator(); - static final key = locator(); - static final server = locator(); - static final sftp = locator(); - static final snippet = locator(); + static final app = AppProvider(); + static final debug = DebugProvider(); + static final key = PrivateKeyProvider(); + static final server = ServerProvider(); + static final sftp = SftpProvider(); + static final snippet = SnippetProvider(); static void reload() { key.load(); diff --git a/lib/data/res/store.dart b/lib/data/res/store.dart index ef4fe067..a2c4ce9a 100644 --- a/lib/data/res/store.dart +++ b/lib/data/res/store.dart @@ -1,19 +1,18 @@ -import 'package:toolbox/core/persistant_store.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/data/store/container.dart'; import 'package:toolbox/data/store/history.dart'; import 'package:toolbox/data/store/private_key.dart'; import 'package:toolbox/data/store/server.dart'; import 'package:toolbox/data/store/setting.dart'; import 'package:toolbox/data/store/snippet.dart'; -import 'package:toolbox/locator.dart'; abstract final class Stores { - static final setting = locator(); - static final server = locator(); - static final container = locator(); - static final history = locator(); - static final key = locator(); - static final snippet = locator(); + static final setting = SettingStore(); + static final server = ServerStore(); + static final container = ContainerStore(); + static final history = HistoryStore(); + static final key = PrivateKeyStore(); + static final snippet = SnippetStore(); static final List all = [ setting, diff --git a/lib/data/res/ui.dart b/lib/data/res/ui.dart deleted file mode 100644 index c09a5c6a..00000000 --- a/lib/data/res/ui.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; - -abstract final class UIs { - /// Font style - - static const text11 = TextStyle(fontSize: 11); - static const text11Bold = TextStyle( - fontSize: 11, - fontWeight: FontWeight.w500, - ); - static const text11Grey = TextStyle(color: Colors.grey, fontSize: 11); - static const text12 = TextStyle(fontSize: 12); - static const text12Bold = TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ); - static const text12Grey = TextStyle(color: Colors.grey, fontSize: 12); - static const text13 = TextStyle(fontSize: 13); - static const text13Bold = TextStyle( - fontSize: 13, - fontWeight: FontWeight.bold, - ); - static const text13Grey = TextStyle(color: Colors.grey, fontSize: 13); - static const text15 = TextStyle(fontSize: 15); - static const text15Bold = TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ); - static const text18 = TextStyle(fontSize: 18); - static const text27 = TextStyle(fontSize: 27); - static const textGrey = TextStyle(color: Colors.grey); - static const textRed = TextStyle(color: Colors.red); - - /// Icon - - static final appIcon = Image.asset('assets/app_icon.png'); - - /// Padding - - static const roundRectCardPadding = - EdgeInsets.symmetric(horizontal: 17, vertical: 13); - - /// SizedBox - - static const placeholder = SizedBox(); - static const height7 = SizedBox(height: 7); - static const height13 = SizedBox(height: 13); - static const height77 = SizedBox(height: 77); - static const width13 = SizedBox(width: 13); - static const width7 = SizedBox(width: 7); - - /// Misc - - static const popMenuChild = Padding( - padding: EdgeInsets.only(left: 7), - child: Icon( - Icons.more_vert, - size: 21, - ), - ); - - static const centerLoading = Center(child: CircularProgressIndicator()); - - static const centerSizedLoadingSmall = SizedBox( - width: 23, - height: 23, - child: Center( - child: CircularProgressIndicator(), - ), - ); - - static const centerSizedLoading = SizedBox( - width: 77, - height: 77, - child: Center( - child: CircularProgressIndicator(), - ), - ); -} diff --git a/lib/data/res/url.dart b/lib/data/res/url.dart index 82da2e26..5dc7b898 100644 --- a/lib/data/res/url.dart +++ b/lib/data/res/url.dart @@ -1,5 +1,6 @@ abstract final class Urls { static const cdnBase = 'https://cdn.lolli.tech/serverbox'; + static const updateCfg = '$cdnBase/update.json'; static const myGithub = 'https://github.com/lollipopkit'; static const appHelp = '$myGithub/flutter_server_box#-help'; static const appWiki = '$myGithub/flutter_server_box/wiki'; diff --git a/lib/data/service/app.dart b/lib/data/service/app.dart deleted file mode 100644 index f903406b..00000000 --- a/lib/data/service/app.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:dio/dio.dart'; - -import '../model/app/update.dart'; -import '../res/url.dart'; - -class AppService { - Future getUpdate() async { - final resp = await Dio().get('${Urls.cdnBase}/update.json'); - return AppUpdate.fromJson(resp.data); - } -} diff --git a/lib/data/store/container.dart b/lib/data/store/container.dart index 8cac168b..5c29998f 100644 --- a/lib/data/store/container.dart +++ b/lib/data/store/container.dart @@ -1,8 +1,7 @@ -import 'package:toolbox/core/extension/listx.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/data/model/container/type.dart'; import 'package:toolbox/data/res/store.dart'; -import '../../core/persistant_store.dart'; const _keyConfig = 'providerConfig'; diff --git a/lib/data/store/history.dart b/lib/data/store/history.dart index a6670d7a..6d7ba081 100644 --- a/lib/data/store/history.dart +++ b/lib/data/store/history.dart @@ -1,5 +1,5 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:hive_flutter/hive_flutter.dart'; -import 'package:toolbox/core/persistant_store.dart'; /// index from 0 -> n : latest -> oldest class _ListHistory { diff --git a/lib/data/store/private_key.dart b/lib/data/store/private_key.dart index 5c9ce4fa..63bc2251 100644 --- a/lib/data/store/private_key.dart +++ b/lib/data/store/private_key.dart @@ -1,4 +1,5 @@ -import '../../core/persistant_store.dart'; +import 'package:fl_lib/fl_lib.dart'; + import '../model/server/private_key_info.dart'; class PrivateKeyStore extends PersistentStore { diff --git a/lib/data/store/server.dart b/lib/data/store/server.dart index 36e544ac..aebcd9b9 100644 --- a/lib/data/store/server.dart +++ b/lib/data/store/server.dart @@ -1,4 +1,5 @@ -import '../../core/persistant_store.dart'; +import 'package:fl_lib/fl_lib.dart'; + import '../model/server/server_private_info.dart'; class ServerStore extends PersistentStore { diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index 5b4a4aad..8f96547d 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -1,5 +1,4 @@ -import 'package:toolbox/core/persistant_store.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/model/app/server_detail_card.dart'; import 'package:toolbox/data/model/ssh/virtual_key.dart'; diff --git a/lib/data/store/snippet.dart b/lib/data/store/snippet.dart index 72b25b5b..53c84cad 100644 --- a/lib/data/store/snippet.dart +++ b/lib/data/store/snippet.dart @@ -1,4 +1,5 @@ -import '../../core/persistant_store.dart'; +import 'package:fl_lib/fl_lib.dart'; + import '../model/server/snippet.dart'; class SnippetStore extends PersistentStore { diff --git a/lib/locator.dart b/lib/locator.dart deleted file mode 100644 index 68b93b22..00000000 --- a/lib/locator.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:get_it/get_it.dart'; - -import 'data/provider/app.dart'; -import 'data/provider/debug.dart'; -import 'data/provider/private_key.dart'; -import 'data/provider/server.dart'; -import 'data/provider/sftp.dart'; -import 'data/provider/snippet.dart'; -import 'data/provider/virtual_keyboard.dart'; -import 'data/service/app.dart'; -import 'data/store/container.dart'; -import 'data/store/history.dart'; -import 'data/store/private_key.dart'; -import 'data/store/server.dart'; -import 'data/store/setting.dart'; -import 'data/store/snippet.dart'; - -GetIt locator = GetIt.instance; - -void _setupLocatorForServices() { - locator.registerLazySingleton(() => AppService()); -} - -void _setupLocatorForProviders() { - locator.registerSingleton(AppProvider()); - locator.registerSingleton(DebugProvider()); - locator.registerSingleton(ServerProvider()); - locator.registerSingleton(VirtKeyProvider()); - locator.registerSingleton(SnippetProvider()); - locator.registerSingleton(PrivateKeyProvider()); - locator.registerSingleton(SftpProvider()); -} - -Future _setupLocatorForStores() async { - final setting = SettingStore(); - await setting.init(); - locator.registerSingleton(setting); - - final server = ServerStore(); - await server.init(); - locator.registerSingleton(server); - - final key = PrivateKeyStore(); - await key.init(); - locator.registerSingleton(key); - - final snippet = SnippetStore(); - await snippet.init(); - locator.registerSingleton(snippet); - - final docker = ContainerStore(); - await docker.init(); - locator.registerSingleton(docker); - - final history = HistoryStore(); - await history.init(); - locator.registerSingleton(history); -} - -Future setupLocator() async { - await _setupLocatorForStores(); - _setupLocatorForProviders(); - _setupLocatorForServices(); -} diff --git a/lib/main.dart b/lib/main.dart index 6856fcb2..2b4f62c3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,40 +3,30 @@ import 'dart:async'; import 'package:computer/computer.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:toolbox/core/channel/bg_run.dart'; import 'package:toolbox/core/utils/sync/icloud.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/sync/webdav.dart'; import 'package:toolbox/core/utils/ui.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/model/app/version_related.dart'; import 'package:toolbox/data/model/server/custom.dart'; import 'package:toolbox/data/res/build_data.dart'; -import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:window_manager/window_manager.dart'; import 'app.dart'; -import 'core/analysis.dart'; import 'data/model/app/net_view.dart'; import 'data/model/server/private_key_info.dart'; import 'data/model/server/server_private_info.dart'; import 'data/model/server/snippet.dart'; import 'data/model/ssh/virtual_key.dart'; -import 'data/provider/app.dart'; -import 'data/provider/private_key.dart'; -import 'data/provider/server.dart'; -import 'data/provider/sftp.dart'; -import 'data/provider/snippet.dart'; -import 'locator.dart'; -import 'view/widget/appbar.dart'; Future main() async { _runInZone(() async { @@ -44,11 +34,11 @@ Future main() async { runApp( MultiProvider( providers: [ - ChangeNotifierProvider(create: (_) => locator()), - ChangeNotifierProvider(create: (_) => locator()), - ChangeNotifierProvider(create: (_) => locator()), - ChangeNotifierProvider(create: (_) => locator()), - ChangeNotifierProvider(create: (_) => locator()), + ChangeNotifierProvider(create: (_) => Pros.app), + ChangeNotifierProvider(create: (_) => Pros.server), + ChangeNotifierProvider(create: (_) => Pros.snippet), + ChangeNotifierProvider(create: (_) => Pros.key), + ChangeNotifierProvider(create: (_) => Pros.sftp), ], child: const MyApp(), ), @@ -76,30 +66,28 @@ void _runInZone(void Function() body) { Future _initApp() async { WidgetsFlutterBinding.ensureInitialized(); + await Paths.init(BuildData.name); + // Base of all data. await _initDb(); - await setupLocator(); - await _initDesktopWindow(); - Computer.shared.turnOn( - // Plus 1 to avoid 0. - workersCount: (Stores.server.box.keys.length / 3).round() + 1, - ); + + _initDesktopWindow(); _setupLogger(); - _setupProviders(); // Load font loadFontFile(Stores.setting.fontPath.fetch()); if (isAndroid) { - // Only start service when [bgRun] is true. - if (Stores.setting.bgRun.fetch()) { - BgRunMC.startService(); - } // SharedPreferences is only used on Android for saving home widgets settings. SharedPreferences.setPrefix(''); // try switch to highest refresh rate await FlutterDisplayMode.setHighRefreshRate(); } + + final serversCount = Stores.server.box.keys.length; + // Plus 1 to avoid 0. + Computer.shared.turnOn(workersCount: (serversCount / 3).round() + 1); + if (isIOS || isMacOS) { if (Stores.setting.icloudSync.fetch()) ICloud.sync(); } @@ -108,11 +96,6 @@ Future _initApp() async { _doVersionRelated(); } -void _setupProviders() { - Pros.snippet.load(); - Pros.key.load(); -} - Future _initDb() async { // await SecureStore.init(); await Hive.initFlutter(); @@ -124,6 +107,16 @@ Future _initDb() async { Hive.registerAdapter(NetViewTypeAdapter()); // 5 Hive.registerAdapter(ServerFuncBtnAdapter()); // 6 Hive.registerAdapter(ServerCustomAdapter()); // 7 + + await Stores.setting.init(); + await Stores.server.init(); + await Stores.key.init(); + await Stores.snippet.init(); + await Stores.container.init(); + await Stores.history.init(); + + Pros.snippet.load(); + Pros.key.load(); } void _setupLogger() { @@ -136,11 +129,11 @@ void _setupLogger() { }); } -Future _initDesktopWindow() async { +void _initDesktopWindow() async { if (!isDesktop) return; await windowManager.ensureInitialized(); - await CustomAppBar.updateTitlebarHeight(); + await CustomAppBar.updateTitlebarHeight(Stores.setting.hideTitleBar.fetch()); final windowOptions = WindowOptions( center: true, diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart index b7416804..d9770f50 100644 --- a/lib/view/page/backup.dart +++ b/lib/view/page/backup.dart @@ -2,31 +2,16 @@ import 'dart:convert'; import 'dart:io'; import 'package:computer/computer.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/extension/datetime.dart'; -import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/sync/icloud.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/core/utils/sync/webdav.dart'; import 'package:toolbox/data/model/app/backup.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; -import 'package:toolbox/data/res/logger.dart'; -import 'package:toolbox/data/res/path.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/url.dart'; -import 'package:toolbox/view/widget/appbar.dart'; -import 'package:toolbox/view/widget/expand_tile.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/input_field.dart'; -import 'package:toolbox/view/widget/markdown.dart'; -import 'package:toolbox/view/widget/store_switch.dart'; class BackupPage extends StatelessWidget { BackupPage({super.key}); @@ -82,11 +67,12 @@ class BackupPage extends StatelessWidget { final path = await Backup.backup(); /// Issue #188 - if (isWindows) { - await Shares.text(await File(path).readAsString()); - } else { - await Shares.files([path]); - } + final _ = switch (Pfs.type) { + Pfs.windows => + await Process.run('explorer', ['/select,', path]), + Pfs.linux => await Process.run('xdg-open', [path]), + _ => await Pfs.sharePath(path), + }; }, ), ListTile( @@ -206,7 +192,7 @@ class BackupPage extends StatelessWidget { trailing: const Icon(Icons.save), onTap: () async { final path = await Backup.backup(); - Shares.copy(await File(path).readAsString()); + Pfs.copy(await File(path).readAsString()); context.showSnackBar(l10n.success); }, ), @@ -232,25 +218,14 @@ class BackupPage extends StatelessWidget { ), leading: const Icon(Icons.import_export), onTap: () => _onBulkImportServers(context), + trailing: const Icon(Icons.keyboard_arrow_right), ), ); } Future _onTapFileRestore(BuildContext context) async { - final path = await pickOneFile(); - if (path == null) return; - - final file = File(path); - if (!await file.exists()) { - context.showSnackBar(l10n.fileNotExist(path)); - return; - } - - final text = await file.readAsString(); - if (text.isEmpty) { - context.showSnackBar(l10n.fieldMustNotEmpty); - return; - } + final text = await Pfs.pickFileString(); + if (text == null) return; try { final backup = await context.showLoadingDialog( @@ -262,7 +237,7 @@ class BackupPage extends StatelessWidget { } await context.showRoundDialog( - title: Text(l10n.restore), + title: l10n.restore, child: Text(l10n.askContinue( '${l10n.restore} ${l10n.backup}(${backup.date})', )), @@ -296,7 +271,7 @@ class BackupPage extends StatelessWidget { } final fileName = await context.showRoundDialog( - title: Text(l10n.restore), + title: l10n.restore, child: SizedBox( width: 300, height: 300, @@ -329,7 +304,7 @@ class BackupPage extends StatelessWidget { webdavLoading.value = false; return; } - final dlFile = await File('${await Paths.doc}/$fileName').readAsString(); + final dlFile = await File('${Paths.doc}/$fileName').readAsString(); final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile); await dlBak.restore(force: true); webdavLoading.value = false; @@ -337,7 +312,7 @@ class BackupPage extends StatelessWidget { Future _onTapWebdavUp(BuildContext context) async { webdavLoading.value = true; - final bakName = '${DateTime.now().numStr}-${Paths.bakName}'; + final bakName = '${DateTime.now().ymdhms()}-${Paths.bakName}'; await Backup.backup(bakName); final uploadResult = await Webdav.upload(relativePath: bakName); if (uploadResult != null) { @@ -359,7 +334,7 @@ class BackupPage extends StatelessWidget { text: Stores.setting.webdavPwd.fetch(), ); final result = await context.showRoundDialog( - title: const Text('WebDAV'), + title: 'WebDAV', child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -401,7 +376,7 @@ class BackupPage extends StatelessWidget { } void _onTapClipboardRestore(BuildContext context) async { - final text = await Shares.paste(); + final text = await Pfs.paste(); if (text == null || text.isEmpty) { context.showSnackBar(l10n.fieldMustNotEmpty); return; @@ -418,7 +393,7 @@ class BackupPage extends StatelessWidget { } await context.showRoundDialog( - title: Text(l10n.restore), + title: l10n.restore, child: Text(l10n.askContinue( '${l10n.restore} ${l10n.backup}(${backup.date})', )), @@ -443,26 +418,8 @@ class BackupPage extends StatelessWidget { } void _onBulkImportServers(BuildContext context) async { - final path = await pickOneFile(); - if (path == null) return; - - final file = File(path); - if (!await file.exists()) { - context.showRoundDialog( - title: Text(l10n.error), - child: Text(l10n.fileNotExist(path)), - ); - return; - } - - final text = await file.readAsString(); - if (text.isEmpty) { - context.showRoundDialog( - title: Text(l10n.error), - child: Text(l10n.fieldMustNotEmpty), - ); - return; - } + final text = await Pfs.pickFileString(); + if (text == null) return; try { final spis = await context.showLoadingDialog( @@ -472,7 +429,7 @@ class BackupPage extends StatelessWidget { }, text.trim()), ); final sure = await context.showRoundDialog( - title: Text(l10n.import), + title: l10n.import, child: Text(l10n.askContinue('${spis.length} ${l10n.server}')), actions: [ TextButton( @@ -493,7 +450,7 @@ class BackupPage extends StatelessWidget { } } catch (e) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(e.toString()), ); } diff --git a/lib/view/page/container.dart b/lib/view/page/container.dart index 7dc9f629..d7458f8e 100644 --- a/lib/view/page/container.dart +++ b/lib/view/page/container.dart @@ -1,27 +1,20 @@ import 'dart:async'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/core/route.dart'; +import 'package:toolbox/data/model/app/menu/base.dart'; import 'package:toolbox/data/model/app/menu/container.dart'; import 'package:toolbox/data/model/container/image.dart'; import 'package:toolbox/data/model/container/type.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/expand_tile.dart'; -import 'package:toolbox/view/widget/input_field.dart'; import '../../data/model/container/ps.dart'; import '../../data/model/server/server_private_info.dart'; import '../../data/provider/container.dart'; -import '../../data/res/ui.dart'; -import '../widget/appbar.dart'; import '../widget/popup_menu.dart'; -import '../widget/cardx.dart'; import '../widget/two_line_text.dart'; class ContainerPage extends StatefulWidget { @@ -267,7 +260,8 @@ class _ContainerPageState extends State { Widget _buildMoreBtn(ContainerPs dItem) { return PopupMenu( - items: ContainerMenu.items(dItem.running).map((e) => e.widget).toList(), + items: ContainerMenu.items(dItem.running), + builder: (e) => PopMenu.build(e, e.icon, e.toStr), onSelected: (item) => _onTapMoreBtn(item, dItem), ); } @@ -331,7 +325,7 @@ class _ContainerPageState extends State { final nameCtrl = TextEditingController(); final argsCtrl = TextEditingController(); await context.showRoundDialog( - title: Text(l10n.newContainer), + title: l10n.newContainer, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -380,7 +374,7 @@ class _ContainerPageState extends State { Future _showAddCmdPreview(String cmd) async { await context.showRoundDialog( - title: Text(l10n.preview), + title: l10n.preview, child: Text(cmd), actions: [ TextButton( @@ -422,7 +416,7 @@ class _ContainerPageState extends State { final host = Stores.container.fetch(id); final ctrl = TextEditingController(text: host); await context.showRoundDialog( - title: Text(l10n.dockerEditHost), + title: l10n.dockerEditHost, child: Input( maxLines: 2, controller: ctrl, @@ -446,7 +440,7 @@ class _ContainerPageState extends State { void _showImageRmDialog(ContainerImg e) { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue('${l10n.delete} Image(${e.repository})')), actions: [ TextButton( @@ -477,7 +471,7 @@ class _ContainerPageState extends State { case ContainerMenu.rm: var force = false; context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -510,7 +504,7 @@ class _ContainerPageState extends State { ); if (result != null) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(result.message ?? l10n.unknownError), ); } @@ -526,7 +520,7 @@ class _ContainerPageState extends State { ); if (result != null) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(result.message ?? l10n.unknownError), ); } @@ -537,7 +531,7 @@ class _ContainerPageState extends State { ); if (result != null) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(result.message ?? l10n.unknownError), ); } @@ -548,19 +542,19 @@ class _ContainerPageState extends State { ); if (result != null) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(result.message ?? l10n.unknownError), ); } break; case ContainerMenu.logs: - AppRoute.ssh( + AppRoutes.ssh( spi: widget.spi, initCmd: 'docker logs -f --tail 100 ${dItem.id}', ).go(context); break; case ContainerMenu.terminal: - AppRoute.ssh( + AppRoutes.ssh( spi: widget.spi, initCmd: 'docker exec -it ${dItem.id} sh', ).go(context); diff --git a/lib/view/page/debug.dart b/lib/view/page/debug.dart index 6e503950..c6fb86fa 100644 --- a/lib/view/page/debug.dart +++ b/lib/view/page/debug.dart @@ -1,10 +1,9 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/data/provider/debug.dart'; import 'package:toolbox/data/res/provider.dart'; -import '../widget/appbar.dart'; class DebugPage extends StatelessWidget { const DebugPage({super.key}); diff --git a/lib/view/page/editor.dart b/lib/view/page/editor.dart index c6265cca..1aba15df 100644 --- a/lib/view/page/editor.dart +++ b/lib/view/page/editor.dart @@ -3,18 +3,16 @@ import 'dart:io'; import 'package:code_text_field/code_text_field.dart'; import 'package:computer/computer.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_highlight/theme_map.dart'; import 'package:flutter_highlight/themes/a11y-light.dart'; import 'package:flutter_highlight/themes/monokai.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/data/res/highlight.dart'; import 'package:toolbox/data/res/store.dart'; -import '../widget/appbar.dart'; import '../widget/two_line_text.dart'; class EditorPage extends StatefulWidget { diff --git a/lib/view/page/home/home.dart b/lib/view/page/home/home.dart index 8f775394..0353b7c6 100644 --- a/lib/view/page/home/home.dart +++ b/lib/view/page/home/home.dart @@ -1,38 +1,24 @@ import 'dart:convert'; import 'package:after_layout/after_layout.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:get_it/get_it.dart'; import 'package:icons_plus/icons_plus.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:toolbox/core/channel/bg_run.dart'; import 'package:toolbox/core/channel/home_widget.dart'; import 'package:toolbox/core/extension/build.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/core/route.dart'; -import 'package:toolbox/core/update.dart'; -import 'package:toolbox/core/utils/platform/auth.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/core/utils/platform/perm.dart'; import 'package:toolbox/core/utils/ui.dart'; import 'package:toolbox/data/model/app/github_id.dart'; import 'package:toolbox/data/model/app/tab.dart'; import 'package:toolbox/data/res/build_data.dart'; import 'package:toolbox/data/res/github_id.dart'; -import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/url.dart'; -import 'package:toolbox/view/widget/appbar.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/markdown.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; part 'appbar.dart'; @@ -100,7 +86,9 @@ class _HomePageState extends State switch (state) { case AppLifecycleState.resumed: if (_shouldAuth) { - BioAuth.go().then((_) => _shouldAuth = false); + if (Stores.setting.useBioAuth.fetch()) { + BioAuth.go().then((_) => _shouldAuth = false); + } } if (!Pros.server.isAutoRefreshOn) { Pros.server.startAutoRefresh(); @@ -112,9 +100,9 @@ class _HomePageState extends State // Keep running in background on Android device if (isAndroid && Stores.setting.bgRun.fetch()) { // Keep this if statement single - if (Pros.app.moveBg) { - BgRunMC.moveToBg(); - } + // if (Pros.app.moveBg) { + // BgRunMC.moveToBg(); + // } } else { //Pros.server.setDisconnected(); Pros.server.stopAutoRefresh(); @@ -152,7 +140,7 @@ class _HomePageState extends State IconButton( icon: const Icon(Icons.developer_mode, size: 21), tooltip: l10n.debug, - onPressed: () => AppRoute.debug().go(context), + onPressed: () => AppRoutes.debug().go(context), ), ], ); @@ -239,7 +227,7 @@ class _HomePageState extends State _buildIcon(), TextButton( onPressed: () => context.showRoundDialog( - title: const Text(BuildDataX.versionStr), + title: BuildDataX.versionStr, child: const Text( '${BuildData.buildAt}\nFlutter ${BuildData.engine}'), ), @@ -264,23 +252,23 @@ class _HomePageState extends State ListTile( leading: const Icon(Icons.settings), title: Text(l10n.setting), - onTap: () => AppRoute.settings().go(context), + onTap: () => AppRoutes.settings().go(context), onLongPress: _onLongPressSetting, ), ListTile( leading: const Icon(Icons.vpn_key), title: Text(l10n.privateKey), - onTap: () => AppRoute.keyList().go(context), + onTap: () => AppRoutes.keyList().go(context), ), ListTile( leading: const Icon(BoxIcons.bxs_file_blank), title: Text(l10n.files), - onTap: () => AppRoute.localStorage().go(context), + onTap: () => AppRoutes.localStorage().go(context), ), ListTile( leading: const Icon(MingCute.file_import_fill), title: Text(l10n.backup), - onTap: () => AppRoute.backup().go(context), + onTap: () => AppRoutes.backup().go(context), ), ListTile( leading: const Icon(OctIcons.feed_discussion), @@ -294,7 +282,7 @@ class _HomePageState extends State void _showAboutDialog() { context.showRoundDialog( - title: Text(l10n.about), + title: l10n.about, child: _buildAboutContent(), actions: [ TextButton( @@ -348,15 +336,19 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')} @override Future afterFirstLayout(BuildContext context) async { // Auth required for first launch - BioAuth.go(); + if (Stores.setting.useBioAuth.fetch()) BioAuth.go(); _reqNotiPerm(); if (Stores.setting.autoCheckAppUpdate.fetch()) { - doUpdate(context); + AppUpdateIface.doUpdate( + build: BuildData.build, + url: '${Urls.cdnBase}/update.json', + context: context, + updateL10n: l10n.update, + ); } HomeWidgetMC.update(); - await GetIt.I.allReady(); await Pros.server.load(); await Pros.server.refresh(); } @@ -369,7 +361,7 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')} final noNotiPerm = Stores.setting.noNotiPerm; if (noNotiPerm.fetch()) return; context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(l10n.noNotiPerm), actions: [ TextButton( @@ -390,7 +382,7 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')} /// Encode [map] to String with indent `\t` final text = Miscs.jsonEncoder.convert(map); - final result = await AppRoute.editor( + final result = await AppRoutes.editor( text: text, langCode: 'json', title: l10n.setting, @@ -408,7 +400,7 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')} } } catch (e, trace) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text('${l10n.save}:\n$e'), ); Loggers.app.warning('Update json settings failed', e, trace); diff --git a/lib/view/page/iperf.dart b/lib/view/page/iperf.dart index 31fd32c7..12ec993d 100644 --- a/lib/view/page/iperf.dart +++ b/lib/view/page/iperf.dart @@ -1,10 +1,8 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/route.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; -import 'package:toolbox/view/widget/appbar.dart'; -import 'package:toolbox/view/widget/input_field.dart'; class IPerfPage extends StatefulWidget { final ServerPrivateInfo spi; @@ -38,7 +36,7 @@ class _IPerfPageState extends State { context.showSnackBar(l10n.fieldMustNotEmpty); return; } - AppRoute.ssh( + AppRoutes.ssh( spi: widget.spi, initCmd: 'iperf -c ${_hostCtrl.text} -p ${_portCtrl.text}', ).go(context); diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart index f0415972..bac91e32 100644 --- a/lib/view/page/ping.dart +++ b/lib/view/page/ping.dart @@ -1,19 +1,11 @@ import 'dart:async'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; 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/share.dart'; import 'package:toolbox/data/res/provider.dart'; import '../../data/model/server/ping_result.dart'; -import '../../data/res/color.dart'; -import '../../data/res/ui.dart'; -import '../widget/input_field.dart'; -import '../widget/cardx.dart'; /// Only permit ipv4 / ipv6 / domain chars final targetReg = RegExp(r'[a-zA-Z0-9\.-_:]+'); @@ -61,7 +53,7 @@ class _PingPageState extends State heroTag: 'ping', onPressed: () { context.showRoundDialog( - title: Text(l10n.choose), + title: l10n.choose, child: Input( autoFocus: true, controller: _textEditingController, @@ -84,11 +76,11 @@ class _PingPageState extends State await doPing(); } catch (e) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(e.toString()), actions: [ TextButton( - onPressed: () => Shares.copy(e.toString()), + onPressed: () => Pfs.copy(e.toString()), child: Text(l10n.copy), ), ], @@ -125,7 +117,7 @@ class _PingPageState extends State style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, - color: primaryColor, + color: UIs.primaryColor, ), ), subtitle: Text( @@ -136,7 +128,7 @@ class _PingPageState extends State '${l10n.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? l10n.unknown} $ms', style: TextStyle( fontSize: 14, - color: primaryColor, + color: UIs.primaryColor, ), ), ), diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index 571965ed..f3b63050 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -1,23 +1,15 @@ import 'dart:io'; import 'package:computer/computer.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/extension/numx.dart'; -import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/provider.dart'; -import 'package:toolbox/view/widget/input_field.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; import '../../../core/utils/server.dart'; import '../../../data/model/server/private_key_info.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/appbar.dart'; const _format = 'text/plain'; @@ -91,7 +83,7 @@ class _PrivateKeyEditPageState extends State { tooltip: l10n.delete, onPressed: () { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue( '${l10n.delete} ${l10n.privateKey}(${widget.pki!.id})', )), @@ -181,7 +173,7 @@ class _PrivateKeyEditPageState extends State { ), TextButton( onPressed: () async { - final path = await pickOneFile(); + final path = await Pfs.pickFilePath(); if (path == null) return; final file = File(path); diff --git a/lib/view/page/private_key/list.dart b/lib/view/page/private_key/list.dart index 8abbbeb2..0e448e50 100644 --- a/lib/view/page/private_key/list.dart +++ b/lib/view/page/private_key/list.dart @@ -1,21 +1,15 @@ import 'dart:io'; import 'dart:async'; import 'package:after_layout/after_layout.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/core/utils/platform/path.dart'; import 'package:toolbox/data/res/store.dart'; import '../../../core/route.dart'; import '../../../data/model/server/private_key_info.dart'; import '../../../data/provider/private_key.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/appbar.dart'; -import '../../widget/cardx.dart'; class PrivateKeysListPage extends StatefulWidget { const PrivateKeysListPage({super.key}); @@ -35,7 +29,7 @@ class _PrivateKeyListState extends State body: _buildBody(), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), - onPressed: () => AppRoute.keyEdit().go(context), + onPressed: () => AppRoutes.keyEdit().go(context), ), ); } @@ -64,7 +58,7 @@ class _PrivateKeyListState extends State ), title: Text(item.id), subtitle: Text(item.type ?? l10n.unknown, style: UIs.textGrey), - onTap: () => AppRoute.keyEdit(pki: item).go(context), + onTap: () => AppRoutes.keyEdit(pki: item).go(context), trailing: const Icon(Icons.edit), ), ); @@ -77,22 +71,22 @@ class _PrivateKeyListState extends State void autoAddSystemPriavteKey() { // Only trigger on desktop platform and no private key saved if (isDesktop && Stores.snippet.box.keys.isEmpty) { - final home = getHomeDir(); + final home = Pfs.homeDir; if (home == null) return; - final idRsaFile = File(joinPath(home, '.ssh/id_rsa')); + final idRsaFile = File(home.joinPath('.ssh/id_rsa')); if (!idRsaFile.existsSync()) return; final sysPk = PrivateKeyInfo( id: 'system', key: idRsaFile.readAsStringSync(), ); context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.addSystemPrivateKeyTip), actions: [ TextButton( onPressed: () { context.pop(); - AppRoute.keyEdit(pki: sysPk).go(context); + AppRoutes.keyEdit(pki: sysPk).go(context); }, child: Text(l10n.ok), ), diff --git a/lib/view/page/process.dart b/lib/view/page/process.dart index 5fb2e473..4ac8de14 100644 --- a/lib/view/page/process.dart +++ b/lib/view/page/process.dart @@ -1,21 +1,14 @@ import 'dart:async'; import 'package:dartssh2/dartssh2.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; 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/share.dart'; import 'package:toolbox/data/res/store.dart'; import '../../data/model/app/shell_func.dart'; import '../../data/model/server/proc.dart'; import '../../data/model/server/server_private_info.dart'; -import '../../data/res/ui.dart'; -import '../widget/appbar.dart'; -import '../widget/cardx.dart'; import '../widget/two_line_text.dart'; class ProcessPage extends StatefulWidget { @@ -107,11 +100,11 @@ class _ProcessPageState extends State { actions.add(IconButton( icon: const Icon(Icons.error), onPressed: () => context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: SingleChildScrollView(child: Text(_result.error!)), actions: [ TextButton( - onPressed: () => Shares.copy(_result.error!), + onPressed: () => Pfs.copy(_result.error!), child: Text(l10n.copy), ), ], @@ -160,7 +153,7 @@ class _ProcessPageState extends State { onTap: () => _lastFocusId = proc.pid, onLongPress: () { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue( '${l10n.stop} ${l10n.process}(${proc.pid})', )), diff --git a/lib/view/page/pve.dart b/lib/view/page/pve.dart index 37208fb7..80d4238a 100644 --- a/lib/view/page/pve.dart +++ b/lib/view/page/pve.dart @@ -1,25 +1,14 @@ import 'dart:async'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/extension/numx.dart'; -import 'package:toolbox/core/extension/widget.dart'; import 'package:toolbox/data/model/server/pve.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/provider/pve.dart'; -import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/appbar.dart'; -import 'package:toolbox/view/widget/icon_btn.dart'; -import 'package:toolbox/view/widget/kv_row.dart'; import 'package:toolbox/view/widget/percent_circle.dart'; -import 'package:toolbox/view/widget/row.dart'; import 'package:toolbox/view/widget/two_line_text.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; final class PvePage extends StatefulWidget { final ServerPrivateInfo spi; @@ -156,7 +145,7 @@ final class _PvePageState extends State { } Widget _buildNode(PveNode item) { - final valueAnim = AlwaysStoppedAnimation(primaryColor); + final valueAnim = AlwaysStoppedAnimation(UIs.primaryColor); return Padding( padding: const EdgeInsets.symmetric(vertical: 13, horizontal: 13), child: Column( @@ -216,7 +205,7 @@ final class _PvePageState extends State { ), ], ), - ).card; + ).cardx; } Widget _buildQemu(PveQemu item) { @@ -224,7 +213,7 @@ final class _PvePageState extends State { return ListTile( title: Text(_wrapNodeName(item), style: UIs.text13Bold), trailing: _buildCtrlBtns(item), - ).card; + ).cardx; } final children = [ const SizedBox(height: 5), @@ -293,7 +282,7 @@ final class _PvePageState extends State { return Column( mainAxisSize: MainAxisSize.min, children: children, - ).card; + ).cardx; } Widget _buildLxc(PveLxc item) { @@ -301,7 +290,7 @@ final class _PvePageState extends State { return ListTile( title: Text(_wrapNodeName(item), style: UIs.text13Bold), trailing: _buildCtrlBtns(item), - ).card; + ).cardx; } final children = [ const SizedBox(height: 5), @@ -370,7 +359,7 @@ final class _PvePageState extends State { return Column( mainAxisSize: MainAxisSize.min, children: children, - ).card; + ).cardx; } Widget _buildStorage(PveStorage item) { @@ -392,14 +381,14 @@ final class _PvePageState extends State { KvRow(k: l10n.plugInType, v: item.plugintype), ], ), - ).card; + ).cardx; } Widget _buildSdn(PveSdn item) { return ListTile( title: Text(_wrapNodeName(item)), trailing: Text(item.summary), - ).card; + ).cardx; } Widget _buildCtrlBtns(PveCtrlIface item) { @@ -430,7 +419,7 @@ final class _PvePageState extends State { void _onCtrl(PveCtrlFunc func, String action, PveCtrlIface item) async { final sure = await context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue('$action ${item.id}')), actions: [ TextButton( diff --git a/lib/view/page/server/detail/misc.dart b/lib/view/page/server/detail/misc.dart index d138e719..a0c40026 100644 --- a/lib/view/page/server/detail/misc.dart +++ b/lib/view/page/server/detail/misc.dart @@ -109,7 +109,7 @@ Widget _buildLineChart( isCurved: curve, barWidth: 2, isStrokeCapRound: true, - color: primaryColor, + color: UIs.primaryColor, dotData: const FlDotData(show: false), belowBarData: BarAreaData(show: false), )) diff --git a/lib/view/page/server/detail/view.dart b/lib/view/page/server/detail/view.dart index 6e3999cd..bd94f735 100644 --- a/lib/view/page/server/detail/view.dart +++ b/lib/view/page/server/detail/view.dart @@ -1,14 +1,11 @@ import 'package:extended_image/extended_image.dart'; import 'package:fl_chart/fl_chart.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:icons_plus/icons_plus.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/listx.dart'; -import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/data/model/app/server_detail_card.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/server/battery.dart'; @@ -21,20 +18,11 @@ import 'package:toolbox/data/model/server/sensors.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/model/server/system.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/expand_tile.dart'; -import 'package:toolbox/view/widget/kv_row.dart'; -import 'package:toolbox/view/widget/markdown.dart'; import 'package:toolbox/view/widget/server_func_btns.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; -import '../../../../core/extension/numx.dart'; import '../../../../core/route.dart'; import '../../../../data/model/server/server.dart'; import '../../../../data/provider/server.dart'; -import '../../../../data/res/color.dart'; -import '../../../../data/res/ui.dart'; -import '../../../widget/appbar.dart'; -import '../../../widget/cardx.dart'; part 'misc.dart'; @@ -139,7 +127,7 @@ class _ServerDetailPageState extends State IconButton( icon: const Icon(Icons.edit), onPressed: () async { - final delete = await AppRoute.serverEdit(spi: si.spi).go(context); + final delete = await AppRoutes.serverEdit(spi: si.spi).go(context); if (delete == true) { context.pop(); } @@ -322,8 +310,8 @@ class _ServerDetailPageState extends State return LinearProgressIndicator( value: percentWithinOne, minHeight: 7, - backgroundColor: DynamicColors.progress.resolve(context), - color: primaryColor, + backgroundColor: UIs.halfAlpha, + color: UIs.primaryColor, ); } @@ -452,7 +440,7 @@ class _ServerDetailPageState extends State return processes.length * 47.0; }(); context.showRoundDialog( - title: Text(item.name), + title: item.name, child: SizedBox( width: double.maxFinite, height: height, @@ -494,10 +482,8 @@ class _ServerDetailPageState extends State trailing: InkWell( onTap: () { context.showRoundDialog( - title: SizedBox( - width: 377, - child: Text('${process.pid}', maxLines: 1), - ), + title: '${process.pid}', + titleMaxLines: 1, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -573,8 +559,8 @@ class _ServerDetailPageState extends State CircularProgressIndicator( value: disk.usedPercent / 100, strokeWidth: 5, - backgroundColor: DynamicColors.progress.resolve(context), - color: primaryColor, + backgroundColor: UIs.halfAlpha, + color: UIs.primaryColor, ), Text('${disk.usedPercent}%', style: UIs.text12Grey) ], @@ -770,7 +756,7 @@ class _ServerDetailPageState extends State return InkWell( onTap: () { context.showRoundDialog( - title: Text(si.device), + title: si.device, child: SingleChildScrollView( child: SimpleMarkdown( data: si.toMarkdown, @@ -819,7 +805,7 @@ class _ServerDetailPageState extends State subtitle: Text(addr, style: UIs.textGrey), leading: const Icon(FontAwesome.server_solid, size: 17), trailing: const Icon(Icons.chevron_right), - onTap: () => AppRoute.pve(spi: widget.spi).go(context), + onTap: () => AppRoutes.pve(spi: widget.spi).go(context), ), ); } @@ -847,7 +833,7 @@ class _ServerDetailPageState extends State return GestureDetector( onTap: () { context.showRoundDialog( - title: Text(cmd.key), + title: cmd.key, child: SingleChildScrollView( child: Text(cmd.value, style: UIs.text13Grey), ), diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 7158da72..1a6f3341 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -1,29 +1,19 @@ import 'dart:convert'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:icons_plus/icons_plus.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/extension/stringx.dart'; -import 'package:toolbox/core/extension/widget.dart'; import 'package:toolbox/core/utils/ui.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/server/custom.dart'; import 'package:toolbox/data/model/server/wol_cfg.dart'; import 'package:toolbox/data/res/provider.dart'; -import 'package:toolbox/view/widget/expand_tile.dart'; import '../../../core/route.dart'; import '../../../data/model/server/server_private_info.dart'; import '../../../data/provider/private_key.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/appbar.dart'; -import '../../widget/input_field.dart'; -import '../../widget/cardx.dart'; -import '../../widget/tag.dart'; class ServerEditPage extends StatefulWidget { const ServerEditPage({super.key, this.spi}); @@ -163,7 +153,7 @@ class _ServerEditPageState extends State { onPressed: () { var delScripts = false; context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: StatefulBuilder(builder: (ctx, setState) { return Column( mainAxisSize: MainAxisSize.min, @@ -224,7 +214,7 @@ class _ServerEditPageState extends State { icon: BoxIcons.bx_rename, obscureText: false, autoCorrect: true, - suggestiion: true, + suggestion: true, ), Input( controller: _ipController, @@ -266,6 +256,9 @@ class _ServerEditPageState extends State { onChanged: (p0) => _tags = p0, allTags: [...Pros.server.tags.value], onRenameTag: Pros.server.renameTag, + renameL10n: l10n.rename, + tagL10n: l10n.tag, + addL10n: l10n.add, ), ListTile( title: Text(l10n.autoConnect), @@ -367,7 +360,7 @@ class _ServerEditPageState extends State { padding: EdgeInsets.only(right: 13), child: Icon(Icons.add), ), - onTap: () => AppRoute.keyEdit().go(context), + onTap: () => AppRoutes.keyEdit().go(context), ), ); return CardX( @@ -440,7 +433,7 @@ class _ServerEditPageState extends State { }, ), ), - ).card, + ).cardx, ]; } @@ -464,7 +457,7 @@ class _ServerEditPageState extends State { title: Text(l10n.doc), trailing: const Icon(Icons.open_in_new, size: 17), onTap: () => openUrl(l10n.customCmdDocUrl), - ).card, + ).cardx, ]; } @@ -479,7 +472,7 @@ class _ServerEditPageState extends State { ), title: Text(l10n.about), subtitle: Text(l10n.wolTip, style: UIs.text12Grey), - ).card, + ).cardx, Input( controller: _wolMacCtrl, type: TextInputType.text, @@ -564,7 +557,7 @@ class _ServerEditPageState extends State { } if (_keyIdx.value == null && _passwordController.text.isEmpty) { final cancel = await context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue(l10n.useNoPwd)), actions: [ TextButton( diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index bf5e9013..11ae8ef6 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -2,26 +2,16 @@ import 'dart:async'; import 'dart:math' as math; import 'package:after_layout/after_layout.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:get_it/get_it.dart'; import 'package:icons_plus/icons_plus.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/listx.dart'; -import 'package:toolbox/core/extension/media_queryx.dart'; -import 'package:toolbox/core/extension/numx.dart'; import 'package:toolbox/core/extension/ssh_client.dart'; -import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/server/try_limiter.dart'; -import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/auto_hide.dart'; -import 'package:toolbox/view/widget/icon_text_btn.dart'; -import 'package:toolbox/view/widget/markdown.dart'; import 'package:toolbox/view/widget/percent_circle.dart'; import '../../../core/route.dart'; @@ -29,10 +19,7 @@ import '../../../data/model/app/net_view.dart'; import '../../../data/model/server/server.dart'; import '../../../data/model/server/server_private_info.dart'; import '../../../data/provider/server.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/cardx.dart'; import '../../widget/server_func_btns.dart'; -import '../../widget/tag.dart'; class ServerPage extends StatefulWidget { const ServerPage({super.key}); @@ -79,7 +66,7 @@ class _ServerPageState extends State _media = MediaQuery.of(context); _updateOffset(); _updateTextScaler(); - _useDoubleColumn = _media.useDoubleColumn && + _useDoubleColumn = _media.size.width > 639 && Stores.setting.doubleColumnServersPage.fetch(); } @@ -115,7 +102,7 @@ class _ServerPageState extends State controller: _scrollController, child: FloatingActionButton( heroTag: 'addServer', - onPressed: () => AppRoute.serverEdit().go(context), + onPressed: () => AppRoutes.serverEdit().go(context), tooltip: l10n.addAServer, child: const Icon(Icons.add), ), @@ -137,7 +124,7 @@ class _ServerPageState extends State top: 0, left: 0, child: IconButton( - onPressed: () => AppRoute.settings().go(context), + onPressed: () => AppRoutes.settings().go(context), icon: const Icon(Icons.settings, color: Colors.grey), ), ), @@ -227,6 +214,7 @@ class _ServerPageState extends State _tag = p0; }), initTag: _tag, + allL10n: l10n.all, ); } @@ -285,9 +273,9 @@ class _ServerPageState extends State child: InkWell( onTap: () { if (srv.canViewDetails) { - AppRoute.serverDetail(spi: srv.spi).go(context); + AppRoutes.serverDetail(spi: srv.spi).go(context); } else { - AppRoute.serverEdit(spi: srv.spi).go(context); + AppRoutes.serverEdit(spi: srv.spi).go(context); } }, onLongPress: () { @@ -298,7 +286,7 @@ class _ServerPageState extends State flip: !cardStatus.value.flip, ); } else { - AppRoute.serverEdit(spi: srv.spi).go(context); + AppRoutes.serverEdit(spi: srv.spi).go(context); } }, child: Padding( @@ -343,7 +331,7 @@ class _ServerPageState extends State height: _calcCardHeight(srv.conn, cardStatus.value.flip), child: Column( mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, children: children, ), @@ -363,7 +351,7 @@ class _ServerPageState extends State func: () async { if (Stores.setting.showSuspendTip.fetch()) { await context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.suspendTip), ); Stores.setting.showSuspendTip.put(false); @@ -407,7 +395,7 @@ class _ServerPageState extends State text: l10n.reboot, ), IconTextBtn( - onPressed: () => AppRoute.serverEdit(spi: srv.spi).go(context), + onPressed: () => AppRoutes.serverEdit(spi: srv.spi).go(context), icon: Icons.edit, text: l10n.edit, ) @@ -482,7 +470,7 @@ class _ServerPageState extends State height: 19, child: CircularProgressIndicator( strokeWidth: 3, - valueColor: AlwaysStoppedAnimation(primaryColor), + valueColor: AlwaysStoppedAnimation(UIs.primaryColor), ), ), ), @@ -549,11 +537,11 @@ ${ss.err?.solution ?? l10n.unknown} ${ss.err?.message ?? l10n.unknownError} '''; context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: SingleChildScrollView(child: SimpleMarkdown(data: md)), actions: [ TextButton( - onPressed: () => Shares.copy(md), + onPressed: () => Pfs.copy(md), child: Text(l10n.copy), ) ], @@ -649,7 +637,6 @@ ${ss.err?.message ?? l10n.unknownError} @override Future afterFirstLayout(BuildContext context) async { - await GetIt.I.allReady(); await Pros.server.load(); Pros.server.startAutoRefresh(); } @@ -682,7 +669,7 @@ ${ss.err?.message ?? l10n.unknownError} required String name, }) { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue('$typ ${l10n.server}($name)')), actions: [ TextButton( diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart index b2895f91..5ad3c7c5 100644 --- a/lib/view/page/setting/entry.dart +++ b/lib/view/page/setting/entry.dart @@ -1,42 +1,22 @@ import 'dart:io'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_highlight/theme_map.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:icons_plus/icons_plus.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/build_mode.dart'; -import 'package:toolbox/core/extension/colorx.dart'; -import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/extension/locale.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; -import 'package:toolbox/core/extension/stringx.dart'; -import 'package:toolbox/core/utils/function.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/rebuild.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/expand_tile.dart'; -import 'package:toolbox/view/widget/markdown.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; +import 'package:toolbox/data/res/url.dart'; -import '../../../core/persistant_store.dart'; import '../../../core/route.dart'; import '../../../core/utils/misc.dart'; -import '../../../core/update.dart'; import '../../../data/model/app/net_view.dart'; import '../../../data/provider/app.dart'; import '../../../data/res/build_data.dart'; -import '../../../data/res/color.dart'; -import '../../../data/res/path.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/color_picker.dart'; -import '../../widget/appbar.dart'; -import '../../widget/input_field.dart'; -import '../../widget/cardx.dart'; -import '../../widget/store_switch.dart'; const _kIconSize = 23.0; @@ -59,7 +39,7 @@ class _SettingPageState extends State { IconButton( icon: const Icon(Icons.delete), onPressed: () => context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: SimpleMarkdown( data: l10n.askContinue( '${l10n.delete} **${l10n.all}** ${l10n.setting}', @@ -220,7 +200,13 @@ class _SettingPageState extends State { }, ), onTap: () => Funcs.throttle( - () => doUpdate(context, force: BuildMode.isDebug), + () => AppUpdateIface.doUpdate( + context: context, + build: BuildData.build, + url: Urls.updateCfg, + force: BuildMode.isDebug, + updateL10n: l10n.update, + ), ), trailing: StoreSwitch(prop: _setting.autoCheckAppUpdate), ); @@ -237,6 +223,7 @@ class _SettingPageState extends State { ), onTap: () async { final val = await context.showPickSingleDialog( + title: l10n.setting, items: List.generate(10, (idx) => idx == 1 ? null : idx), initial: _setting.serverStatusUpdateInterval.fetch(), name: (p0) => p0 == 0 ? l10n.manual : '$p0 ${l10n.second}', @@ -260,12 +247,12 @@ class _SettingPageState extends State { leading: const Icon(Icons.colorize), title: Text(l10n.primaryColorSeed), trailing: ClipOval( - child: Container(color: primaryColor, height: 27, width: 27), + child: Container(color: UIs.primaryColor, height: 27, width: 27), ), onTap: () async { - final ctrl = TextEditingController(text: primaryColor.toHex); + final ctrl = TextEditingController(text: UIs.primaryColor.toHex); await context.showRoundDialog( - title: Text(l10n.primaryColorSeed), + title: l10n.primaryColorSeed, child: StatefulBuilder(builder: (context, setState) { final children = [ /// Plugin [dynamic_color] is not supported on iOS @@ -316,7 +303,7 @@ class _SettingPageState extends State { } // Change [primaryColor] first, then change [_selectedColorValue], // So the [ValueBuilder] will be triggered with the new value - primaryColor = color; + UIs.colorSeed = color; _setting.primaryColor.put(color.value); context.pop(); context.pop(); @@ -376,6 +363,7 @@ class _SettingPageState extends State { style: UIs.textGrey), onTap: () async { final selected = await context.showPickSingleDialog( + title: l10n.maxRetryCount, items: List.generate(10, (index) => index), name: (p0) => '$p0 ${l10n.times}', initial: val, @@ -400,6 +388,7 @@ class _SettingPageState extends State { title: Text(l10n.themeMode), onTap: () async { final selected = await context.showPickSingleDialog( + title: l10n.themeMode, items: List.generate(len + 2, (index) => index), name: (p0) => _buildThemeModeStr(p0), initial: _setting.themeMode.fetch(), @@ -445,7 +434,7 @@ class _SettingPageState extends State { ), onTap: () { context.showRoundDialog( - title: Text(l10n.font), + title: l10n.font, actions: [ TextButton( onPressed: () async => await _pickFontFile(), @@ -466,23 +455,22 @@ class _SettingPageState extends State { } Future _pickFontFile() async { - final path = await pickOneFile(); - if (path != null) { - // iOS can't copy file to app dir, so we need to use the original path - if (isIOS) { - _setting.fontPath.put(path); - } else { - final fontFile = File(path); - final newPath = '${await Paths.font}/${path.split('/').last}'; - await fontFile.copy(newPath); - _setting.fontPath.put(newPath); - } - - context.pop(); - RebuildNodes.app.rebuild(); - return; + final path = await Pfs.pickFilePath(); + if (path == null) return; + + // iOS can't copy file to app dir, so we need to use the original path + if (isIOS) { + _setting.fontPath.put(path); + } else { + final fontFile = File(path); + final newPath = '${Paths.fontPath}/${path.split('/').last}'; + await fontFile.copy(newPath); + _setting.fontPath.put(newPath); } - context.showSnackBar(l10n.failed); + + context.pop(); + RebuildNodes.app.rebuild(); + return; } Widget _buildTermFontSize() { @@ -544,6 +532,7 @@ class _SettingPageState extends State { title: Text(l10n.language), onTap: () async { final selected = await context.showPickSingleDialog( + title: l10n.language, items: S.supportedLocales, name: (p0) => p0.code, initial: _setting.locale.fetch().toLocale, @@ -583,6 +572,7 @@ class _SettingPageState extends State { ), onTap: () async { final selected = await context.showPickSingleDialog( + title: l10n.theme, items: themeMap.keys.toList(), name: (p0) => p0, initial: _setting.editorTheme.fetch(), @@ -604,6 +594,7 @@ class _SettingPageState extends State { ), onTap: () async { final selected = await context.showPickSingleDialog( + title: l10n.theme, items: themeMap.keys.toList(), name: (p0) => p0, initial: _setting.editorDarkTheme.fetch(), @@ -687,7 +678,7 @@ class _SettingPageState extends State { leading: const Icon(BoxIcons.bxs_keyboard), title: Text(l10n.editVirtKeys), trailing: const Icon(Icons.keyboard_arrow_right), - onTap: () => AppRoute.sshVirtKeySetting().go(context), + onTap: () => AppRoutes.sshVirtKeySetting().go(context), ); } @@ -731,6 +722,7 @@ class _SettingPageState extends State { ), onTap: () async { final selected = await context.showPickSingleDialog( + title: l10n.netViewType, items: NetViewType.values, name: (p0) => p0.toStr, initial: _setting.netViewType.fetch(), @@ -749,7 +741,7 @@ class _SettingPageState extends State { trailing: const Icon(Icons.keyboard_arrow_right), onTap: () async { context.showRoundDialog>( - title: Text(l10n.choose), + title: l10n.choose, child: SingleChildScrollView( child: StatefulBuilder(builder: (ctx, setState) { final keys = Stores.server.box.keys.toList(); @@ -761,7 +753,7 @@ class _SettingPageState extends State { title: Text(name ?? e), subtitle: name != null ? Text(e) : null, onTap: () => context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue( '${l10n.delete} ${l10n.server}($e)', )), @@ -806,7 +798,7 @@ class _SettingPageState extends State { ), ), onTap: () => context.showRoundDialog( - title: Text(l10n.textScaler), + title: l10n.textScaler, child: Input( autoFocus: true, type: TextInputType.number, @@ -859,7 +851,7 @@ class _SettingPageState extends State { return ListTile( title: Text(l10n.sequence), trailing: const Icon(Icons.keyboard_arrow_right), - onTap: () => AppRoute.serverFuncBtnsOrder().go(context), + onTap: () => AppRoutes.serverFuncBtnsOrder().go(context), ); } @@ -868,7 +860,7 @@ class _SettingPageState extends State { leading: const Icon(OctIcons.sort_desc, size: _kIconSize), title: Text(l10n.serverOrder), trailing: const Icon(Icons.keyboard_arrow_right), - onTap: () => AppRoute.serverOrder().go(context), + onTap: () => AppRoutes.serverOrder().go(context), ); } @@ -877,7 +869,7 @@ class _SettingPageState extends State { leading: const Icon(OctIcons.sort_desc, size: _kIconSize), title: Text(l10n.serverDetailOrder), trailing: const Icon(Icons.keyboard_arrow_right), - onTap: () => AppRoute.serverDetailOrder().go(context), + onTap: () => AppRoutes.serverDetailOrder().go(context), ); } @@ -903,7 +895,7 @@ class _SettingPageState extends State { final fontSize = double.tryParse(ctrller.text); if (fontSize == null) { context.showRoundDialog( - title: Text(l10n.failed), + title: l10n.failed, child: Text('Parsed failed: ${ctrller.text}'), ); return; @@ -912,7 +904,7 @@ class _SettingPageState extends State { } context.showRoundDialog( - title: Text(l10n.fontSize), + title: l10n.fontSize, child: Input( controller: ctrller, autoFocus: true, @@ -947,15 +939,15 @@ class _SettingPageState extends State { } Widget? _buildPlatformSetting() { - final func = switch (OS.type) { - OS.android => AppRoute.androidSettings().go, - OS.ios => AppRoute.iosSettings().go, + final func = switch (Pfs.type) { + Pfs.android => AppRoutes.androidSettings().go, + Pfs.ios => AppRoutes.iosSettings().go, _ => null, }; if (func == null) return null; return ListTile( leading: const Icon(Icons.phone_android), - title: Text('${OS.type} ${l10n.setting}'), + title: Text('${Pfs.type} ${l10n.setting}'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () => func(context), ); @@ -1061,6 +1053,7 @@ class _SettingPageState extends State { ), onTap: () async { final selected = await context.showPickSingleDialog( + title: l10n.theme, items: List.generate(3, (index) => index), name: (p0) => index2Str(p0), initial: _setting.termTheme.fetch(), @@ -1153,7 +1146,7 @@ class _SettingPageState extends State { void onSave(String url) { if (url.isEmpty || !url.startsWith('http')) { context.showRoundDialog( - title: Text(l10n.failed), + title: l10n.failed, child: Text('${l10n.invalid} URL'), actions: [ TextButton( @@ -1169,14 +1162,15 @@ class _SettingPageState extends State { } return ListTile( + leading: const Icon(Icons.image), title: Text('Logo ${l10n.addr}'), - subtitle: SimpleMarkdown(data: '${l10n.view} ${l10n.doc}'), + subtitle: SimpleMarkdown(data: '[${l10n.doc}](${Urls.appWiki})'), trailing: const Icon(Icons.keyboard_arrow_right), onTap: () { final ctrl = TextEditingController(text: _setting.serverLogoUrl.fetch()); context.showRoundDialog( - title: Text('Logo ${l10n.addr}'), + title: 'Logo ${l10n.addr}', child: Input( controller: ctrl, autoFocus: true, diff --git a/lib/view/page/setting/platform/android.dart b/lib/view/page/setting/platform/android.dart index bc7141c6..fd803b8c 100644 --- a/lib/view/page/setting/platform/android.dart +++ b/lib/view/page/setting/platform/android.dart @@ -1,19 +1,11 @@ import 'dart:convert'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/utils/platform/auth.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/view/page/setting/platform/platform_pub.dart'; -import 'package:toolbox/view/widget/appbar.dart'; -import 'package:toolbox/view/widget/input_field.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/store_switch.dart'; class AndroidSettingsPage extends StatefulWidget { const AndroidSettingsPage({super.key}); @@ -88,7 +80,7 @@ class _AndroidSettingsPageState extends State { }); final ctrl = TextEditingController(text: json.encode(data)); context.showRoundDialog( - title: Text(l10n.homeWidgetUrlConfig), + title: l10n.homeWidgetUrlConfig, child: Input( autoFocus: true, controller: ctrl, diff --git a/lib/view/page/setting/platform/ios.dart b/lib/view/page/setting/platform/ios.dart index 2bc3eb4c..9d6dd628 100644 --- a/lib/view/page/setting/platform/ios.dart +++ b/lib/view/page/setting/platform/ios.dart @@ -1,22 +1,13 @@ import 'dart:convert'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/route.dart'; import 'package:toolbox/core/utils/misc.dart'; -import 'package:toolbox/core/utils/platform/auth.dart'; -import 'package:toolbox/core/utils/share.dart'; -import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/view/page/setting/platform/platform_pub.dart'; -import 'package:toolbox/view/widget/appbar.dart'; -import 'package:toolbox/view/widget/future_widget.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/store_switch.dart'; import 'package:watch_connectivity/watch_connectivity.dart'; class IOSSettingsPage extends StatefulWidget { @@ -59,7 +50,7 @@ class _IOSSettingsPageState extends State { padding: EdgeInsets.zero, onPressed: () { if (_pushToken.value != null) { - Shares.copy(_pushToken.value!); + Pfs.copy(_pushToken.value!); context.showSnackBar(l10n.success); } else { context.showSnackBar(l10n.getPushTokenFailed); @@ -126,7 +117,7 @@ class _IOSSettingsPageState extends State { void _onTapWatchApp(Map map) async { /// Encode [map] to String with indent `\t` final text = Miscs.jsonEncoder.convert(map); - final result = await AppRoute.editor( + final result = await AppRoutes.editor( text: text, langCode: 'json', title: 'Watch app', @@ -139,7 +130,7 @@ class _IOSSettingsPageState extends State { await wc.updateApplicationContext(newCtx); } catch (e, trace) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text('${l10n.save}:\n$e'), ); Loggers.app.warning('Update watch config failed', e, trace); diff --git a/lib/view/page/setting/platform/platform_pub.dart b/lib/view/page/setting/platform/platform_pub.dart index be1375cc..7b3295a9 100644 --- a/lib/view/page/setting/platform/platform_pub.dart +++ b/lib/view/page/setting/platform/platform_pub.dart @@ -1,10 +1,7 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/utils/platform/auth.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/future_widget.dart'; -import 'package:toolbox/view/widget/store_switch.dart'; abstract final class PlatformPublicSettings { static Widget buildBioAuth() { diff --git a/lib/view/page/setting/seq/srv_detail_seq.dart b/lib/view/page/setting/seq/srv_detail_seq.dart index 5a2a50b3..5ffee580 100644 --- a/lib/view/page/setting/seq/srv_detail_seq.dart +++ b/lib/view/page/setting/seq/srv_detail_seq.dart @@ -1,13 +1,9 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/data/model/app/server_detail_card.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; -import '../../../../core/extension/order.dart'; -import '../../../widget/appbar.dart'; -import '../../../widget/cardx.dart'; class ServerDetailOrderPage extends StatefulWidget { const ServerDetailOrderPage({super.key}); diff --git a/lib/view/page/setting/seq/srv_func_seq.dart b/lib/view/page/setting/seq/srv_func_seq.dart index e114decd..f3a46c62 100644 --- a/lib/view/page/setting/seq/srv_func_seq.dart +++ b/lib/view/page/setting/seq/srv_func_seq.dart @@ -1,14 +1,8 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; - -import '../../../../core/extension/order.dart'; -import '../../../widget/appbar.dart'; -import '../../../widget/cardx.dart'; class ServerFuncBtnsOrderPage extends StatefulWidget { const ServerFuncBtnsOrderPage({super.key}); @@ -50,7 +44,7 @@ class _ServerDetailOrderPageState extends State { title: RichText( text: TextSpan( children: [ - WidgetSpan(child: funcBtn.icon(2)), + WidgetSpan(child: Icon(funcBtn.icon)), const WidgetSpan(child: UIs.width7), TextSpan(text: funcBtn.toStr, style: UIs.textGrey), ], diff --git a/lib/view/page/setting/seq/srv_seq.dart b/lib/view/page/setting/seq/srv_seq.dart index 2e46d251..970a4815 100644 --- a/lib/view/page/setting/seq/srv_seq.dart +++ b/lib/view/page/setting/seq/srv_seq.dart @@ -1,12 +1,8 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/cardx.dart'; - -import '../../../widget/appbar.dart'; class ServerOrderPage extends StatefulWidget { const ServerOrderPage({super.key}); diff --git a/lib/view/page/setting/seq/virt_key.dart b/lib/view/page/setting/seq/virt_key.dart index a03eb1c2..352c9752 100644 --- a/lib/view/page/setting/seq/virt_key.dart +++ b/lib/view/page/setting/seq/virt_key.dart @@ -1,17 +1,8 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/extension/order.dart'; -import 'package:toolbox/core/extension/widget.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/data/model/ssh/virtual_key.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/store_switch.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; - -import '../../../widget/appbar.dart'; class SSHVirtKeySettingPage extends StatefulWidget { const SSHVirtKeySettingPage({super.key}); @@ -33,7 +24,7 @@ class _SSHVirtKeySettingPageState extends State { children: [ Padding( padding: const EdgeInsets.all(7), - child: _buildOneLineVirtKey().card, + child: _buildOneLineVirtKey().cardx, ), Expanded(child: _buildBody()), ], diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart index cd1b0ef0..19e69d23 100644 --- a/lib/view/page/snippet/edit.dart +++ b/lib/view/page/snippet/edit.dart @@ -1,20 +1,11 @@ import 'package:after_layout/after_layout.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/data/res/provider.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/input_field.dart'; -import 'package:toolbox/view/widget/markdown.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; import '../../../data/model/server/snippet.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/appbar.dart'; -import '../../widget/tag.dart'; class SnippetEditPage extends StatefulWidget { const SnippetEditPage({super.key, this.snippet}); @@ -62,7 +53,7 @@ class _SnippetEditPageState extends State IconButton( onPressed: () { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue( '${l10n.delete} ${l10n.snippet}(${widget.snippet!.name})', )), @@ -145,6 +136,9 @@ class _SnippetEditPageState extends State onRenameTag: (old, n) => setState(() { Pros.snippet.renameTag(old, n); }), + renameL10n: l10n.rename, + tagL10n: l10n.tag, + addL10n: l10n.add, ); }, ), @@ -182,6 +176,7 @@ class _SnippetEditPageState extends State onTap: () async { vals.removeWhere((e) => !Pros.server.serverOrder.contains(e)); final serverIds = await context.showPickDialog( + title: l10n.autoRun, items: Pros.server.serverOrder, initial: vals, ); diff --git a/lib/view/page/snippet/list.dart b/lib/view/page/snippet/list.dart index 099ee664..6dd40b1c 100644 --- a/lib/view/page/snippet/list.dart +++ b/lib/view/page/snippet/list.dart @@ -1,15 +1,12 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/data/res/store.dart'; import '../../../data/model/server/snippet.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/tag.dart'; import '/core/route.dart'; import '/data/provider/snippet.dart'; -import '../../widget/cardx.dart'; class SnippetListPage extends StatefulWidget { const SnippetListPage({super.key}); @@ -36,7 +33,7 @@ class _SnippetListPageState extends State { floatingActionButton: FloatingActionButton( heroTag: 'snippetAdd', child: const Icon(Icons.add), - onPressed: () => AppRoute.snippetEdit().go(context), + onPressed: () => AppRoutes.snippetEdit().go(context), ), ); } @@ -72,6 +69,7 @@ class _SnippetListPageState extends State { onTagChanged: (tag) => setState(() => _tag = tag), initTag: _tag, width: _media.size.width, + allL10n: l10n.all, ), footer: UIs.height77, buildDefaultDragHandles: false, @@ -108,7 +106,7 @@ class _SnippetListPageState extends State { children: [ IconButton( onPressed: () => - AppRoute.snippetEdit(snippet: snippet).go(context), + AppRoutes.snippetEdit(snippet: snippet).go(context), icon: const Icon(Icons.edit), ), ], @@ -128,7 +126,7 @@ class _SnippetListPageState extends State { // final ids = servers.map((e) => e.spi.id).toList(); // final results = await Pros.server.runSnippetsMulti(ids, snippet); // if (results.isNotEmpty) { - // AppRoute.snippetResult(results: results).go(context); + // AppRoutes.snippetResult(results: results).go(context); // } // } } diff --git a/lib/view/page/snippet/result.dart b/lib/view/page/snippet/result.dart index b0088323..7e292a45 100644 --- a/lib/view/page/snippet/result.dart +++ b/lib/view/page/snippet/result.dart @@ -1,10 +1,7 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/data/model/server/snippet.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/appbar.dart'; -import 'package:toolbox/view/widget/expand_tile.dart'; class SnippetResultPage extends StatelessWidget { final List results; diff --git a/lib/view/page/ssh/page.dart b/lib/view/page/ssh/page.dart index 14f804ab..fb9bcb01 100644 --- a/lib/view/page/ssh/page.dart +++ b/lib/view/page/ssh/page.dart @@ -2,22 +2,18 @@ import 'dart:async'; import 'dart:convert'; import 'package:dartssh2/dartssh2.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/utils/ssh_auth.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/server.dart'; -import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/model/server/snippet.dart'; import 'package:toolbox/data/provider/virtual_keyboard.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/appbar.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; import 'package:xterm/core.dart'; import 'package:xterm/ui.dart' hide TerminalThemes; @@ -26,7 +22,6 @@ import '../../../core/route.dart'; import '../../../core/utils/misc.dart'; import '../../../data/model/server/server_private_info.dart'; import '../../../data/model/ssh/virtual_key.dart'; -import '../../../data/res/color.dart'; import '../../../data/res/terminal.dart'; const _echoPWD = 'echo \$PWD'; @@ -104,7 +99,7 @@ class _SSHPageState extends State with AutomaticKeepAliveClientMixin { _media = MediaQuery.of(context); _terminalTheme = _isDark ? TerminalThemes.dark : TerminalThemes.light; - _terminalTheme = _terminalTheme.copyWith(selectionCursor: primaryColor); + _terminalTheme = _terminalTheme.copyWith(selectionCursor: UIs.primaryColor); // Because the virtual keyboard only displayed on mobile devices if (isMobile) { @@ -231,7 +226,7 @@ class _SSHPageState extends State with AutomaticKeepAliveClientMixin { item.text, style: TextStyle( color: selected - ? primaryColor + ? UIs.primaryColor : (_isDark ? Colors.white : Colors.black), fontSize: 15, ), @@ -298,13 +293,14 @@ class _SSHPageState extends State with AutomaticKeepAliveClientMixin { case VirtualKeyFunc.clipboard: final selected = terminalSelected; if (selected != null) { - Shares.copy(selected); + Pfs.copy(selected); } else { _paste(); } break; case VirtualKeyFunc.snippet: final snippets = await context.showPickWithTagDialog( + title: l10n.snippet, tags: Pros.snippet.tags, itemsBuilder: (e) { if (e == null) return Pros.snippet.snippets; @@ -313,6 +309,7 @@ class _SSHPageState extends State with AutomaticKeepAliveClientMixin { .toList(); }, name: (e) => e.name, + all: l10n.all, ); if (snippets == null || snippets.isEmpty) return; @@ -333,12 +330,12 @@ class _SSHPageState extends State with AutomaticKeepAliveClientMixin { final initPath = cmds[idx + 1].toString(); if (initPath.isEmpty || !initPath.startsWith('/')) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: const Text('Failed to get current path'), ); return; } - AppRoute.sftp(spi: widget.spi, initPath: initPath).go(context); + AppRoutes.sftp(spi: widget.spi, initPath: initPath).go(context); } } @@ -525,7 +522,7 @@ class _SSHPageState extends State with AutomaticKeepAliveClientMixin { Future _showHelp() async { if (!Stores.setting.sshTermHelpShown.fetch()) { await context.showRoundDialog( - title: Text(l10n.doc), + title: l10n.doc, child: Text(l10n.sshTermHelp), actions: [ TextButton( diff --git a/lib/view/page/ssh/tab.dart b/lib/view/page/ssh/tab.dart index dfd2cc95..17960119 100644 --- a/lib/view/page/ssh/tab.dart +++ b/lib/view/page/ssh/tab.dart @@ -1,15 +1,12 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/route.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/provider/server.dart'; import 'package:toolbox/data/res/provider.dart'; -import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/view/page/ssh/page.dart'; -import 'package:toolbox/view/widget/cardx.dart'; class SSHTabPage extends StatefulWidget { const SSHTabPage({super.key}); @@ -48,7 +45,7 @@ class _SSHTabPageState extends State if (_fabRN.value != 0) return const SizedBox(); return FloatingActionButton( heroTag: 'sshAddServer', - onPressed: () => AppRoute.serverEdit().go(context), + onPressed: () => AppRoutes.serverEdit().go(context), tooltip: l10n.addAServer, child: const Icon(Icons.add), ); @@ -70,7 +67,7 @@ class _SSHTabPageState extends State icon: const Icon(Icons.close, size: 17), onPressed: () async { final confirm = await context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text('${l10n.close} SSH ${l10n.conn}($e) ?'), actions: [ TextButton( diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index 80a5c725..baa5ea35 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -1,28 +1,17 @@ import 'dart:io'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/model/sftp/req.dart'; import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/provider.dart'; -import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/omit_start_text.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; -import '../../../core/extension/numx.dart'; import '../../../core/route.dart'; import '../../../core/utils/misc.dart'; import '../../../data/model/app/path_with_prefix.dart'; -import '../../../data/res/path.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/appbar.dart'; -import '../../widget/fade_in.dart'; class LocalStoragePage extends StatefulWidget { final bool isPickFile; @@ -50,10 +39,8 @@ class _LocalStoragePageState extends State { _path = LocalPath(widget.initDir!); }); } else { - Paths.sftp.then((dir) { - setState(() { - _path = LocalPath(dir); - }); + setState(() { + _path = LocalPath(Paths.file); }); } } @@ -75,7 +62,7 @@ class _LocalStoragePageState extends State { actions: [ IconButton( icon: const Icon(Icons.downloading), - onPressed: () => AppRoute.sftpMission().go(context), + onPressed: () => AppRoutes.sftpMission().go(context), ), ValBuilder<_SortType>( listenable: _sortType, @@ -145,10 +132,10 @@ class _LocalStoragePageState extends State { ), IconButton( onPressed: () async { - final path = await pickOneFile(); + final path = await Pfs.pickFilePath(); if (path == null) return; final name = getFileName(path) ?? 'imported'; - await File(path).copy(pathJoin(_path!.path, name)); + await File(path).copy(_path!.path.joinPath(name)); setState(() {}); }, icon: const Icon(Icons.add), @@ -237,7 +224,7 @@ class _LocalStoragePageState extends State { final fileName = file.path.split('/').last; if (widget.isPickFile) { await context.showRoundDialog( - title: Text(l10n.pickFile), + title: l10n.pickFile, child: Text(fileName), actions: [ TextButton( @@ -262,12 +249,12 @@ class _LocalStoragePageState extends State { final stat = await file.stat(); if (stat.size > Miscs.editorMaxSize) { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.fileTooLarge(fileName, stat.size, '1m')), ); return; } - final result = await AppRoute.editor( + final result = await AppRoutes.editor( path: file.absolute.path, ).go(context); if (result == true) { @@ -299,6 +286,7 @@ class _LocalStoragePageState extends State { context.pop(); final spi = await context.showPickSingleDialog( + title: l10n.choose, items: Pros.server.serverOrder .map((e) => Pros.server.pick(id: e)?.spi) .toList(), @@ -306,7 +294,7 @@ class _LocalStoragePageState extends State { ); if (spi == null) return; - final remotePath = await AppRoute.sftp( + final remotePath = await AppRoutes.sftp( spi: spi, isSelect: true, ).go(context); @@ -327,7 +315,7 @@ class _LocalStoragePageState extends State { leading: const Icon(Icons.open_in_new), title: Text(l10n.open), onTap: () { - Shares.files([file.absolute.path]); + Pfs.sharePath(file.absolute.path); }, ), ], @@ -338,7 +326,7 @@ class _LocalStoragePageState extends State { void _showRenameDialog(FileSystemEntity file) { final fileName = file.path.split('/').last; context.showRoundDialog( - title: Text(l10n.rename), + title: l10n.rename, child: Input( autoFocus: true, controller: TextEditingController(text: fileName), @@ -361,7 +349,7 @@ class _LocalStoragePageState extends State { void _showDeleteDialog(FileSystemEntity file) { final fileName = file.path.split('/').last; context.showRoundDialog( - title: Text(l10n.delete), + title: l10n.delete, child: Text(l10n.askContinue('${l10n.delete} $fileName')), actions: [ TextButton( diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index 6bb8586a..25298cf6 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -2,36 +2,21 @@ import 'dart:async'; import 'package:after_layout/after_layout.dart'; import 'package:dartssh2/dartssh2.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/sftpfile.dart'; import 'package:toolbox/core/utils/comparator.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/data/res/color.dart'; -import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/view/widget/omit_start_text.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/search.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; -import '../../../core/extension/numx.dart'; import '../../../core/route.dart'; -import '../../../core/utils/misc.dart'; import '../../../data/model/server/server_private_info.dart'; import '../../../data/model/sftp/absolute_path.dart'; import '../../../data/model/sftp/browser_status.dart'; import '../../../data/model/sftp/req.dart'; -import '../../../data/res/path.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/appbar.dart'; -import '../../widget/fade_in.dart'; -import '../../widget/input_field.dart'; import '../../widget/two_line_text.dart'; class SftpPage extends StatefulWidget { @@ -72,7 +57,7 @@ class _SftpPageState extends State with AfterLayoutMixin { actions: [ IconButton( icon: const Icon(Icons.downloading), - onPressed: () => AppRoute.sftpMission().go(context), + onPressed: () => AppRoutes.sftpMission().go(context), ), ValBuilder( listenable: _sortOption, @@ -96,7 +81,7 @@ class _SftpPageState extends State with AfterLayoutMixin { : name, style: TextStyle( color: type == currentSelectedOption.sortBy - ? primaryColor + ? UIs.primaryColor : null, fontWeight: type == currentSelectedOption.sortBy ? FontWeight.bold @@ -210,10 +195,10 @@ class _SftpPageState extends State with AfterLayoutMixin { final path = await () async { switch (idx) { case 0: - return await AppRoute.localStorage(isPickFile: true) + return await AppRoutes.localStorage(isPickFile: true) .go(context); case 1: - return await pickOneFile(); + return await Pfs.pickFilePath(); default: return null; } @@ -263,7 +248,7 @@ class _SftpPageState extends State with AfterLayoutMixin { padding: const EdgeInsets.all(0), onPressed: () async { final p = await context.showRoundDialog( - title: Text(l10n.goto), + title: l10n.goto, child: Autocomplete( optionsBuilder: (val) { if (!Stores.setting.recordHistory.fetch()) { @@ -441,7 +426,7 @@ class _SftpPageState extends State with AfterLayoutMixin { Pros.sftp.add(req, completer: completer); await context.showLoadingDialog(fn: () => completer.future); - final result = await AppRoute.editor(path: localPath).go(context); + final result = await AppRoutes.editor(path: localPath).go(context); if (result != null && result) { Pros.sftp .add(SftpReq(req.spi, remotePath, localPath, SftpReqType.upload)); @@ -451,7 +436,7 @@ class _SftpPageState extends State with AfterLayoutMixin { void _download(SftpName name) { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text('${l10n.dl2Local(name.filename)}\n${l10n.keepForeground}'), actions: [ TextButton( @@ -493,7 +478,7 @@ class _SftpPageState extends State with AfterLayoutMixin { }(); context.showRoundDialog( child: Text(text), - title: Text(l10n.attention), + title: l10n.attention, actions: [ TextButton( onPressed: () => context.pop(), @@ -515,7 +500,7 @@ class _SftpPageState extends State with AfterLayoutMixin { }); } catch (e) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(e.toString()), actions: [ TextButton( @@ -538,7 +523,7 @@ class _SftpPageState extends State with AfterLayoutMixin { context.pop(); final textController = TextEditingController(); context.showRoundDialog( - title: Text(l10n.createFolder), + title: l10n.createFolder, child: Input( autoFocus: true, icon: Icons.folder, @@ -579,7 +564,7 @@ class _SftpPageState extends State with AfterLayoutMixin { context.pop(); final textController = TextEditingController(); context.showRoundDialog( - title: Text(l10n.createFile), + title: l10n.createFile, child: Input( autoFocus: true, icon: Icons.insert_drive_file, @@ -591,7 +576,7 @@ class _SftpPageState extends State with AfterLayoutMixin { onPressed: () async { if (textController.text.isEmpty) { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.fieldMustNotEmpty), actions: [ TextButton( @@ -618,7 +603,7 @@ class _SftpPageState extends State with AfterLayoutMixin { context.pop(); final textController = TextEditingController(text: file.filename); context.showRoundDialog( - title: Text(l10n.rename), + title: l10n.rename, child: Input( autoFocus: true, icon: Icons.abc, @@ -631,7 +616,7 @@ class _SftpPageState extends State with AfterLayoutMixin { onPressed: () async { if (textController.text.isEmpty) { context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.fieldMustNotEmpty), actions: [ TextButton( @@ -658,7 +643,7 @@ class _SftpPageState extends State with AfterLayoutMixin { final cmd = _getDecompressCmd(absPath); if (cmd == null) { context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text('Unsupport file: ${name.filename}'), actions: [ TextButton( @@ -675,11 +660,12 @@ class _SftpPageState extends State with AfterLayoutMixin { String _getRemotePath(SftpName name) { final prePath = _status.path!.path; - return pathJoin(prePath, name.filename); + // Only support Linux as remote now, so the seperator is '/' + return prePath.joinPath(name.filename, seperator: '/'); } Future _getLocalPath(String remotePath) async { - return '${await Paths.sftp}$remotePath'; + return Paths.file.joinPath(remotePath); } /// Only return true if the path is changed @@ -728,7 +714,7 @@ class _SftpPageState extends State with AfterLayoutMixin { Future.delayed( const Duration(milliseconds: 177), () => context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(e.toString()), actions: [ TextButton( diff --git a/lib/view/page/storage/sftp_mission.dart b/lib/view/page/storage/sftp_mission.dart index 05696410..78a0ef23 100644 --- a/lib/view/page/storage/sftp_mission.dart +++ b/lib/view/page/storage/sftp_mission.dart @@ -1,19 +1,12 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/datetime.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/route.dart'; -import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/res/provider.dart'; -import '../../../core/extension/numx.dart'; import '../../../data/model/sftp/req.dart'; import '../../../data/provider/sftp.dart'; -import '../../../data/res/ui.dart'; -import '../../widget/appbar.dart'; -import '../../widget/cardx.dart'; class SftpMissionPage extends StatefulWidget { const SftpMissionPage({super.key}); @@ -59,7 +52,7 @@ class _SftpMissionPageState extends State { subtitle: l10n.error, trailing: IconButton( onPressed: () => context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text(err.toString()), ), icon: const Icon(Icons.error), @@ -82,11 +75,11 @@ class _SftpMissionPageState extends State { onPressed: () { final idx = status.req.localPath.lastIndexOf('/'); final dir = status.req.localPath.substring(0, idx); - AppRoute.localStorage(initDir: dir).go(context); + AppRoutes.localStorage(initDir: dir).go(context); }, icon: const Icon(Icons.file_open)), IconButton( - onPressed: () => Shares.files([status.req.localPath]), + onPressed: () => Pfs.sharePath(status.req.localPath), icon: const Icon(Icons.open_in_new), ) ], @@ -118,7 +111,7 @@ class _SftpMissionPageState extends State { subtitle: l10n.unknown, trailing: IconButton( onPressed: () => context.showRoundDialog( - title: Text(l10n.error), + title: l10n.error, child: Text((status.error ?? l10n.unknown).toString()), ), icon: const Icon(Icons.error), @@ -150,7 +143,7 @@ class _SftpMissionPageState extends State { Widget _buildDelete(String name, int id) { return IconButton( onPressed: () => context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: Text(l10n.askContinue( '${l10n.delete} ${l10n.mission}($name)', )), diff --git a/lib/view/widget/appbar.dart b/lib/view/widget/appbar.dart deleted file mode 100644 index c3ed0fe7..00000000 --- a/lib/view/widget/appbar.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/store.dart'; -import 'package:window_manager/window_manager.dart'; - -class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { - /// System status bar height - static double? barHeight; - static bool drawTitlebar = false; - - const CustomAppBar({ - super.key, - this.title, - this.actions, - this.centerTitle = true, - this.leading, - this.backgroundColor, - }); - - final Widget? title; - final List? actions; - final bool? centerTitle; - final Widget? leading; - final Color? backgroundColor; - - @override - Widget build(BuildContext context) { - final bar = AppBar( - key: key, - title: title, - actions: actions, - centerTitle: centerTitle, - leading: leading, - backgroundColor: backgroundColor, - toolbarHeight: (barHeight ?? 0) + kToolbarHeight, - ); - if (!drawTitlebar) return bar; - return Stack( - children: [ - bar, - Positioned( - right: 0, - top: 0, - child: GestureDetector( - onVerticalDragStart: (_) { - windowManager.startDragging(); - }, - onHorizontalDragStart: (_) { - windowManager.startDragging(); - }, - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - IconButton( - icon: Transform.translate( - offset: const Offset(0, -3.5), - child: const Icon(Icons.minimize, size: 13), - ), - onPressed: () => windowManager.minimize(), - ), - IconButton( - icon: const Icon(Icons.crop_square, size: 13), - onPressed: () async { - if (await windowManager.isMaximized()) { - windowManager.unmaximize(); - } else { - windowManager.maximize(); - } - }, - ), - IconButton( - icon: const Icon(Icons.close, size: 14), - onPressed: () => windowManager.close(), - ), - ], - ), - ), - ), - ], - ); - } - - static Future updateTitlebarHeight() async { - switch (Platform.operatingSystem) { - case 'macos': - barHeight = 27; - break; - case 'linux' || 'windows': - if (!Stores.setting.hideTitleBar.fetch()) break; - barHeight = 37; - drawTitlebar = true; - break; - default: - break; - } - } - - @override - Size get preferredSize => Size.fromHeight((barHeight ?? 0) + kToolbarHeight); -} diff --git a/lib/view/widget/auto_hide.dart b/lib/view/widget/auto_hide.dart deleted file mode 100644 index b341cc93..00000000 --- a/lib/view/widget/auto_hide.dart +++ /dev/null @@ -1,113 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -final class AutoHide extends StatefulWidget { - final Widget child; - final ScrollController controller; - final AxisDirection direction; - final double offset; - - const AutoHide({ - super.key, - required this.child, - required this.controller, - required this.direction, - this.offset = 55, - }); - - @override - State createState() => AutoHideState(); -} - -final class AutoHideState extends State { - bool _visible = true; - bool _isScrolling = false; - Timer? _timer; - - @override - void initState() { - super.initState(); - widget.controller.addListener(_scrollListener); - _setupTimer(); - } - - @override - void dispose() { - widget.controller.removeListener(_scrollListener); - _timer?.cancel(); - _timer = null; - super.dispose(); - } - - void show() { - debugPrint('show'); - if (_visible) return; - setState(() { - _visible = true; - }); - _setupTimer(); - } - - void _setupTimer() { - _timer?.cancel(); - _timer = Timer.periodic(const Duration(seconds: 3), (_) { - if (_isScrolling) return; - if (!_visible) return; - final canScroll = - widget.controller.positions.any((e) => e.maxScrollExtent >= 0); - if (!canScroll) return; - - setState(() { - _visible = false; - }); - _timer?.cancel(); - _timer = null; - }); - } - - void _scrollListener() { - if (_isScrolling) return; - _isScrolling = true; - - if (!_visible) { - setState(() { - _visible = true; - }); - _setupTimer(); - } - - _isScrolling = false; - } - - @override - Widget build(BuildContext context) { - return AnimatedContainer( - duration: Durations.medium1, - curve: Curves.easeInOutCubic, - transform: _transform, - child: widget.child, - ); - } - - Matrix4? get _transform { - switch (widget.direction) { - case AxisDirection.down: - return _visible - ? Matrix4.identity() - : Matrix4.translationValues(0, widget.offset, 0); - case AxisDirection.up: - return _visible - ? Matrix4.identity() - : Matrix4.translationValues(0, -widget.offset, 0); - case AxisDirection.left: - return _visible - ? Matrix4.identity() - : Matrix4.translationValues(-widget.offset, 0, 0); - case AxisDirection.right: - return _visible - ? Matrix4.identity() - : Matrix4.translationValues(widget.offset, 0, 0); - } - } -} diff --git a/lib/view/widget/cardx.dart b/lib/view/widget/cardx.dart deleted file mode 100644 index f0e637ef..00000000 --- a/lib/view/widget/cardx.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; - -class CardX extends StatelessWidget { - const CardX({super.key, required this.child, this.color}); - - final Widget child; - final Color? color; - - @override - Widget build(BuildContext context) { - return Card( - key: key, - clipBehavior: Clip.antiAlias, - color: color, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(17)), - ), - child: child, - ); - } -} diff --git a/lib/view/widget/choice_chip.dart b/lib/view/widget/choice_chip.dart deleted file mode 100644 index bb93c3c9..00000000 --- a/lib/view/widget/choice_chip.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:choice/selection.dart'; -import 'package:flutter/material.dart'; - -class ChoiceChipX extends StatelessWidget { - const ChoiceChipX({ - super.key, - required this.label, - required this.state, - required this.value, - }); - - final String label; - final ChoiceController state; - final T value; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 5), - child: ChoiceChip( - label: Text(label), - side: BorderSide.none, - showCheckmark: true, - padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 8), - labelPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0), - selected: state.selected(value), - onSelected: state.onSelected(value), - ), - ); - } -} diff --git a/lib/view/widget/color_picker.dart b/lib/view/widget/color_picker.dart deleted file mode 100644 index d694ba41..00000000 --- a/lib/view/widget/color_picker.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; - -enum _ColorPropType { - r, - g, - b, -} - -class ColorPicker extends StatefulWidget { - final Color color; - final ValueChanged onColorChanged; - - const ColorPicker({ - super.key, - required this.color, - required this.onColorChanged, - }); - - @override - _ColorPickerState createState() => _ColorPickerState(); -} - -class _ColorPickerState extends State { - late int _r = widget.color.red; - late int _g = widget.color.green; - late int _b = widget.color.blue; - - @override - Widget build(BuildContext context) { - return Column( - children: [ - _buildProgress(_ColorPropType.r, 'R', _r.toDouble()), - _buildProgress(_ColorPropType.g, 'G', _g.toDouble()), - _buildProgress(_ColorPropType.b, 'B', _b.toDouble()), - ], - ); - } - - Widget _buildProgress(_ColorPropType type, String title, double value) { - return Row( - children: [ - Text( - title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - Expanded( - child: Slider( - value: value, - onChanged: (v) { - setState(() { - switch (type) { - case _ColorPropType.r: - _r = v.toInt(); - break; - case _ColorPropType.g: - _g = v.toInt(); - break; - case _ColorPropType.b: - _b = v.toInt(); - break; - } - }); - widget.onColorChanged(Color.fromARGB(255, _r, _g, _b)); - }, - min: 0, - max: 255, - divisions: 255, - label: value.toInt().toString(), - ), - ), - ], - ); - } -} diff --git a/lib/view/widget/count_down_btn.dart b/lib/view/widget/count_down_btn.dart deleted file mode 100644 index 713651d9..00000000 --- a/lib/view/widget/count_down_btn.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; - -final class CountDownBtn extends StatefulWidget { - final int seconds; - final String text; - final Color? afterColor; - final VoidCallback onTap; - - const CountDownBtn({ - super.key, - required this.onTap, - this.seconds = 3, - this.text = 'Go', - this.afterColor, - }); - - @override - State createState() => _CountDownBtnState(); -} - -final class _CountDownBtnState extends State { - late int _seconds = widget.seconds; - Timer? _timer; - - @override - void initState() { - super.initState(); - _startCountDown(); - } - - @override - void dispose() { - _timer?.cancel(); - super.dispose(); - } - - bool get isCounting => _seconds > 0; - - void _startCountDown() { - _timer = Timer.periodic(const Duration(seconds: 1), (timer) { - if (!isCounting) { - _timer?.cancel(); - } - setState(() { - _seconds--; - }); - }); - } - - @override - Widget build(BuildContext context) { - return TextButton( - onPressed: () { - if (isCounting) return; - widget.onTap(); - }, - child: Text( - isCounting ? '$_seconds${l10n.second}' : widget.text, - style: TextStyle( - color: _seconds > 0 ? Colors.grey : widget.afterColor, - ), - ), - ); - } -} diff --git a/lib/view/widget/expand_tile.dart b/lib/view/widget/expand_tile.dart deleted file mode 100644 index d09797bc..00000000 --- a/lib/view/widget/expand_tile.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/material.dart'; - -const _shape = Border(); - -class ExpandTile extends ExpansionTile { - const ExpandTile({ - super.key, - super.leading, - required super.title, - super.children, - super.subtitle, - super.initiallyExpanded, - super.tilePadding, - super.childrenPadding, - super.trailing, - super.controller, - }) : super(shape: _shape, collapsedShape: _shape); -} diff --git a/lib/view/widget/fade_in.dart b/lib/view/widget/fade_in.dart deleted file mode 100644 index 58d92024..00000000 --- a/lib/view/widget/fade_in.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; - -/// 渐隐渐显实现 -class FadeIn extends StatefulWidget { - final Widget child; - final Duration duration; - - const FadeIn({ - super.key, - required this.child, - this.duration = const Duration(milliseconds: 477), - }); - - @override - _MyFadeInState createState() => _MyFadeInState(); -} - -class _MyFadeInState extends State with SingleTickerProviderStateMixin { - late AnimationController _controller; - late Animation _animation; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - vsync: this, - duration: widget.duration, - ); - _animation = Tween( - begin: 0.0, - end: 1.0, - ).animate(_controller); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - _controller.forward(); - return FadeTransition( - opacity: _animation, - child: widget.child, - ); - } -} diff --git a/lib/view/widget/future_widget.dart b/lib/view/widget/future_widget.dart deleted file mode 100644 index 1629cf1b..00000000 --- a/lib/view/widget/future_widget.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/ui.dart'; - -class FutureWidget extends StatelessWidget { - final Future future; - final Widget loading; - final Widget Function(Object? error, StackTrace? trace) error; - final Widget Function(T? data) success; - final Widget Function(AsyncSnapshot snapshot)? active; - - const FutureWidget({ - super.key, - required this.future, - this.loading = UIs.placeholder, - required this.error, - required this.success, - this.active, - }); - - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: future, - builder: (context, snapshot) { - if (snapshot.hasError) { - return error(snapshot.error, snapshot.stackTrace); - } - switch (snapshot.connectionState) { - case ConnectionState.none: - case ConnectionState.waiting: - return loading; - case ConnectionState.active: - if (active != null) { - return active!(snapshot); - } - return loading; - case ConnectionState.done: - return success(snapshot.data); - } - }, - ); - } -} diff --git a/lib/view/widget/icon_btn.dart b/lib/view/widget/icon_btn.dart deleted file mode 100644 index dbf2b581..00000000 --- a/lib/view/widget/icon_btn.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; - -final class IconBtn extends StatelessWidget { - final IconData icon; - final double size; - final Color? color; - final void Function() onTap; - - const IconBtn({ - super.key, - required this.icon, - required this.onTap, - this.size = 17, - this.color, - }); - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(17), - child: Padding( - padding: const EdgeInsets.all(8), - child: Icon(icon, size: size, color: color), - ), - ); - } -} diff --git a/lib/view/widget/icon_text_btn.dart b/lib/view/widget/icon_text_btn.dart deleted file mode 100644 index 79d42b5c..00000000 --- a/lib/view/widget/icon_text_btn.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/ui.dart'; - -final class IconTextBtn extends StatelessWidget { - final String text; - final IconData icon; - final VoidCallback? onPressed; - final Orientation orientation; - - const IconTextBtn({ - super.key, - required this.text, - required this.icon, - this.onPressed, - this.orientation = Orientation.portrait, - }); - - @override - Widget build(BuildContext context) { - return IconButton( - onPressed: onPressed, - tooltip: text, - icon: orientation == Orientation.landscape - ? Row( - children: [ - Icon(icon), - UIs.width7, - Text(text, style: UIs.text13Grey), - ], - ) - : Column( - children: [ - Icon(icon), - UIs.height7, - Text(text, style: UIs.text13Grey), - ], - )); - } -} diff --git a/lib/view/widget/input_field.dart b/lib/view/widget/input_field.dart deleted file mode 100644 index 94687581..00000000 --- a/lib/view/widget/input_field.dart +++ /dev/null @@ -1,102 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'cardx.dart'; - -class Input extends StatefulWidget { - final TextEditingController? controller; - final int maxLines; - final int? minLines; - final String? hint; - final String? label; - final void Function(String)? onSubmitted; - final void Function(String)? onChanged; - final bool obscureText; - final IconData? icon; - final TextInputType? type; - final FocusNode? node; - final bool autoCorrect; - final bool suggestiion; - final String? errorText; - final Widget? prefix; - final bool autoFocus; - final void Function(bool)? onViewPwdTap; - - const Input({ - super.key, - this.controller, - this.maxLines = 1, - this.minLines, - this.hint, - this.label, - this.onSubmitted, - this.onChanged, - this.obscureText = false, - this.icon, - this.type, - this.node, - this.autoCorrect = false, - this.suggestiion = false, - this.errorText, - this.prefix, - this.autoFocus = false, - this.onViewPwdTap, - }); - - @override - State createState() => _InputState(); -} - -class _InputState extends State { - bool _obscureText = false; - - @override - void initState() { - super.initState(); - _obscureText = widget.obscureText; - } - - @override - Widget build(BuildContext context) { - return CardX( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: TextField( - controller: widget.controller, - maxLines: widget.maxLines, - minLines: widget.minLines, - obscureText: _obscureText, - decoration: InputDecoration( - hintText: widget.hint, - labelText: widget.label, - errorText: widget.errorText, - border: InputBorder.none, - prefixIcon: widget.icon == null ? null : Icon(widget.icon), - prefix: widget.prefix, - suffixIcon: widget.obscureText - ? IconButton( - icon: Icon( - _obscureText ? Icons.visibility : Icons.visibility_off, - ), - onPressed: () { - setState(() { - _obscureText = !_obscureText; - }); - if (widget.onViewPwdTap != null) { - widget.onViewPwdTap?.call(_obscureText); - } - }, - ) - : null, - ), - keyboardType: widget.type, - focusNode: widget.node, - autocorrect: widget.autoCorrect, - enableSuggestions: widget.suggestiion, - autofocus: widget.autoFocus, - onSubmitted: widget.onSubmitted, - onChanged: widget.onChanged, - ), - ), - ); - } -} diff --git a/lib/view/widget/kv_row.dart b/lib/view/widget/kv_row.dart deleted file mode 100644 index 63d1fc54..00000000 --- a/lib/view/widget/kv_row.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/ui.dart'; - -final class KvRow extends StatelessWidget { - final String k; - final String v; - final void Function()? onTap; - final Widget? Function()? kBuilder; - final Widget? Function()? vBuilder; - - const KvRow({ - super.key, - required this.k, - required this.v, - this.onTap, - this.kBuilder, - this.vBuilder, - }); - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 3), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - kBuilder?.call() ?? Text(k, style: UIs.text12), - UIs.width7, - vBuilder?.call() ?? - Text( - v, - style: UIs.text11Grey, - overflow: TextOverflow.ellipsis, - ), - if (onTap != null) UIs.width7, - if (onTap != null) const Icon(Icons.keyboard_arrow_right, size: 16), - ], - ), - ), - ); - } -} diff --git a/lib/view/widget/markdown.dart b/lib/view/widget/markdown.dart deleted file mode 100644 index df7442f6..00000000 --- a/lib/view/widget/markdown.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; -import 'package:toolbox/core/utils/ui.dart'; -import 'package:toolbox/data/res/color.dart'; - -final class SimpleMarkdown extends StatelessWidget { - const SimpleMarkdown({ - super.key, - required this.data, - this.styleSheet, - }); - - final String data; - final MarkdownStyleSheet? styleSheet; - - @override - Widget build(BuildContext context) { - return MarkdownBody( - data: data, - onTapLink: (text, href, title) { - if (href != null && href.isNotEmpty) { - openUrl(href); - return; - } - context.showSnackBar(l10n.failed); - }, - styleSheet: styleSheet?.copyWith( - a: TextStyle(color: primaryColor), - ) ?? - MarkdownStyleSheet( - a: TextStyle(color: primaryColor), - ), - ); - } -} diff --git a/lib/view/widget/percent_circle.dart b/lib/view/widget/percent_circle.dart index f403ac71..89da8f89 100644 --- a/lib/view/widget/percent_circle.dart +++ b/lib/view/widget/percent_circle.dart @@ -1,6 +1,6 @@ import 'package:circle_chart/circle_chart.dart'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/color.dart'; final class PercentCircle extends StatelessWidget { final double percent; @@ -23,7 +23,7 @@ final class PercentCircle extends StatelessWidget { alignment: Alignment.center, children: [ CircleChart( - progressColor: primaryColor, + progressColor: UIs.primaryColor, progressNumber: percent, maxNumber: 100, width: 57, diff --git a/lib/view/widget/popup_menu.dart b/lib/view/widget/popup_menu.dart index bfc4948c..e64df50e 100644 --- a/lib/view/widget/popup_menu.dart +++ b/lib/view/widget/popup_menu.dart @@ -1,8 +1,9 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/ui.dart'; class PopupMenu extends StatelessWidget { - final List> items; + final List items; + final Widget Function(T) builder; final void Function(T) onSelected; final Widget child; final EdgeInsetsGeometry padding; @@ -11,6 +12,7 @@ class PopupMenu extends StatelessWidget { const PopupMenu({ super.key, required this.items, + required this.builder, required this.onSelected, this.child = UIs.popMenuChild, this.padding = const EdgeInsets.all(7), @@ -20,7 +22,9 @@ class PopupMenu extends StatelessWidget { @override Widget build(BuildContext context) { return PopupMenuButton( - itemBuilder: (_) => items, + itemBuilder: (_) => items + .map((e) => PopupMenuItem(value: e, child: builder(e))) + .toList(), onSelected: onSelected, initialValue: initialValue, padding: padding, diff --git a/lib/view/widget/row.dart b/lib/view/widget/row.dart deleted file mode 100644 index 028a5a0d..00000000 --- a/lib/view/widget/row.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; - -final class AvgWidthRow extends StatelessWidget { - final List children; - final double? width; - final double padding; - - const AvgWidthRow({ - super.key, - required this.children, - this.width, - this.padding = 0, - }); - - @override - Widget build(BuildContext context) { - final width = - ((this.width ?? MediaQuery.of(context).size.width) - padding) / - children.length; - return Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: children.map((e) => SizedBox(width: width, child: e)).toList(), - ); - } -} diff --git a/lib/view/widget/search.dart b/lib/view/widget/search.dart deleted file mode 100644 index 9dda8a9a..00000000 --- a/lib/view/widget/search.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/future_widget.dart'; - -final class SearchPage extends SearchDelegate { - final Future> Function(String) future; - final Widget Function(BuildContext, T) builder; - final EdgeInsetsGeometry? padding; - final Duration throttleInterval; - - List _cache = []; - DateTime? _lastSearch; - - SearchPage({ - required this.future, - required this.builder, - this.padding, - this.throttleInterval = const Duration(milliseconds: 200), - }); - - @override - List? buildActions(BuildContext context) { - return [ - IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - query = ''; - }, - ), - ]; - } - - @override - Widget? buildLeading(BuildContext context) { - return IconButton( - onPressed: context.pop, - icon: const Icon(Icons.arrow_back), - ); - } - - @override - Widget buildResults(BuildContext context) { - return _buildList(context); - } - - @override - Widget buildSuggestions(BuildContext context) { - return _buildList(context); - } - - Widget _buildList(BuildContext context) { - return FutureWidget( - future: _search(query), - loading: const Center(child: UIs.centerSizedLoading), - error: (error, trace) { - return Center( - child: Text('$error\n$trace'), - ); - }, - success: (list) { - if (list == null || list.isEmpty) { - return Center(child: Text(l10n.noResult)); - } - - return ListView.builder( - padding: padding, - itemCount: list.length, - itemBuilder: (_, index) => builder(context, list[index]), - ); - }, - ); - } - - Future> _search(String query) async { - final lastSearch = _lastSearch; - if (lastSearch != null) { - final now = DateTime.now(); - if (now.difference(lastSearch) < throttleInterval) { - return _cache; - } - } - _cache = await future(query); - return _cache; - } -} diff --git a/lib/view/widget/server_func_btns.dart b/lib/view/widget/server_func_btns.dart index 698c56a0..1d118637 100644 --- a/lib/view/widget/server_func_btns.dart +++ b/lib/view/widget/server_func_btns.dart @@ -1,24 +1,17 @@ import 'dart:io'; +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/ssh_client.dart'; -import 'package:toolbox/core/extension/uint8list.dart'; -import 'package:toolbox/core/utils/platform/base.dart'; -import 'package:toolbox/core/utils/platform/path.dart'; +import 'package:toolbox/data/model/app/menu/base.dart'; import 'package:toolbox/data/model/app/menu/server_func.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/pkg/manager.dart'; import 'package:toolbox/data/model/server/dist.dart'; import 'package:toolbox/data/model/server/snippet.dart'; -import 'package:toolbox/data/res/path.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/count_down_btn.dart'; import '../../core/route.dart'; import '../../core/utils/server.dart'; @@ -37,18 +30,8 @@ class ServerFuncBtnsTopRight extends StatelessWidget { @override Widget build(BuildContext context) { return PopupMenu( - items: ServerFuncBtn.values - .map((e) => PopupMenuItem( - value: e, - child: Row( - children: [ - e.icon(), - const SizedBox(width: 10), - Text(e.toStr), - ], - ), - )) - .toList(), + items: ServerFuncBtn.values, + builder: (e) => PopMenu.build(e, e.icon, e.toStr), padding: const EdgeInsets.symmetric(horizontal: 10), onSelected: (val) => _onTapMoreBtns(val, spi, context), ); @@ -87,7 +70,7 @@ class ServerFuncBtns extends StatelessWidget { onPressed: () => _onTapMoreBtns(e, spi, context), padding: EdgeInsets.zero, tooltip: e.toStr, - icon: e.icon(), + icon: Icon(e.icon, size: 15), ) : Padding( padding: const EdgeInsets.only(bottom: 13), @@ -97,7 +80,7 @@ class ServerFuncBtns extends StatelessWidget { IconButton( onPressed: () => _onTapMoreBtns(e, spi, context), padding: EdgeInsets.zero, - icon: e.icon(), + icon: Icon(e.icon, size: 17), ), Text(e.toStr, style: UIs.text11Grey) ], @@ -119,7 +102,7 @@ void _onTapMoreBtns( _onPkg(context, spi); break; case ServerFuncBtn.sftp: - AppRoute.sftp(spi: spi).checkGo( + AppRoutes.sftp(spi: spi).checkGo( context: context, check: () => _checkClient(context, spi.id), ); @@ -130,6 +113,7 @@ void _onTapMoreBtns( return; } final snippets = await context.showPickWithTagDialog( + title: l10n.snippet, tags: Pros.snippet.tags, itemsBuilder: (e) { if (e == null) return Pros.snippet.snippets; @@ -138,23 +122,24 @@ void _onTapMoreBtns( .toList(); }, name: (e) => e.name, + all: l10n.all, ); if (snippets == null || snippets.isEmpty) return; final snippet = snippets.firstOrNull; if (snippet == null) return; - AppRoute.ssh(spi: spi, initCmd: snippet.fmtWith(spi)).checkGo( + AppRoutes.ssh(spi: spi, initCmd: snippet.fmtWith(spi)).checkGo( context: context, check: () => _checkClient(context, spi.id), ); break; case ServerFuncBtn.container: - AppRoute.docker(spi: spi).checkGo( + AppRoutes.docker(spi: spi).checkGo( context: context, check: () => _checkClient(context, spi.id), ); break; case ServerFuncBtn.process: - AppRoute.process(spi: spi).checkGo( + AppRoutes.process(spi: spi).checkGo( context: context, check: () => _checkClient(context, spi.id), ); @@ -163,7 +148,7 @@ void _onTapMoreBtns( _gotoSSH(spi, context); break; case ServerFuncBtn.iperf: - AppRoute.iperf(spi: spi).checkGo( + AppRoutes.iperf(spi: spi).checkGo( context: context, check: () => _checkClient(context, spi.id), ); @@ -174,7 +159,7 @@ void _onTapMoreBtns( void _gotoSSH(ServerPrivateInfo spi, BuildContext context) async { // run built-in ssh on macOS due to incompatibility if (isMobile || isMacOS) { - AppRoute.ssh(spi: spi).go(context); + AppRoutes.ssh(spi: spi).go(context); return; } final extraArgs = []; @@ -186,7 +171,7 @@ void _gotoSSH(ServerPrivateInfo spi, BuildContext context) async { final tempKeyFileName = 'srvbox_pk_${spi.keyId}'; /// For security reason, save the private key file to app doc path - return joinPath(await Paths.doc, tempKeyFileName); + return Paths.doc.joinPath(tempKeyFileName); }(); final file = File(path); final shouldGenKey = spi.keyId != null; @@ -199,12 +184,12 @@ void _gotoSSH(ServerPrivateInfo spi, BuildContext context) async { } final sshCommand = ["ssh", "${spi.user}@${spi.ip}"] + extraArgs; - final system = OS.type; + final system = Pfs.type; switch (system) { - case OS.windows: + case Pfs.windows: await Process.start("cmd", ["/c", "start"] + sshCommand); break; - case OS.linux: + case Pfs.linux: await Process.start("x-terminal-emulator", ["-e"] + sshCommand); break; default: @@ -282,7 +267,7 @@ Future _onPkg(BuildContext context, ServerPrivateInfo spi) async { // Confirm upgrade final gotoUpgrade = await context.showRoundDialog( - title: Text(l10n.attention), + title: l10n.attention, child: SingleChildScrollView( child: Text( '${l10n.pkgUpgradeTip}\n${l10n.foundNUpdate(upgradeable.length)}\n\n$upgradeCmd'), @@ -298,7 +283,7 @@ Future _onPkg(BuildContext context, ServerPrivateInfo spi) async { if (gotoUpgrade != true) return; - AppRoute.ssh(spi: spi, initCmd: upgradeCmd).checkGo( + AppRoutes.ssh(spi: spi, initCmd: upgradeCmd).checkGo( context: context, check: () => _checkClient(context, spi.id), ); diff --git a/lib/view/widget/store_switch.dart b/lib/view/widget/store_switch.dart deleted file mode 100644 index 1b4cebc3..00000000 --- a/lib/view/widget/store_switch.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; - -import '../../core/persistant_store.dart'; - -class StoreSwitch extends StatelessWidget { - final StorePropertyBase prop; - - /// Exec before make change, after validator. - final FutureOr Function(bool)? callback; - - /// If return false, the switch will not change. - final bool Function(bool)? validator; - - const StoreSwitch({ - super.key, - required this.prop, - this.callback, - this.validator, - }); - - @override - Widget build(BuildContext context) { - return ValBuilder( - listenable: prop.listenable(), - builder: (value) { - return Switch( - value: value, - onChanged: (value) async { - if (validator?.call(value) == false) return; - await callback?.call(value); - prop.put(value); - }, - ); - }, - ); - } -} diff --git a/lib/view/widget/tag.dart b/lib/view/widget/tag.dart deleted file mode 100644 index 6d4d29eb..00000000 --- a/lib/view/widget/tag.dart +++ /dev/null @@ -1,254 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:toolbox/core/extension/context/common.dart'; -import 'package:toolbox/core/extension/context/dialog.dart'; -import 'package:toolbox/core/extension/context/locale.dart'; -import 'package:toolbox/data/res/ui.dart'; -import 'package:toolbox/view/widget/input_field.dart'; -import 'package:toolbox/view/widget/cardx.dart'; -import 'package:toolbox/view/widget/val_builder.dart'; - -import '../../data/res/color.dart'; - -const _kTagBtnHeight = 31.0; - -class TagBtn extends StatelessWidget { - final String content; - final void Function() onTap; - final bool isEnable; - - const TagBtn({ - super.key, - required this.onTap, - required this.isEnable, - required this.content, - }); - - @override - Widget build(BuildContext context) { - return _wrap( - Text( - content, - textAlign: TextAlign.center, - style: isEnable ? UIs.text13 : UIs.text13Grey, - ), - onTap: onTap, - ); - } -} - -class TagEditor extends StatefulWidget { - final List tags; - final void Function(List)? onChanged; - final void Function(String old, String new_)? onRenameTag; - final List allTags; - - const TagEditor({ - super.key, - required this.tags, - this.onChanged, - this.onRenameTag, - this.allTags = const [], - }); - - @override - State createState() => _TagEditorState(); -} - -class _TagEditorState extends State { - @override - Widget build(BuildContext context) { - return CardX( - child: ListTile( - // Align the place of TextField.prefixIcon - leading: const Padding( - padding: EdgeInsets.only(left: 10), - child: Icon(Icons.tag), - ), - title: _buildTags(widget.tags), - trailing: IconButton( - icon: const Icon(Icons.add), - onPressed: () => _showAddTagDialog(), - ), - ), - ); - } - - Widget _buildTags(List tags) { - final suggestions = widget.allTags.where((e) => !tags.contains(e)).toList(); - final suggestionLen = suggestions.length; - - /// Add vertical divider if suggestions.length > 0 - final counts = tags.length + suggestionLen + (suggestionLen == 0 ? 0 : 1); - if (counts == 0) return Text(l10n.tag); - return ConstrainedBox( - constraints: const BoxConstraints(maxHeight: _kTagBtnHeight), - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - if (index < tags.length) { - return _buildTagItem(tags[index]); - } else if (index > tags.length) { - return _buildTagItem( - suggestions[index - tags.length - 1], - isAdd: true, - ); - } - return const VerticalDivider(); - }, - itemCount: counts, - ), - ); - } - - Widget _buildTagItem(String tag, {bool isAdd = false}) { - return _wrap( - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - '#$tag', - textAlign: TextAlign.center, - style: isAdd ? UIs.text13Grey : UIs.text13, - ), - const SizedBox(width: 4.0), - Icon( - isAdd ? Icons.add_circle : Icons.cancel, - size: 13.7, - ), - ], - ), - onTap: () { - if (isAdd) { - widget.tags.add(tag); - } else { - widget.tags.remove(tag); - } - widget.onChanged?.call(widget.tags); - setState(() {}); - }, - onLongPress: () => _showRenameDialog(tag), - ); - } - - void _showAddTagDialog() { - final textEditingController = TextEditingController(); - context.showRoundDialog( - title: Text(l10n.add), - child: Input( - autoFocus: true, - icon: Icons.tag, - controller: textEditingController, - hint: l10n.tag, - ), - actions: [ - TextButton( - onPressed: () { - final tag = textEditingController.text; - widget.tags.add(tag.trim()); - widget.onChanged?.call(widget.tags); - context.pop(); - }, - child: Text(l10n.add), - ), - ], - ); - } - - void _showRenameDialog(String tag) { - final textEditingController = TextEditingController(text: tag); - context.showRoundDialog( - title: Text(l10n.rename), - child: Input( - autoFocus: true, - icon: Icons.abc, - controller: textEditingController, - hint: l10n.tag, - ), - actions: [ - TextButton( - onPressed: () { - final newTag = textEditingController.text.trim(); - if (newTag.isEmpty) return; - widget.onRenameTag?.call(tag, newTag); - context.pop(); - setState(() {}); - }, - child: Text(l10n.rename), - ), - ], - ); - } -} - -class TagSwitcher extends StatelessWidget implements PreferredSizeWidget { - final ValueNotifier> tags; - final double width; - final void Function(String?) onTagChanged; - final String? initTag; - - const TagSwitcher({ - super.key, - required this.tags, - required this.width, - required this.onTagChanged, - this.initTag, - }); - - @override - Widget build(BuildContext context) { - return ValBuilder( - listenable: tags, - builder: (vals) { - if (vals.isEmpty) return UIs.placeholder; - final items = [null, ...vals]; - return Container( - height: _kTagBtnHeight, - width: width, - padding: const EdgeInsets.symmetric(horizontal: 7), - alignment: Alignment.center, - color: Colors.transparent, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - final item = items[index]; - return TagBtn( - content: item == null ? l10n.all : '#$item', - isEnable: initTag == item, - onTap: () => onTagChanged(item), - ); - }, - itemCount: items.length, - ), - ); - }, - ); - } - - @override - Size get preferredSize => const Size.fromHeight(_kTagBtnHeight); -} - -Widget _wrap( - Widget child, { - void Function()? onTap, - void Function()? onLongPress, -}) { - return Padding( - padding: const EdgeInsets.all(3), - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20.0)), - child: Material( - color: primaryColor.withAlpha(20), - child: InkWell( - onTap: onTap, - onLongPress: onLongPress, - child: Padding( - padding: const EdgeInsets.fromLTRB(11.7, 2.7, 11.7, 0), - child: child, - ), - ), - ), - ), - ); -} diff --git a/lib/view/widget/two_line_text.dart b/lib/view/widget/two_line_text.dart index 91400c57..7a154b87 100644 --- a/lib/view/widget/two_line_text.dart +++ b/lib/view/widget/two_line_text.dart @@ -1,5 +1,5 @@ +import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/ui.dart'; class TwoLineText extends StatelessWidget { const TwoLineText({super.key, required this.up, required this.down}); diff --git a/lib/view/widget/url_text.dart b/lib/view/widget/url_text.dart deleted file mode 100644 index 380c7314..00000000 --- a/lib/view/widget/url_text.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:toolbox/data/res/color.dart'; - -import '../../core/utils/ui.dart'; - -final _reg = RegExp( - r"(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]*"); - -class UrlText extends StatelessWidget { - final String text; - final String? replace; - final TextAlign? textAlign; - final TextStyle style; - - const UrlText({ - super.key, - required this.text, - this.replace, - this.textAlign, - this.style = const TextStyle(), - }); - - List _buildTextSpans(Color c) { - final widgets = []; - int start = 0; - - for (final match in _reg.allMatches(text)) { - final group0 = match.group(0); - if (group0 != null && group0.isNotEmpty) { - if (start != match.start) { - widgets.add( - TextSpan( - text: text.substring(start, match.start), - style: style.copyWith(color: c), - ), - ); - } - - widgets.add(_LinkTextSpan( - replace: replace, - text: group0, - style: style.copyWith(color: primaryColor), - )); - start = match.end; - } - } - - if (start < text.length) { - widgets.add( - TextSpan( - text: text.substring(start), - style: style.copyWith(color: c), - ), - ); - } - return widgets; - } - - @override - Widget build(BuildContext context) { - return RichText( - textAlign: textAlign ?? TextAlign.start, - text: TextSpan( - children: _buildTextSpans(DynamicColors.content.resolve(context)), - ), - ); - } -} - -class _LinkTextSpan extends TextSpan { - _LinkTextSpan({super.style, required String text, String? replace}) - : super( - text: replace ?? text, - recognizer: TapGestureRecognizer() - ..onTap = () { - openUrl(text); - }, - ); -} diff --git a/lib/view/widget/val_builder.dart b/lib/view/widget/val_builder.dart deleted file mode 100644 index 03645cd9..00000000 --- a/lib/view/widget/val_builder.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -final class ValBuilder extends ValueListenableBuilder { - ValBuilder({ - super.key, - required ValueListenable listenable, - required Widget Function(T) builder, - }) : super( - valueListenable: listenable, - builder: (_, val, __) => builder(val), - ); -} - -final class ValChildBuilder extends ValueListenableBuilder { - ValChildBuilder({ - super.key, - required ValueListenable listenable, - required Widget Function(T, Widget?) builder, - super.child, - }) : super( - valueListenable: listenable, - builder: (_, val, child) => builder(val, child), - ); -} - -final class ListenBuilder extends ListenableBuilder { - ListenBuilder({ - super.key, - required super.listenable, - required Widget Function() builder, - }) : super( - builder: (_, __) => builder(), - ); -} diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index bab93041..989df5d1 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -471,7 +471,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -481,7 +481,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -608,7 +608,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Server Box"; @@ -618,7 +618,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -638,7 +638,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 893; + CURRENT_PROJECT_VERSION = 896; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6; INFOPLIST_FILE = Runner/Info.plist; @@ -649,7 +649,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.0.893; + MARKETING_VERSION = 1.0.896; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "Server Box"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/pubspec.lock b/pubspec.lock index e4fc5cd6..ed08780b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,26 +37,26 @@ packages: dependency: "direct main" description: name: archive - sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 url: "https://pub.dev" source: hosted - version: "3.4.10" + version: "3.5.1" args: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" asn1lib: dependency: transitive description: name: asn1lib - sha256: c9c85fedbe2188b95133cbe960e16f5f448860f7133330e272edbbca5893ddc6 + sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda" url: "https://pub.dev" source: hosted - version: "1.5.2" + version: "1.5.3" async: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: built_value - sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.0" + version: "8.9.2" characters: dependency: transitive description: @@ -157,10 +157,10 @@ packages: dependency: "direct main" description: name: choice - sha256: b33c757b56c73dd32a565e74283d8437c6ab0733986bbf31053f42575a680de5 + sha256: "52d07065e8056beba5b26cff7786134cbfa24927b1f5bf60a05d50058597b2d9" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.2" circle_chart: dependency: "direct main" description: @@ -220,7 +220,7 @@ packages: source: hosted version: "3.1.1" countly_flutter: - dependency: "direct main" + dependency: transitive description: name: countly_flutter sha256: "829853407896350bdb4881ddc92326cf87b8d70ad92a78c4775cd05666d5a965" @@ -255,10 +255,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.6" dartssh2: dependency: "direct main" description: @@ -280,18 +280,18 @@ packages: dependency: "direct main" description: name: dio - sha256: "797e1e341c3dd2f69f2dad42564a6feff3bfb87187d05abb93b9609e6f1645c3" + sha256: "11e40df547d418cc0c4900a9318b26304e665da6fa4755399a9ff9efd09034b5" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "5.4.3+1" dynamic_color: dependency: "direct main" description: name: dynamic_color - sha256: a866f1f8947bfdaf674d7928e769eac7230388a2e7a2542824fad4bb5b87be3b + sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d url: "https://pub.dev" source: hosted - version: "1.6.9" + version: "1.7.0" easy_isolate: dependency: "direct main" description: @@ -352,10 +352,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: b6283d7387310ad83bc4f3bc245b75d223a032ae6eba275afcd585de2b9a1476 + sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" url: "https://pub.dev" source: hosted - version: "8.0.1" + version: "8.0.3" fixnum: dependency: transitive description: @@ -372,11 +372,28 @@ packages: url: "https://pub.dev" source: hosted version: "0.67.0" + fl_lib: + dependency: "direct main" + description: + path: "." + ref: main + resolved-ref: ff02a5d2b808a77f2f54528aece6b958cdc209a5 + url: "https://github.com/lollipopkit/fl_lib" + source: git + version: "0.0.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_adaptive_scaffold: + dependency: "direct main" + description: + name: flutter_adaptive_scaffold + sha256: "9a1d5e9f728815e27b7b612883db19107ba8a35a46a97c757ea00896cb027451" + url: "https://pub.dev" + source: hosted + version: "0.1.10+2" flutter_background_service: dependency: "direct main" description: @@ -429,39 +446,55 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" flutter_localizations: dependency: "direct main" description: flutter source: sdk version: "0.0.0" flutter_markdown: - dependency: "direct main" + dependency: transitive description: name: flutter_markdown - sha256: "15f39b20486760f9b85531ed2ef7f63e3a376210d2ff83614119ee93fda5670c" + sha256: "9921f9deda326f8a885e202b1e35237eadfc1345239a0f6f0f1ff287e047547f" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.1" + flutter_markdown_latex: + dependency: transitive + description: + name: flutter_markdown_latex + sha256: b07ade84e661a7a2e7b7e59bcfa95e481d38fd8782a8f9f2349a8cb1b056ae89 + url: "https://pub.dev" + source: hosted + version: "0.3.2" + flutter_math_fork: + dependency: transitive + description: + name: flutter_math_fork + sha256: "94bee4642892a94939af0748c6a7de0ff8318feee588379dcdfea7dc5cba06c8" + url: "https://pub.dev" + source: hosted + version: "0.7.2" flutter_native_splash: dependency: "direct dev" description: name: flutter_native_splash - sha256: "45e2c0986d749c070509e03d6c7ad6c8bd1f7b1dad7d11dd8750a5e4fe3e2c0b" + sha256: edf39bcf4d74aca1eb2c1e43c3e445fd9f494013df7f0da752fefe72020eedc0 url: "https://pub.dev" source: hosted - version: "2.3.11" + version: "2.4.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.19" flutter_svg: dependency: transitive description: @@ -484,18 +517,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" - get_it: - dependency: "direct main" - description: - name: get_it - sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 - url: "https://pub.dev" - source: hosted - version: "7.6.7" + version: "4.0.0" glob: dependency: transitive description: @@ -585,7 +610,7 @@ packages: source: hosted version: "4.0.2" icloud_storage: - dependency: "direct main" + dependency: transitive description: name: icloud_storage sha256: fa91d9c3b4264651f01a4f5b99cffa354ffe455623b13ecf92be86d88b1e26ea @@ -636,10 +661,10 @@ packages: dependency: transitive description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" leak_tracker: dependency: transitive description: @@ -681,29 +706,29 @@ packages: source: hosted version: "3.0.0" local_auth: - dependency: "direct main" + dependency: transitive description: name: local_auth - sha256: "27679ed8e0d7daab2357db6bb7076359e083a56b295c0c59723845301da6aed9" + sha256: "280421b416b32de31405b0a25c3bd42dfcef2538dfbb20c03019e02a5ed55ed0" url: "https://pub.dev" source: hosted - version: "2.1.8" + version: "2.2.0" local_auth_android: dependency: transitive description: name: local_auth_android - sha256: "3bcd732dda7c75fcb7ddaef12e131230f53dcc8c00790d0d6efb3aa0fbbeda57" + sha256: e0e5b1ea247c5a0951c13a7ee13dc1beae69750e6a2e1910d1ed6a3cd4d56943 url: "https://pub.dev" source: hosted - version: "1.0.37" - local_auth_ios: + version: "1.0.38" + local_auth_darwin: dependency: transitive description: - name: local_auth_ios - sha256: "6dde47dc852bc0c8343cb58e66a46efb16b62eddf389ce103d4dacb0c6c40c71" + name: local_auth_darwin + sha256: "959145a4cf6f0de745b9ec9ac60101270eb4c5b8b7c2a0470907014adc1c618d" url: "https://pub.dev" source: hosted - version: "1.1.7" + version: "1.3.0" local_auth_platform_interface: dependency: transitive description: @@ -721,7 +746,7 @@ packages: source: hosted version: "1.0.10" logging: - dependency: "direct main" + dependency: transitive description: name: logging sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" @@ -732,10 +757,10 @@ packages: dependency: transitive description: name: markdown - sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90" + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 url: "https://pub.dev" source: hosted - version: "7.2.1" + version: "7.2.2" matcher: dependency: transitive description: @@ -788,10 +813,10 @@ packages: dependency: transitive description: name: package_info_plus - sha256: "2c582551839386fa7ddbc7770658be7c0f87f388a4bff72066478f597c34d17f" + sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.0.0" package_info_plus_platform_interface: dependency: transitive description: @@ -817,29 +842,29 @@ packages: source: hosted version: "1.0.1" path_provider: - dependency: "direct main" + dependency: transitive description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.4" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -873,7 +898,7 @@ packages: source: hosted version: "1.11.1" permission_handler: - dependency: "direct main" + dependency: transitive description: name: permission_handler sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" @@ -884,10 +909,10 @@ packages: dependency: transitive description: name: permission_handler_android - sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" + sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5" url: "https://pub.dev" source: hosted - version: "12.0.5" + version: "12.0.6" permission_handler_apple: dependency: transitive description: @@ -964,10 +989,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" url: "https://pub.dev" source: hosted - version: "3.7.4" + version: "3.9.1" pool: dependency: transitive description: @@ -980,10 +1005,10 @@ packages: dependency: "direct main" description: name: provider - sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.2" pub_semver: dependency: transitive description: @@ -1017,45 +1042,45 @@ packages: source: hosted version: "0.1.9" share_plus: - dependency: "direct main" + dependency: transitive description: name: share_plus - sha256: fb5319f3aab4c5dda5ebb92dca978179ba21f8c783ee4380910ef4c1c6824f51 + sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "9.0.0" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496" + sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "4.0.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.0" shared_preferences_linux: dependency: transitive description: @@ -1197,6 +1222,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" typed_data: dependency: transitive description: @@ -1214,29 +1247,29 @@ packages: source: hosted version: "2.2.2" url_launcher: - dependency: "direct main" + dependency: transitive description: name: url_launcher - sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.2.6" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 + sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.0" url_launcher_linux: dependency: transitive description: @@ -1249,10 +1282,10 @@ packages: dependency: transitive description: name: url_launcher_macos - sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.0" url_launcher_platform_interface: dependency: transitive description: @@ -1281,10 +1314,10 @@ packages: dependency: transitive description: name: uuid - sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" url: "https://pub.dev" source: hosted - version: "4.3.3" + version: "4.4.0" vector_graphics: dependency: transitive description: @@ -1337,10 +1370,10 @@ packages: dependency: "direct main" description: name: wakelock_plus - sha256: c8b7cc80f045533b40a0e6c9109905494e3cf32c0fbd5c62616998e0de44003f + sha256: "14758533319a462ffb5aa3b7ddb198e59b29ac3b02da14173a1715d65d4e6e68" url: "https://pub.dev" source: hosted - version: "1.2.4" + version: "1.2.5" wakelock_plus_platform_interface: dependency: transitive description: @@ -1391,7 +1424,7 @@ packages: source: hosted version: "2.4.5" webdav_client: - dependency: "direct main" + dependency: transitive description: path: "." ref: main @@ -1408,7 +1441,7 @@ packages: source: hosted version: "5.5.0" window_manager: - dependency: "direct main" + dependency: transitive description: name: window_manager sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 @@ -1457,5 +1490,5 @@ packages: source: hosted version: "0.0.6" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.3.3 <4.0.0" flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0cec0057..7179a8bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,28 +13,21 @@ dependencies: flutter_localizations: sdk: flutter provider: ^6.0.0 - get_it: ^7.2.0 hive_flutter: ^1.1.0 dio: ^5.2.1 after_layout: ^1.1.0 - url_launcher: ^6.1.8 - countly_flutter: ^24.4.0 dartssh2: #^2.9.1-pre # newer version has some issues git: ref: dev url: https://github.com/lollipopkit/dartssh2 #path: ../dartssh2 - logging: ^1.0.2 circle_chart: git: url: https://github.com/lollipopkit/circle_chart ref: main # path: ../circle_chart - - path_provider: ^2.0.9 easy_isolate: ^1.3.0 - share_plus: ^8.0.3 intl: ^0.18.0 # xterm: ^3.5.0 xterm: @@ -49,8 +42,6 @@ dependencies: code_text_field: ^1.1.0 shared_preferences: ^2.1.1 dynamic_color: ^1.6.6 - icloud_storage: ^2.2.0 - local_auth: ^2.1.7 watch_connectivity: #path: ../watch_connectivity git: @@ -59,24 +50,23 @@ dependencies: choice: ^2.0.0 #flutter_secure_storage: ^9.0.0 xml: ^6.4.2 # for parsing nvidia-smi - webdav_client: - git: - ref: main - url: https://github.com/lollipopkit/webdav_client - window_manager: ^0.3.7 flutter_displaymode: ^0.6.0 - flutter_markdown: ^0.7.0 computer: git: ref: master url: https://github.com/lollipopkit/dart_computer flutter_background_service: ^5.0.5 icons_plus: ^5.0.0 - permission_handler: ^11.3.1 fl_chart: ^0.67.0 wakelock_plus: ^1.2.4 extended_image: ^8.2.0 wake_on_lan: ^4.1.1+3 + flutter_adaptive_scaffold: ^0.1.10+2 + fl_lib: + git: + url: https://github.com/lollipopkit/fl_lib + ref: main + #path: ../fl_lib dev_dependencies: flutter_native_splash: ^2.1.6