mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
opt.: migrate fl_lib
This commit is contained in:
@@ -24,6 +24,7 @@ linter:
|
|||||||
rules:
|
rules:
|
||||||
library_private_types_in_public_api: false
|
library_private_types_in_public_api: false
|
||||||
use_build_context_synchronously: false
|
use_build_context_synchronously: false
|
||||||
|
depend_on_referenced_packages: false
|
||||||
prefer_final_locals: true
|
prefer_final_locals: true
|
||||||
unnecessary_parenthesis: true
|
unnecessary_parenthesis: true
|
||||||
implicit_call_tearoffs: true
|
implicit_call_tearoffs: true
|
||||||
|
|||||||
@@ -690,7 +690,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -700,7 +700,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -826,7 +826,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -836,7 +836,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -854,7 +854,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -864,7 +864,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -885,7 +885,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -898,7 +898,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
@@ -924,7 +924,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -937,7 +937,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -960,7 +960,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -973,7 +973,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -996,7 +996,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -1008,7 +1008,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||||
@@ -1037,7 +1037,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -1049,7 +1049,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||||
PRODUCT_NAME = ServerBox;
|
PRODUCT_NAME = ServerBox;
|
||||||
@@ -1075,7 +1075,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 893;
|
CURRENT_PROJECT_VERSION = 896;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -1087,7 +1087,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.893;
|
MARKETING_VERSION = 1.0.896;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||||
PRODUCT_NAME = ServerBox;
|
PRODUCT_NAME = ServerBox;
|
||||||
|
|||||||
20
lib/app.dart
20
lib/app.dart
@@ -1,12 +1,9 @@
|
|||||||
import 'package:dynamic_color/dynamic_color.dart';
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.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/core/utils/ui.dart';
|
||||||
import 'package:toolbox/data/res/build_data.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/rebuild.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
import 'package:toolbox/view/page/home/home.dart';
|
import 'package:toolbox/view/page/home/home.dart';
|
||||||
@@ -21,7 +18,7 @@ class MyApp extends StatelessWidget {
|
|||||||
listenable: RebuildNodes.app,
|
listenable: RebuildNodes.app,
|
||||||
builder: (_, __) {
|
builder: (_, __) {
|
||||||
if (!Stores.setting.useSystemPrimaryColor.fetch()) {
|
if (!Stores.setting.useSystemPrimaryColor.fetch()) {
|
||||||
primaryColor = Color(Stores.setting.primaryColor.fetch());
|
UIs.colorSeed = Color(Stores.setting.primaryColor.fetch());
|
||||||
return _buildApp();
|
return _buildApp();
|
||||||
}
|
}
|
||||||
return DynamicColorBuilder(
|
return DynamicColorBuilder(
|
||||||
@@ -36,9 +33,9 @@ class MyApp extends StatelessWidget {
|
|||||||
colorScheme: dark,
|
colorScheme: dark,
|
||||||
);
|
);
|
||||||
if (context.isDark && light != null) {
|
if (context.isDark && light != null) {
|
||||||
primaryColor = light.primary;
|
UIs.primaryColor = light.primary;
|
||||||
} else if (!context.isDark && dark != null) {
|
} else if (!context.isDark && dark != null) {
|
||||||
primaryColor = dark.primary;
|
UIs.primaryColor = dark.primary;
|
||||||
}
|
}
|
||||||
return _buildApp(light: lightTheme, dark: darkTheme);
|
return _buildApp(light: lightTheme, dark: darkTheme);
|
||||||
},
|
},
|
||||||
@@ -59,12 +56,12 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
light ??= ThemeData(
|
light ??= ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
colorSchemeSeed: primaryColor,
|
colorSchemeSeed: UIs.colorSeed,
|
||||||
);
|
);
|
||||||
dark ??= ThemeData(
|
dark ??= ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
colorSchemeSeed: primaryColor,
|
colorSchemeSeed: UIs.colorSeed,
|
||||||
);
|
);
|
||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
@@ -88,7 +85,10 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
void _setup(BuildContext context) async {
|
void _setup(BuildContext context) async {
|
||||||
setTransparentNavigationBar(context);
|
setTransparentNavigationBar(context);
|
||||||
Analysis.init();
|
Analysis.init(
|
||||||
|
'https://countly.lolli.tech',
|
||||||
|
'0772e65c696709f879d87db77ae1a811259e3eb9',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData _getAmoledTheme(ThemeData darkTheme) => darkTheme.copyWith(
|
ThemeData _getAmoledTheme(ThemeData darkTheme) => darkTheme.copyWith(
|
||||||
|
|||||||
@@ -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<void> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
const _interactiveStates = <MaterialState>{
|
|
||||||
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<Color?> 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),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
extension ContextX on BuildContext {
|
|
||||||
void pop<T extends Object?>([T? result]) {
|
|
||||||
Navigator.of(this).pop<T>(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get canPop => Navigator.of(this).canPop();
|
|
||||||
|
|
||||||
bool get isDark => Theme.of(this).brightness == Brightness.dark;
|
|
||||||
}
|
|
||||||
@@ -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<T?> showRoundDialog<T>({
|
|
||||||
Widget? child,
|
|
||||||
List<Widget>? actions,
|
|
||||||
Widget? title,
|
|
||||||
bool barrierDismiss = true,
|
|
||||||
void Function(BuildContext)? onContext,
|
|
||||||
}) async {
|
|
||||||
return await showDialog<T>(
|
|
||||||
context: this,
|
|
||||||
barrierDismissible: barrierDismiss,
|
|
||||||
builder: (ctx) {
|
|
||||||
onContext?.call(ctx);
|
|
||||||
return AlertDialog(
|
|
||||||
title: title,
|
|
||||||
content: child,
|
|
||||||
actions: actions,
|
|
||||||
actionsPadding: const EdgeInsets.all(17),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<T> showLoadingDialog<T>({
|
|
||||||
required Future<T> 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 = <String, String>{};
|
|
||||||
|
|
||||||
/// Show a dialog to input password
|
|
||||||
///
|
|
||||||
/// [hostId] set it to null to skip remembering the password
|
|
||||||
Future<String?> showPwdDialog({
|
|
||||||
String? hostId,
|
|
||||||
String? title,
|
|
||||||
String? label,
|
|
||||||
}) async {
|
|
||||||
if (!mounted) return null;
|
|
||||||
return await showRoundDialog<String>(
|
|
||||||
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<List<T>?> showPickDialog<T>({
|
|
||||||
required List<T?> items,
|
|
||||||
String Function(T)? name,
|
|
||||||
bool multi = true,
|
|
||||||
List<T>? initial,
|
|
||||||
bool clearable = false,
|
|
||||||
List<Widget>? actions,
|
|
||||||
}) async {
|
|
||||||
var vals = initial ?? <T>[];
|
|
||||||
final sure = await showRoundDialog<bool>(
|
|
||||||
title: Text(l10n.choose),
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: Choice<T>(
|
|
||||||
onChanged: (value) => vals = value,
|
|
||||||
multiple: multi,
|
|
||||||
clearable: clearable,
|
|
||||||
value: vals,
|
|
||||||
builder: (state, _) {
|
|
||||||
return Wrap(
|
|
||||||
children: List<Widget>.generate(
|
|
||||||
items.length,
|
|
||||||
(index) {
|
|
||||||
final item = items[index];
|
|
||||||
if (item == null) return UIs.placeholder;
|
|
||||||
return ChoiceChipX<T>(
|
|
||||||
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<T?> showPickSingleDialog<T>({
|
|
||||||
required List<T?> items,
|
|
||||||
String Function(T)? name,
|
|
||||||
T? initial,
|
|
||||||
bool clearable = false,
|
|
||||||
List<Widget>? actions,
|
|
||||||
}) async {
|
|
||||||
final vals = await showPickDialog<T>(
|
|
||||||
items: items,
|
|
||||||
name: name,
|
|
||||||
multi: false,
|
|
||||||
initial: initial == null ? null : [initial],
|
|
||||||
actions: actions,
|
|
||||||
);
|
|
||||||
if (vals != null && vals.isNotEmpty) {
|
|
||||||
return vals.first;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<T>?> showPickWithTagDialog<T>({
|
|
||||||
required List<T?> Function(String? tag) itemsBuilder,
|
|
||||||
required ValueNotifier<List<String>> tags,
|
|
||||||
String Function(T)? name,
|
|
||||||
List<T>? initial,
|
|
||||||
bool clearable = false,
|
|
||||||
bool multi = false,
|
|
||||||
List<Widget>? actions,
|
|
||||||
}) async {
|
|
||||||
var vals = initial ?? <T>[];
|
|
||||||
final tag = ValueNotifier<String?>(null);
|
|
||||||
final sure = await showRoundDialog<bool>(
|
|
||||||
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<T>(
|
|
||||||
onChanged: (value) => vals = value,
|
|
||||||
multiple: multi,
|
|
||||||
clearable: clearable,
|
|
||||||
value: vals,
|
|
||||||
builder: (state, _) {
|
|
||||||
return Wrap(
|
|
||||||
children: List<Widget>.generate(
|
|
||||||
items.length,
|
|
||||||
(index) {
|
|
||||||
final item = items[index];
|
|
||||||
if (item == null) return UIs.placeholder;
|
|
||||||
return ChoiceChipX<T>(
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
extension EnumListX<T> on List<T> {
|
|
||||||
T fromIndex(int index, [T? defaultValue]) {
|
|
||||||
try {
|
|
||||||
return this[index];
|
|
||||||
} catch (e) {
|
|
||||||
if (defaultValue != null) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
throw Exception('Invalid index: $index');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
extension ListX<T> on List<T> {
|
|
||||||
List<T> joinWith(T item, [bool self = true]) {
|
|
||||||
final list = self ? this : List<T>.from(this);
|
|
||||||
for (var i = length - 1; i > 0; i--) {
|
|
||||||
list.insert(i, item);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<T> combine(List<T> other, [bool self = true]) {
|
|
||||||
final list = self ? this : List<T>.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
extension MideaQueryX on MediaQueryData {
|
|
||||||
bool get useDoubleColumn => size.width > 639;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
import 'package:toolbox/core/extension/listx.dart';
|
|
||||||
import 'package:toolbox/core/persistant_store.dart';
|
|
||||||
|
|
||||||
typedef _OnMove<T> = void Function(List<T>);
|
|
||||||
|
|
||||||
extension OrderX<T> on List<T> {
|
|
||||||
void move(
|
|
||||||
int oldIndex,
|
|
||||||
int newIndex, {
|
|
||||||
StorePropertyBase<List<T>>? property,
|
|
||||||
_OnMove<T>? 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<T>? filtered,
|
|
||||||
StorePropertyBase<List<T>>? property,
|
|
||||||
_OnMove<T>? 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<String> reorder({
|
|
||||||
required List<String> order,
|
|
||||||
required bool Function(T, String) finder,
|
|
||||||
}) {
|
|
||||||
final newOrder = <T>[];
|
|
||||||
final missed = <T>[];
|
|
||||||
final surplus = <String>[];
|
|
||||||
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<T> other) {
|
|
||||||
if (length != other.length) return false;
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
if (this[i] != other[i]) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,8 @@ import 'dart:async';
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/widgets.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';
|
import '../../data/res/misc.dart';
|
||||||
|
|
||||||
@@ -81,7 +79,7 @@ extension SSHClientX on SSHClient {
|
|||||||
isRequestingPwd = true;
|
isRequestingPwd = true;
|
||||||
final user = Miscs.pwdRequestWithUserReg.firstMatch(data)?.group(1);
|
final user = Miscs.pwdRequestWithUserReg.firstMatch(data)?.group(1);
|
||||||
if (context == null) return;
|
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) {
|
if (pwd == null || pwd.isEmpty) {
|
||||||
session.kill(SSHSignal.TERM);
|
session.kill(SSHSignal.TERM);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
extension FutureUint8ListX on Future<Uint8List> {
|
|
||||||
Future<String> get string async => utf8.decode(await this);
|
|
||||||
Future<ByteData> get byteData async => (await this).buffer.asByteData();
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Uint8ListX on Uint8List {
|
|
||||||
String get string => utf8.decode(this);
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<void> 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<void> init() async => box = await Hive.openBox(
|
|
||||||
boxName,
|
|
||||||
//encryptionCipher: SecureStore._cipher,
|
|
||||||
);
|
|
||||||
|
|
||||||
_StoreProperty<T> property<T>(
|
|
||||||
String key,
|
|
||||||
T defaultValue, {
|
|
||||||
bool updateLastModified = true,
|
|
||||||
}) {
|
|
||||||
return _StoreProperty<T>(
|
|
||||||
box,
|
|
||||||
key,
|
|
||||||
defaultValue,
|
|
||||||
updateLastModified: updateLastModified,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_StoreListProperty<T> listProperty<T>(
|
|
||||||
String key,
|
|
||||||
List<T> defaultValue, {
|
|
||||||
bool updateLastModified = true,
|
|
||||||
}) {
|
|
||||||
return _StoreListProperty<T>(
|
|
||||||
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<void> updateLastModified([int? time]) => put(
|
|
||||||
lastModifiedKey,
|
|
||||||
time ?? timeStamp,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Convert db to json
|
|
||||||
Map<String, dynamic> toJson({bool includeInternal = true}) {
|
|
||||||
final json = <String, dynamic>{};
|
|
||||||
for (final key in keys) {
|
|
||||||
if (key is String &&
|
|
||||||
key.startsWith(_internalPreffix) &&
|
|
||||||
!includeInternal) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
json[key] = get(key);
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class StorePropertyBase<T> {
|
|
||||||
ValueListenable<T> listenable();
|
|
||||||
T fetch();
|
|
||||||
Future<void> put(T value);
|
|
||||||
Future<void> delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _StoreProperty<T> implements StorePropertyBase<T> {
|
|
||||||
_StoreProperty(
|
|
||||||
this._box,
|
|
||||||
this._key,
|
|
||||||
this.defaultValue, {
|
|
||||||
this.updateLastModified = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Box _box;
|
|
||||||
final String _key;
|
|
||||||
T defaultValue;
|
|
||||||
bool updateLastModified;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ValueListenable<T> listenable() {
|
|
||||||
return PropertyListenable<T>(_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<void> put(T value) {
|
|
||||||
if (updateLastModified) _box.updateLastModified();
|
|
||||||
return _box.put(_key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> delete() {
|
|
||||||
return _box.delete(_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _StoreListProperty<T> implements StorePropertyBase<List<T>> {
|
|
||||||
_StoreListProperty(
|
|
||||||
this._box,
|
|
||||||
this._key,
|
|
||||||
this.defaultValue, {
|
|
||||||
this.updateLastModified = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Box _box;
|
|
||||||
final String _key;
|
|
||||||
List<T> defaultValue;
|
|
||||||
bool updateLastModified;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ValueListenable<List<T>> listenable() {
|
|
||||||
return PropertyListenable<List<T>>(_box, _key, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<T> 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<T>.from(val);
|
|
||||||
} catch (_) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> put(List<T> value) {
|
|
||||||
if (updateLastModified) _box.updateLastModified();
|
|
||||||
return _box.put(_key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> delete() {
|
|
||||||
return _box.delete(_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropertyListenable<T> extends ValueListenable<T> {
|
|
||||||
PropertyListenable(this.box, this.key, this.defaultValue);
|
|
||||||
|
|
||||||
final Box box;
|
|
||||||
final String key;
|
|
||||||
T? defaultValue;
|
|
||||||
|
|
||||||
final List<VoidCallback> _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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.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/private_key_info.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.dart';
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
import 'package:toolbox/data/res/store.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.dart';
|
||||||
import '../view/page/storage/sftp_mission.dart';
|
import '../view/page/storage/sftp_mission.dart';
|
||||||
|
|
||||||
class AppRoute {
|
class AppRoutes {
|
||||||
final Widget page;
|
final Widget page;
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
AppRoute(this.page, this.title);
|
AppRoutes(this.page, this.title);
|
||||||
|
|
||||||
Future<T?> go<T>(BuildContext context) {
|
Future<T?> go<T>(BuildContext context) {
|
||||||
Analysis.recordView(title);
|
|
||||||
return Navigator.push<T>(
|
return Navigator.push<T>(
|
||||||
context,
|
context,
|
||||||
Stores.setting.cupertinoRoute.fetch()
|
Stores.setting.cupertinoRoute.fetch()
|
||||||
@@ -61,49 +59,49 @@ class AppRoute {
|
|||||||
return Future.value(null);
|
return Future.value(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute serverDetail({Key? key, required ServerPrivateInfo spi}) {
|
static AppRoutes serverDetail({Key? key, required ServerPrivateInfo spi}) {
|
||||||
return AppRoute(ServerDetailPage(key: key, spi: spi), 'server_detail');
|
return AppRoutes(ServerDetailPage(key: key, spi: spi), 'server_detail');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute serverTab({Key? key}) {
|
static AppRoutes serverTab({Key? key}) {
|
||||||
return AppRoute(ServerPage(key: key), 'server_tab');
|
return AppRoutes(ServerPage(key: key), 'server_tab');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute serverEdit({Key? key, ServerPrivateInfo? spi}) {
|
static AppRoutes serverEdit({Key? key, ServerPrivateInfo? spi}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
ServerEditPage(spi: spi),
|
ServerEditPage(spi: spi),
|
||||||
'server_${spi == null ? 'add' : 'edit'}',
|
'server_${spi == null ? 'add' : 'edit'}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute keyEdit({Key? key, PrivateKeyInfo? pki}) {
|
static AppRoutes keyEdit({Key? key, PrivateKeyInfo? pki}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
PrivateKeyEditPage(pki: pki),
|
PrivateKeyEditPage(pki: pki),
|
||||||
'key_${pki == null ? 'add' : 'edit'}',
|
'key_${pki == null ? 'add' : 'edit'}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute keyList({Key? key}) {
|
static AppRoutes keyList({Key? key}) {
|
||||||
return AppRoute(PrivateKeysListPage(key: key), 'key_detail');
|
return AppRoutes(PrivateKeysListPage(key: key), 'key_detail');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute snippetEdit({Key? key, Snippet? snippet}) {
|
static AppRoutes snippetEdit({Key? key, Snippet? snippet}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
SnippetEditPage(snippet: snippet),
|
SnippetEditPage(snippet: snippet),
|
||||||
'snippet_${snippet == null ? 'add' : 'edit'}',
|
'snippet_${snippet == null ? 'add' : 'edit'}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute snippetList({Key? key}) {
|
static AppRoutes snippetList({Key? key}) {
|
||||||
return AppRoute(SnippetListPage(key: key), 'snippet_detail');
|
return AppRoutes(SnippetListPage(key: key), 'snippet_detail');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute ssh({
|
static AppRoutes ssh({
|
||||||
Key? key,
|
Key? key,
|
||||||
required ServerPrivateInfo spi,
|
required ServerPrivateInfo spi,
|
||||||
String? initCmd,
|
String? initCmd,
|
||||||
}) {
|
}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
SSHPage(
|
SSHPage(
|
||||||
key: key,
|
key: key,
|
||||||
spi: spi,
|
spi: spi,
|
||||||
@@ -113,13 +111,13 @@ class AppRoute {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute sshVirtKeySetting({Key? key}) {
|
static AppRoutes sshVirtKeySetting({Key? key}) {
|
||||||
return AppRoute(SSHVirtKeySettingPage(key: key), 'ssh_virt_key_setting');
|
return AppRoutes(SSHVirtKeySettingPage(key: key), 'ssh_virt_key_setting');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute localStorage(
|
static AppRoutes localStorage(
|
||||||
{Key? key, bool isPickFile = false, String? initDir}) {
|
{Key? key, bool isPickFile = false, String? initDir}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
LocalStoragePage(
|
LocalStoragePage(
|
||||||
key: key,
|
key: key,
|
||||||
isPickFile: isPickFile,
|
isPickFile: isPickFile,
|
||||||
@@ -128,16 +126,16 @@ class AppRoute {
|
|||||||
'local_storage');
|
'local_storage');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute sftpMission({Key? key}) {
|
static AppRoutes sftpMission({Key? key}) {
|
||||||
return AppRoute(SftpMissionPage(key: key), 'sftp_mission');
|
return AppRoutes(SftpMissionPage(key: key), 'sftp_mission');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute sftp(
|
static AppRoutes sftp(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
required ServerPrivateInfo spi,
|
required ServerPrivateInfo spi,
|
||||||
String? initPath,
|
String? initPath,
|
||||||
bool isSelect = false}) {
|
bool isSelect = false}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
SftpPage(
|
SftpPage(
|
||||||
key: key,
|
key: key,
|
||||||
spi: spi,
|
spi: spi,
|
||||||
@@ -147,28 +145,28 @@ class AppRoute {
|
|||||||
'sftp');
|
'sftp');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute backup({Key? key}) {
|
static AppRoutes backup({Key? key}) {
|
||||||
return AppRoute(BackupPage(key: key), 'backup');
|
return AppRoutes(BackupPage(key: key), 'backup');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute debug({Key? key}) {
|
static AppRoutes debug({Key? key}) {
|
||||||
return AppRoute(DebugPage(key: key), 'debug');
|
return AppRoutes(DebugPage(key: key), 'debug');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute docker({Key? key, required ServerPrivateInfo spi}) {
|
static AppRoutes docker({Key? key, required ServerPrivateInfo spi}) {
|
||||||
return AppRoute(ContainerPage(key: key, spi: spi), 'docker');
|
return AppRoutes(ContainerPage(key: key, spi: spi), 'docker');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// - Pop true if the text is changed & [path] is not null
|
/// - Pop true if the text is changed & [path] is not null
|
||||||
/// - Pop text if [path] is null
|
/// - Pop text if [path] is null
|
||||||
static AppRoute editor({
|
static AppRoutes editor({
|
||||||
Key? key,
|
Key? key,
|
||||||
String? path,
|
String? path,
|
||||||
String? text,
|
String? text,
|
||||||
String? langCode,
|
String? langCode,
|
||||||
String? title,
|
String? title,
|
||||||
}) {
|
}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
EditorPage(
|
EditorPage(
|
||||||
key: key,
|
key: key,
|
||||||
path: path,
|
path: path,
|
||||||
@@ -179,45 +177,45 @@ class AppRoute {
|
|||||||
'editor');
|
'editor');
|
||||||
}
|
}
|
||||||
|
|
||||||
// static AppRoute fullscreen({Key? key}) {
|
// static AppRoutes fullscreen({Key? key}) {
|
||||||
// return AppRoute(FullScreenPage(key: key), 'fullscreen');
|
// return AppRoutes(FullScreenPage(key: key), 'fullscreen');
|
||||||
// }
|
// }
|
||||||
|
|
||||||
static AppRoute home({Key? key}) {
|
static AppRoutes home({Key? key}) {
|
||||||
return AppRoute(HomePage(key: key), 'home');
|
return AppRoutes(HomePage(key: key), 'home');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute ping({Key? key}) {
|
static AppRoutes ping({Key? key}) {
|
||||||
return AppRoute(PingPage(key: key), 'ping');
|
return AppRoutes(PingPage(key: key), 'ping');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute process({Key? key, required ServerPrivateInfo spi}) {
|
static AppRoutes process({Key? key, required ServerPrivateInfo spi}) {
|
||||||
return AppRoute(ProcessPage(key: key, spi: spi), 'process');
|
return AppRoutes(ProcessPage(key: key, spi: spi), 'process');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute settings({Key? key}) {
|
static AppRoutes settings({Key? key}) {
|
||||||
return AppRoute(SettingPage(key: key), 'setting');
|
return AppRoutes(SettingPage(key: key), 'setting');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute serverOrder({Key? key}) {
|
static AppRoutes serverOrder({Key? key}) {
|
||||||
return AppRoute(ServerOrderPage(key: key), 'server_order');
|
return AppRoutes(ServerOrderPage(key: key), 'server_order');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute serverDetailOrder({Key? key}) {
|
static AppRoutes serverDetailOrder({Key? key}) {
|
||||||
return AppRoute(ServerDetailOrderPage(key: key), 'server_detail_order');
|
return AppRoutes(ServerDetailOrderPage(key: key), 'server_detail_order');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute iosSettings({Key? key}) {
|
static AppRoutes iosSettings({Key? key}) {
|
||||||
return AppRoute(IOSSettingsPage(key: key), 'ios_setting');
|
return AppRoutes(IOSSettingsPage(key: key), 'ios_setting');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute androidSettings({Key? key}) {
|
static AppRoutes androidSettings({Key? key}) {
|
||||||
return AppRoute(AndroidSettingsPage(key: key), 'android_setting');
|
return AppRoutes(AndroidSettingsPage(key: key), 'android_setting');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute snippetResult(
|
static AppRoutes snippetResult(
|
||||||
{Key? key, required List<SnippetResult?> results}) {
|
{Key? key, required List<SnippetResult?> results}) {
|
||||||
return AppRoute(
|
return AppRoutes(
|
||||||
SnippetResultPage(
|
SnippetResultPage(
|
||||||
key: key,
|
key: key,
|
||||||
results: results,
|
results: results,
|
||||||
@@ -225,15 +223,15 @@ class AppRoute {
|
|||||||
'snippet_result');
|
'snippet_result');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute iperf({Key? key, required ServerPrivateInfo spi}) {
|
static AppRoutes iperf({Key? key, required ServerPrivateInfo spi}) {
|
||||||
return AppRoute(IPerfPage(key: key, spi: spi), 'iperf');
|
return AppRoutes(IPerfPage(key: key, spi: spi), 'iperf');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute serverFuncBtnsOrder({Key? key}) {
|
static AppRoutes serverFuncBtnsOrder({Key? key}) {
|
||||||
return AppRoute(ServerFuncBtnsOrderPage(key: key), 'server_func_btns_seq');
|
return AppRoutes(ServerFuncBtnsOrderPage(key: key), 'server_func_btns_seq');
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppRoute pve({Key? key, required ServerPrivateInfo spi}) {
|
static AppRoutes pve({Key? key, required ServerPrivateInfo spi}) {
|
||||||
return AppRoute(PvePage(key: key, spi: spi), 'pve');
|
return AppRoutes(PvePage(key: key, spi: spi), 'pve');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<bool> 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<void> doUpdate(BuildContext context, {bool force = false}) async {
|
|
||||||
final update = await locator<AppService>().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<void> _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);
|
|
||||||
}
|
|
||||||
@@ -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<String, int> startTimeMap = <String, int>{
|
|
||||||
_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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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:plain_notification_token/plain_notification_token.dart';
|
||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
|
||||||
|
|
||||||
Future<String?> 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<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
if (isIOS) {
|
if (isIOS) {
|
||||||
@@ -29,22 +21,3 @@ String? getFileName(String? path) {
|
|||||||
}
|
}
|
||||||
return path.split('/').last;
|
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;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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<bool> 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<void> 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<AuthResult> 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,
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
|
|
||||||
abstract final class PermUtils {
|
|
||||||
static Future<bool> request(Permission permission) async {
|
|
||||||
final status = await permission.status;
|
|
||||||
if (status.isGranted) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
final result = await permission.request();
|
|
||||||
return result.isGranted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<bool> files(List<String> 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<bool> 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<String?> paste([String type = 'text/plain']) async {
|
|
||||||
final data = await Clipboard.getData(type);
|
|
||||||
return data?.text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.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/locale.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.dart';
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
@@ -14,6 +14,7 @@ abstract final class KeybordInteractive {
|
|||||||
try {
|
try {
|
||||||
final res = await (ctx ?? Pros.app.ctx)?.showPwdDialog(
|
final res = await (ctx ?? Pros.app.ctx)?.showPwdDialog(
|
||||||
title: '2FA ${l10n.pwd}',
|
title: '2FA ${l10n.pwd}',
|
||||||
|
id: spi.id,
|
||||||
label: spi.id,
|
label: spi.id,
|
||||||
);
|
);
|
||||||
return res == null ? null : [res];
|
return res == null ? null : [res];
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import 'dart:async';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:icloud_storage/icloud_storage.dart';
|
import 'package:icloud_storage/icloud_storage.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:toolbox/data/model/app/backup.dart';
|
import 'package:toolbox/data/model/app/backup.dart';
|
||||||
import 'package:toolbox/data/model/app/sync.dart';
|
import 'package:toolbox/data/model/app/sync.dart';
|
||||||
|
|
||||||
import '../../../data/model/app/error.dart';
|
import '../../../data/model/app/error.dart';
|
||||||
import '../../../data/res/path.dart';
|
|
||||||
|
|
||||||
abstract final class ICloud {
|
abstract final class ICloud {
|
||||||
static const _containerId = 'iCloud.tech.lolli.serverbox';
|
static const _containerId = 'iCloud.tech.lolli.serverbox';
|
||||||
@@ -31,7 +31,7 @@ abstract final class ICloud {
|
|||||||
try {
|
try {
|
||||||
await ICloudStorage.upload(
|
await ICloudStorage.upload(
|
||||||
containerId: _containerId,
|
containerId: _containerId,
|
||||||
filePath: localPath ?? '${await Paths.doc}/$relativePath',
|
filePath: localPath ?? '${Paths.doc}/$relativePath',
|
||||||
destinationRelativePath: relativePath,
|
destinationRelativePath: relativePath,
|
||||||
onProgress: (stream) {
|
onProgress: (stream) {
|
||||||
stream.listen(
|
stream.listen(
|
||||||
@@ -85,7 +85,7 @@ abstract final class ICloud {
|
|||||||
await ICloudStorage.download(
|
await ICloudStorage.download(
|
||||||
containerId: _containerId,
|
containerId: _containerId,
|
||||||
relativePath: relativePath,
|
relativePath: relativePath,
|
||||||
destinationFilePath: localPath ?? '${await Paths.doc}/$relativePath',
|
destinationFilePath: localPath ?? '${Paths.doc}/$relativePath',
|
||||||
onProgress: (stream) {
|
onProgress: (stream) {
|
||||||
stream.listen(
|
stream.listen(
|
||||||
null,
|
null,
|
||||||
@@ -139,7 +139,7 @@ abstract final class ICloud {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
final docPath = await Paths.doc;
|
final docPath = Paths.doc;
|
||||||
|
|
||||||
/// compare files in iCloud and local
|
/// compare files in iCloud and local
|
||||||
missions.addAll(allFiles.map((file) async {
|
missions.addAll(allFiles.map((file) async {
|
||||||
@@ -205,7 +205,7 @@ abstract final class ICloud {
|
|||||||
return;
|
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);
|
final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile);
|
||||||
await dlBak.restore();
|
await dlBak.restore();
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:toolbox/data/model/app/backup.dart';
|
import 'package:toolbox/data/model/app/backup.dart';
|
||||||
import 'package:toolbox/data/model/app/error.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:toolbox/data/res/store.dart';
|
||||||
import 'package:webdav_client/webdav_client.dart';
|
import 'package:webdav_client/webdav_client.dart';
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ abstract final class Webdav {
|
|||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
await _client.writeFile(
|
await _client.writeFile(
|
||||||
localPath ?? '${await Paths.doc}/$relativePath',
|
localPath ?? '${Paths.doc}/$relativePath',
|
||||||
_prefix + relativePath,
|
_prefix + relativePath,
|
||||||
);
|
);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
@@ -64,7 +64,7 @@ abstract final class Webdav {
|
|||||||
try {
|
try {
|
||||||
await _client.readFile(
|
await _client.readFile(
|
||||||
_prefix + relativePath,
|
_prefix + relativePath,
|
||||||
localPath ?? '${await Paths.doc}/$relativePath',
|
localPath ?? '${Paths.doc}/$relativePath',
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_logger.warning('Download $relativePath failed');
|
_logger.warning('Download $relativePath failed');
|
||||||
@@ -104,7 +104,7 @@ abstract final class Webdav {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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);
|
final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile);
|
||||||
await dlBak.restore();
|
await dlBak.restore();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.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 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import 'misc.dart';
|
|
||||||
import '../extension/uint8list.dart';
|
|
||||||
|
|
||||||
Future<bool> openUrl(String url) async {
|
Future<bool> openUrl(String url) async {
|
||||||
return await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
|
return await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:logging/logging.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/private_key_info.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.dart';
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
import 'package:toolbox/data/model/server/snippet.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/provider.dart';
|
||||||
import 'package:toolbox/data/res/rebuild.dart';
|
import 'package:toolbox/data/res/rebuild.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
@@ -76,7 +74,7 @@ class Backup {
|
|||||||
|
|
||||||
static Future<String> backup([String? name]) async {
|
static Future<String> backup([String? name]) async {
|
||||||
final result = _diyEncrypt(json.encode(Backup.loadFromStore().toJson()));
|
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);
|
await File(path).writeAsString(result);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
abstract class PopMenu {
|
abstract class PopMenu {
|
||||||
static PopupMenuItem<T> build<T>(T t, IconData icon, String text) {
|
static PopupMenuItem<T> build<T>(
|
||||||
|
T t,
|
||||||
|
IconData icon,
|
||||||
|
String text, {
|
||||||
|
double? iconSize,
|
||||||
|
}) {
|
||||||
return PopupMenuItem<T>(
|
return PopupMenuItem<T>(
|
||||||
value: t,
|
value: t,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(icon),
|
Icon(icon, size: iconSize),
|
||||||
const SizedBox(
|
const SizedBox(width: 10),
|
||||||
width: 10,
|
|
||||||
),
|
|
||||||
Text(text),
|
Text(text),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/data/model/app/menu/base.dart';
|
|
||||||
|
|
||||||
enum ContainerMenu {
|
enum ContainerMenu {
|
||||||
start,
|
start,
|
||||||
@@ -64,10 +63,4 @@ enum ContainerMenu {
|
|||||||
// return s.stats;
|
// return s.stats;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PopupMenuItem<ContainerMenu> get widget => PopMenu.build(
|
|
||||||
this,
|
|
||||||
icon,
|
|
||||||
toStr,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ enum ServerFuncBtn {
|
|||||||
snippet,
|
snippet,
|
||||||
].map((e) => e.index).toList();
|
].map((e) => e.index).toList();
|
||||||
|
|
||||||
Icon icon([double? sizeDiff]) => switch (this) {
|
IconData get icon => switch (this) {
|
||||||
sftp => Icon(Icons.insert_drive_file, size: 15 + (sizeDiff ?? 0)),
|
sftp => Icons.insert_drive_file,
|
||||||
snippet => Icon(Icons.code, size: 15 + (sizeDiff ?? 0)),
|
snippet => Icons.code,
|
||||||
pkg => Icon(Icons.system_security_update, size: 15 + (sizeDiff ?? 0)),
|
pkg => Icons.system_security_update,
|
||||||
container => Icon(FontAwesome.docker_brand, size: 14 + (sizeDiff ?? 0)),
|
container => FontAwesome.docker_brand,
|
||||||
process => Icon(Icons.list_alt_outlined, size: 15 + (sizeDiff ?? 0)),
|
process => Icons.list_alt_outlined,
|
||||||
terminal => Icon(Icons.terminal, size: 15 + (sizeDiff ?? 0)),
|
terminal => Icons.terminal,
|
||||||
iperf => Icon(Icons.speed, size: 15 + (sizeDiff ?? 0)),
|
iperf => Icons.speed,
|
||||||
};
|
};
|
||||||
|
|
||||||
String get toStr => switch (this) {
|
String get toStr => switch (this) {
|
||||||
|
|||||||
@@ -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.
|
/// It's used on platform's file system.
|
||||||
/// So use [Platform.pathSeparator] to join path.
|
/// So use [Platform.pathSeparator] to join path.
|
||||||
@@ -23,7 +23,7 @@ class LocalPath {
|
|||||||
_path = '/';
|
_path = '/';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_path = joinPath(_path, newPath);
|
_path = _path.joinPath(newPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get canBack => path != '$_prefixPath/';
|
bool get canBack => path != '$_prefixPath/';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.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/model/app/version_related.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -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<String> changelog;
|
|
||||||
final Build build;
|
|
||||||
final AppUpdatePlatformSpecific<String> url;
|
|
||||||
|
|
||||||
factory AppUpdate.fromRawJson(String str) =>
|
|
||||||
AppUpdate.fromJson(json.decode(str));
|
|
||||||
|
|
||||||
String toRawJson() => json.encode(toJson());
|
|
||||||
|
|
||||||
factory AppUpdate.fromJson(Map<String, dynamic> json) => AppUpdate(
|
|
||||||
changelog: AppUpdatePlatformSpecific.fromJson(json["changelog"]),
|
|
||||||
build: Build.fromJson(json["build"]),
|
|
||||||
url: AppUpdatePlatformSpecific.fromJson(json["url"]),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
"changelog": changelog.toJson(),
|
|
||||||
"build": build.toJson(),
|
|
||||||
"url": url.toJson(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class Build {
|
|
||||||
Build({
|
|
||||||
required this.min,
|
|
||||||
required this.last,
|
|
||||||
});
|
|
||||||
|
|
||||||
final AppUpdatePlatformSpecific<int> min;
|
|
||||||
final AppUpdatePlatformSpecific<int> last;
|
|
||||||
|
|
||||||
factory Build.fromRawJson(String str) => Build.fromJson(json.decode(str));
|
|
||||||
|
|
||||||
String toRawJson() => json.encode(toJson());
|
|
||||||
|
|
||||||
factory Build.fromJson(Map<String, dynamic> json) => Build(
|
|
||||||
min: AppUpdatePlatformSpecific.fromJson(json["min"]),
|
|
||||||
last: AppUpdatePlatformSpecific.fromJson(json["last"]),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
"min": min.toJson(),
|
|
||||||
"last": last.toJson(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppUpdatePlatformSpecific<T> {
|
|
||||||
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<String, dynamic> json) =>
|
|
||||||
AppUpdatePlatformSpecific(
|
|
||||||
mac: json["mac"],
|
|
||||||
ios: json["ios"],
|
|
||||||
android: json["android"],
|
|
||||||
windows: json["windows"],
|
|
||||||
linux: json["linux"],
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'dart:convert';
|
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';
|
import 'package:toolbox/data/model/container/type.dart';
|
||||||
|
|
||||||
abstract final class ContainerImg {
|
abstract final class ContainerImg {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/core/extension/numx.dart';
|
|
||||||
import 'package:toolbox/data/model/container/type.dart';
|
import 'package:toolbox/data/model/container/type.dart';
|
||||||
|
|
||||||
abstract final class ContainerPs {
|
abstract final class ContainerPs {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:toolbox/data/res/logger.dart';
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
/// raw dat from server:
|
/// raw dat from server:
|
||||||
/// ```text
|
/// ```text
|
||||||
@@ -92,7 +93,7 @@ abstract final class Batteries {
|
|||||||
if (onlyLiPoly && !bat.isLiPoly) continue;
|
if (onlyLiPoly && !bat.isLiPoly) continue;
|
||||||
batteries.add(bat);
|
batteries.add(bat);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
oneBatLines.clear();
|
oneBatLines.clear();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:toolbox/core/extension/listx.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:toolbox/core/extension/numx.dart';
|
|
||||||
import 'package:toolbox/data/model/server/time_seq.dart';
|
import 'package:toolbox/data/model/server/time_seq.dart';
|
||||||
|
|
||||||
import '../../res/misc.dart';
|
import '../../res/misc.dart';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:toolbox/core/extension/listx.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
class Memory {
|
class Memory {
|
||||||
final int total;
|
final int total;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:toolbox/core/extension/numx.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
import 'time_seq.dart';
|
import 'time_seq.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:toolbox/data/res/logger.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
import '../../../data/res/misc.dart';
|
import '../../../data/res/misc.dart';
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ class PsResult {
|
|||||||
procs.add(Proc.parse(line, map));
|
procs.add(Proc.parse(line, map));
|
||||||
} catch (e, trace) {
|
} catch (e, trace) {
|
||||||
errs.add('$line: $e');
|
errs.add('$line: $e');
|
||||||
Loggers.parse.warning('Process failed', e, trace);
|
Loggers.app.warning('Process failed', e, trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.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 {
|
enum PveResType {
|
||||||
lxc,
|
lxc,
|
||||||
@@ -132,7 +130,12 @@ final class PveLxc extends PveResIface implements PveCtrlIface {
|
|||||||
@override
|
@override
|
||||||
String get summary {
|
String get summary {
|
||||||
if (available) {
|
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;
|
return l10n.stopped;
|
||||||
}
|
}
|
||||||
@@ -210,7 +213,12 @@ final class PveQemu extends PveResIface implements PveCtrlIface {
|
|||||||
@override
|
@override
|
||||||
String get summary {
|
String get summary {
|
||||||
if (available) {
|
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;
|
return l10n.stopped;
|
||||||
}
|
}
|
||||||
@@ -260,7 +268,12 @@ final class PveNode extends PveResIface {
|
|||||||
|
|
||||||
String get topRight {
|
String get topRight {
|
||||||
if (isRunning) {
|
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;
|
return l10n.stopped;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/data/res/logger.dart';
|
|
||||||
|
|
||||||
final class SensorAdaptor {
|
final class SensorAdaptor {
|
||||||
final String raw;
|
final String raw;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:dartssh2/dartssh2.dart';
|
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/context/locale.dart';
|
||||||
import 'package:toolbox/core/extension/listx.dart';
|
|
||||||
import 'package:toolbox/data/model/app/error.dart';
|
import 'package:toolbox/data/model/app/error.dart';
|
||||||
import 'package:toolbox/data/model/app/shell_func.dart';
|
import 'package:toolbox/data/model/app/shell_func.dart';
|
||||||
import 'package:toolbox/data/model/server/battery.dart';
|
import 'package:toolbox/data/model/server/battery.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/battery.dart';
|
||||||
import 'package:toolbox/data/model/server/nvdia.dart';
|
import 'package:toolbox/data/model/server/nvdia.dart';
|
||||||
import 'package:toolbox/data/model/server/sensors.dart';
|
import 'package:toolbox/data/model/server/sensors.dart';
|
||||||
import 'package:toolbox/data/model/server/server.dart';
|
import 'package:toolbox/data/model/server/server.dart';
|
||||||
import 'package:toolbox/data/model/server/system.dart';
|
import 'package:toolbox/data/model/server/system.dart';
|
||||||
import 'package:toolbox/data/res/logger.dart';
|
|
||||||
|
|
||||||
import '../app/shell_func.dart';
|
import '../app/shell_func.dart';
|
||||||
import 'cpu.dart';
|
import 'cpu.dart';
|
||||||
@@ -45,7 +45,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
final net = NetSpeed.parse(StatusCmdType.net.find(segments), time);
|
final net = NetSpeed.parse(StatusCmdType.net.find(segments), time);
|
||||||
req.ss.netSpeed.update(net);
|
req.ss.netSpeed.update(net);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -56,7 +56,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.more[StatusCmdType.sys] = sys;
|
req.ss.more[StatusCmdType.sys] = sys;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -65,14 +65,14 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.more[StatusCmdType.host] = host;
|
req.ss.more[StatusCmdType.host] = host;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final cpus = SingleCpuCore.parse(StatusCmdType.cpu.find(segments));
|
final cpus = SingleCpuCore.parse(StatusCmdType.cpu.find(segments));
|
||||||
req.ss.cpu.update(cpus);
|
req.ss.cpu.update(cpus);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -81,7 +81,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
StatusCmdType.tempVal.find(segments),
|
StatusCmdType.tempVal.find(segments),
|
||||||
);
|
);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -90,20 +90,20 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.tcp = tcp;
|
req.ss.tcp = tcp;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.disk = Disk.parse(StatusCmdType.disk.find(segments));
|
req.ss.disk = Disk.parse(StatusCmdType.disk.find(segments));
|
||||||
req.ss.diskUsage = DiskUsage.parse(req.ss.disk);
|
req.ss.diskUsage = DiskUsage.parse(req.ss.disk);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.mem = Memory.parse(StatusCmdType.mem.find(segments));
|
req.ss.mem = Memory.parse(StatusCmdType.mem.find(segments));
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -112,26 +112,26 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.more[StatusCmdType.uptime] = uptime;
|
req.ss.more[StatusCmdType.uptime] = uptime;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.swap = Swap.parse(StatusCmdType.mem.find(segments));
|
req.ss.swap = Swap.parse(StatusCmdType.mem.find(segments));
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final diskio = DiskIO.parse(StatusCmdType.diskio.find(segments), time);
|
final diskio = DiskIO.parse(StatusCmdType.diskio.find(segments), time);
|
||||||
req.ss.diskIO.update(diskio);
|
req.ss.diskIO.update(diskio);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments));
|
req.ss.nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments));
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -144,7 +144,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.batteries.addAll(batteries);
|
req.ss.batteries.addAll(batteries);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -154,7 +154,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.sensors.addAll(sensors);
|
req.ss.sensors.addAll(sensors);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -164,7 +164,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.customCmds[key] = value;
|
req.ss.customCmds[key] = value;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return req.ss;
|
return req.ss;
|
||||||
@@ -179,25 +179,25 @@ Future<ServerStatus> _getBsdStatus(ServerStatusUpdateReq req) async {
|
|||||||
final net = NetSpeed.parseBsd(BSDStatusCmdType.net.find(segments), time);
|
final net = NetSpeed.parseBsd(BSDStatusCmdType.net.find(segments), time);
|
||||||
req.ss.netSpeed.update(net);
|
req.ss.netSpeed.update(net);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.more[StatusCmdType.sys] = BSDStatusCmdType.sys.find(segments);
|
req.ss.more[StatusCmdType.sys] = BSDStatusCmdType.sys.find(segments);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.cpu = parseBsdCpu(BSDStatusCmdType.cpu.find(segments));
|
req.ss.cpu = parseBsdCpu(BSDStatusCmdType.cpu.find(segments));
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// req.ss.mem = parseBsdMem(BSDStatusCmdType.mem.find(segments));
|
// req.ss.mem = parseBsdMem(BSDStatusCmdType.mem.find(segments));
|
||||||
// } catch (e, s) {
|
// } catch (e, s) {
|
||||||
// Loggers.parse.warning(e, s);
|
// Loggers.app.warning(e, s);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -206,13 +206,13 @@ Future<ServerStatus> _getBsdStatus(ServerStatusUpdateReq req) async {
|
|||||||
req.ss.more[StatusCmdType.uptime] = uptime;
|
req.ss.more[StatusCmdType.uptime] = uptime;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.disk = Disk.parse(BSDStatusCmdType.disk.find(segments));
|
req.ss.disk = Disk.parse(BSDStatusCmdType.disk.find(segments));
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Loggers.parse.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
return req.ss;
|
return req.ss;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:toolbox/core/utils/misc.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
class AbsolutePath {
|
class AbsolutePath {
|
||||||
String _path;
|
String _path;
|
||||||
@@ -24,7 +24,7 @@ class AbsolutePath {
|
|||||||
_path = newPath;
|
_path = newPath;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_path = pathJoin(_path, newPath);
|
_path = _path.joinPath(newPath, seperator: '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool undo() {
|
bool undo() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'dart:async';
|
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 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../../../core/utils/server.dart';
|
import '../../../core/utils/server.dart';
|
||||||
|
|||||||
@@ -2,17 +2,15 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/listx.dart';
|
|
||||||
import 'package:toolbox/core/extension/ssh_client.dart';
|
import 'package:toolbox/core/extension/ssh_client.dart';
|
||||||
import 'package:toolbox/data/model/app/shell_func.dart';
|
import 'package:toolbox/data/model/app/shell_func.dart';
|
||||||
import 'package:toolbox/data/model/container/image.dart';
|
import 'package:toolbox/data/model/container/image.dart';
|
||||||
import 'package:toolbox/data/model/container/ps.dart';
|
import 'package:toolbox/data/model/container/ps.dart';
|
||||||
import 'package:toolbox/data/model/app/error.dart';
|
import 'package:toolbox/data/model/app/error.dart';
|
||||||
import 'package:toolbox/data/model/container/type.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/data/res/store.dart';
|
||||||
import 'package:toolbox/core/extension/uint8list.dart';
|
|
||||||
|
|
||||||
final _dockerNotFound =
|
final _dockerNotFound =
|
||||||
RegExp(r"command not found|Unknown command|Command '\w+' not found");
|
RegExp(r"command not found|Unknown command|Command '\w+' not found");
|
||||||
@@ -105,7 +103,7 @@ class ContainerProvider extends ChangeNotifier {
|
|||||||
type: ContainerErrType.segmentsNotMatch,
|
type: ContainerErrType.segmentsNotMatch,
|
||||||
message: 'Container segments: ${segments.length}',
|
message: 'Container segments: ${segments.length}',
|
||||||
);
|
);
|
||||||
Loggers.parse.warning('Container segments: ${segments.length}\n$raw');
|
Loggers.app.warning('Container segments: ${segments.length}\n$raw');
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -119,7 +117,7 @@ class ContainerProvider extends ChangeNotifier {
|
|||||||
type: ContainerErrType.invalidVersion,
|
type: ContainerErrType.invalidVersion,
|
||||||
message: '$e',
|
message: '$e',
|
||||||
);
|
);
|
||||||
Loggers.parse.warning('Container version failed', e, trace);
|
Loggers.app.warning('Container version failed', e, trace);
|
||||||
} finally {
|
} finally {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@@ -135,7 +133,7 @@ class ContainerProvider extends ChangeNotifier {
|
|||||||
type: ContainerErrType.parsePs,
|
type: ContainerErrType.parsePs,
|
||||||
message: '$e',
|
message: '$e',
|
||||||
);
|
);
|
||||||
Loggers.parse.warning('Container ps failed', e, trace);
|
Loggers.app.warning('Container ps failed', e, trace);
|
||||||
} finally {
|
} finally {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@@ -151,7 +149,7 @@ class ContainerProvider extends ChangeNotifier {
|
|||||||
type: ContainerErrType.parseImages,
|
type: ContainerErrType.parseImages,
|
||||||
message: '$e',
|
message: '$e',
|
||||||
);
|
);
|
||||||
Loggers.parse.warning('Container images failed', e, trace);
|
Loggers.app.warning('Container images failed', e, trace);
|
||||||
} finally {
|
} finally {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@@ -177,7 +175,7 @@ class ContainerProvider extends ChangeNotifier {
|
|||||||
type: ContainerErrType.parseStats,
|
type: ContainerErrType.parseStats,
|
||||||
message: '$e',
|
message: '$e',
|
||||||
);
|
);
|
||||||
Loggers.parse.warning('Parse docker stats: $statsRaw', e, trace);
|
Loggers.app.warning('Parse docker stats: $statsRaw', e, trace);
|
||||||
} finally {
|
} finally {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:logging/logging.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';
|
import '../../data/res/misc.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import 'dart:io';
|
|||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dio/io.dart';
|
import 'package:dio/io.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.dart';
|
import 'package:toolbox/core/extension/context/locale.dart';
|
||||||
import 'package:toolbox/data/model/app/error.dart';
|
import 'package:toolbox/data/model/app/error.dart';
|
||||||
import 'package:toolbox/data/model/server/pve.dart';
|
import 'package:toolbox/data/model/server/pve.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.dart';
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
import 'package:toolbox/data/res/logger.dart';
|
|
||||||
|
|
||||||
typedef PveCtrlFunc = Future<bool> Function(String node, String id);
|
typedef PveCtrlFunc = Future<bool> Function(String node, String id);
|
||||||
|
|
||||||
|
|||||||
@@ -3,22 +3,17 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/ssh_client.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/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/error.dart';
|
||||||
import 'package:toolbox/data/model/app/shell_func.dart';
|
import 'package:toolbox/data/model/app/shell_func.dart';
|
||||||
import 'package:toolbox/data/model/server/system.dart';
|
import 'package:toolbox/data/model/server/system.dart';
|
||||||
import 'package:toolbox/data/model/sftp/req.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/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../../core/extension/order.dart';
|
|
||||||
import '../../core/extension/uint8list.dart';
|
|
||||||
import '../../core/utils/server.dart';
|
import '../../core/utils/server.dart';
|
||||||
import '../model/server/server.dart';
|
import '../model/server/server.dart';
|
||||||
import '../model/server/server_private_info.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);
|
Loggers.app.warning('Write script to ${spi.name} by shell', e);
|
||||||
|
|
||||||
/// by sftp
|
/// by sftp
|
||||||
final localPath = joinPath(await Paths.doc, 'install.sh');
|
final localPath = Paths.doc.joinPath('install.sh');
|
||||||
final file = File(localPath);
|
final file = File(localPath);
|
||||||
try {
|
try {
|
||||||
file.writeAsBytes(scriptRaw);
|
file.writeAsBytes(scriptRaw);
|
||||||
@@ -455,7 +450,7 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
message: 'Parse failed: $e\n\n$raw',
|
message: 'Parse failed: $e\n\n$raw',
|
||||||
);
|
);
|
||||||
_setServerState(s, ServerConn.failed);
|
_setServerState(s, ServerConn.failed);
|
||||||
Loggers.parse.warning('Server status', e, trace);
|
Loggers.app.warning('Server status', e, trace);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/data/model/server/snippet.dart';
|
import 'package:toolbox/data/model/server/snippet.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../../core/extension/order.dart';
|
|
||||||
|
|
||||||
class SnippetProvider extends ChangeNotifier {
|
class SnippetProvider extends ChangeNotifier {
|
||||||
late List<Snippet> _snippets;
|
late List<Snippet> _snippets;
|
||||||
List<Snippet> get snippets => _snippets;
|
List<Snippet> get snippets => _snippets;
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
class BuildData {
|
class BuildData {
|
||||||
static const String name = "ServerBox";
|
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 engine = "3.19.6";
|
||||||
static const String buildAt = "2024-05-10 20:57:55";
|
static const String buildAt = "2024-05-12 15:46:37";
|
||||||
static const int modifications = 8;
|
static const int modifications = 3;
|
||||||
static const int script = 47;
|
static const int script = 47;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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');
|
|
||||||
}
|
|
||||||
@@ -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<String> 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<String> 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<String> 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<String> get bak async => '${await doc}/$bakName';
|
|
||||||
|
|
||||||
static Future<String> get dl async => joinPath(await doc, 'dl');
|
|
||||||
}
|
|
||||||
@@ -4,15 +4,14 @@ import 'package:toolbox/data/provider/private_key.dart';
|
|||||||
import 'package:toolbox/data/provider/server.dart';
|
import 'package:toolbox/data/provider/server.dart';
|
||||||
import 'package:toolbox/data/provider/sftp.dart';
|
import 'package:toolbox/data/provider/sftp.dart';
|
||||||
import 'package:toolbox/data/provider/snippet.dart';
|
import 'package:toolbox/data/provider/snippet.dart';
|
||||||
import 'package:toolbox/locator.dart';
|
|
||||||
|
|
||||||
abstract final class Pros {
|
abstract final class Pros {
|
||||||
static final app = locator<AppProvider>();
|
static final app = AppProvider();
|
||||||
static final debug = locator<DebugProvider>();
|
static final debug = DebugProvider();
|
||||||
static final key = locator<PrivateKeyProvider>();
|
static final key = PrivateKeyProvider();
|
||||||
static final server = locator<ServerProvider>();
|
static final server = ServerProvider();
|
||||||
static final sftp = locator<SftpProvider>();
|
static final sftp = SftpProvider();
|
||||||
static final snippet = locator<SnippetProvider>();
|
static final snippet = SnippetProvider();
|
||||||
|
|
||||||
static void reload() {
|
static void reload() {
|
||||||
key.load();
|
key.load();
|
||||||
|
|||||||
@@ -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/container.dart';
|
||||||
import 'package:toolbox/data/store/history.dart';
|
import 'package:toolbox/data/store/history.dart';
|
||||||
import 'package:toolbox/data/store/private_key.dart';
|
import 'package:toolbox/data/store/private_key.dart';
|
||||||
import 'package:toolbox/data/store/server.dart';
|
import 'package:toolbox/data/store/server.dart';
|
||||||
import 'package:toolbox/data/store/setting.dart';
|
import 'package:toolbox/data/store/setting.dart';
|
||||||
import 'package:toolbox/data/store/snippet.dart';
|
import 'package:toolbox/data/store/snippet.dart';
|
||||||
import 'package:toolbox/locator.dart';
|
|
||||||
|
|
||||||
abstract final class Stores {
|
abstract final class Stores {
|
||||||
static final setting = locator<SettingStore>();
|
static final setting = SettingStore();
|
||||||
static final server = locator<ServerStore>();
|
static final server = ServerStore();
|
||||||
static final container = locator<ContainerStore>();
|
static final container = ContainerStore();
|
||||||
static final history = locator<HistoryStore>();
|
static final history = HistoryStore();
|
||||||
static final key = locator<PrivateKeyStore>();
|
static final key = PrivateKeyStore();
|
||||||
static final snippet = locator<SnippetStore>();
|
static final snippet = SnippetStore();
|
||||||
|
|
||||||
static final List<PersistentStore> all = [
|
static final List<PersistentStore> all = [
|
||||||
setting,
|
setting,
|
||||||
|
|||||||
@@ -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(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
abstract final class Urls {
|
abstract final class Urls {
|
||||||
static const cdnBase = 'https://cdn.lolli.tech/serverbox';
|
static const cdnBase = 'https://cdn.lolli.tech/serverbox';
|
||||||
|
static const updateCfg = '$cdnBase/update.json';
|
||||||
static const myGithub = 'https://github.com/lollipopkit';
|
static const myGithub = 'https://github.com/lollipopkit';
|
||||||
static const appHelp = '$myGithub/flutter_server_box#-help';
|
static const appHelp = '$myGithub/flutter_server_box#-help';
|
||||||
static const appWiki = '$myGithub/flutter_server_box/wiki';
|
static const appWiki = '$myGithub/flutter_server_box/wiki';
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import 'package:dio/dio.dart';
|
|
||||||
|
|
||||||
import '../model/app/update.dart';
|
|
||||||
import '../res/url.dart';
|
|
||||||
|
|
||||||
class AppService {
|
|
||||||
Future<AppUpdate> getUpdate() async {
|
|
||||||
final resp = await Dio().get('${Urls.cdnBase}/update.json');
|
|
||||||
return AppUpdate.fromJson(resp.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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/model/container/type.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../../core/persistant_store.dart';
|
|
||||||
|
|
||||||
const _keyConfig = 'providerConfig';
|
const _keyConfig = 'providerConfig';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:toolbox/core/persistant_store.dart';
|
|
||||||
|
|
||||||
/// index from 0 -> n : latest -> oldest
|
/// index from 0 -> n : latest -> oldest
|
||||||
class _ListHistory {
|
class _ListHistory {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import '../../core/persistant_store.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
import '../model/server/private_key_info.dart';
|
import '../model/server/private_key_info.dart';
|
||||||
|
|
||||||
class PrivateKeyStore extends PersistentStore {
|
class PrivateKeyStore extends PersistentStore {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import '../../core/persistant_store.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
import '../model/server/server_private_info.dart';
|
import '../model/server/server_private_info.dart';
|
||||||
|
|
||||||
class ServerStore extends PersistentStore {
|
class ServerStore extends PersistentStore {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:toolbox/core/persistant_store.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
|
||||||
import 'package:toolbox/data/model/app/menu/server_func.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/app/server_detail_card.dart';
|
||||||
import 'package:toolbox/data/model/ssh/virtual_key.dart';
|
import 'package:toolbox/data/model/ssh/virtual_key.dart';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import '../../core/persistant_store.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
import '../model/server/snippet.dart';
|
import '../model/server/snippet.dart';
|
||||||
|
|
||||||
class SnippetStore extends PersistentStore {
|
class SnippetStore extends PersistentStore {
|
||||||
|
|||||||
@@ -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<void> _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<void> setupLocator() async {
|
|
||||||
await _setupLocatorForStores();
|
|
||||||
_setupLocatorForProviders();
|
|
||||||
_setupLocatorForServices();
|
|
||||||
}
|
|
||||||
@@ -3,40 +3,30 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.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/sync/icloud.dart';
|
||||||
import 'package:toolbox/core/utils/platform/base.dart';
|
|
||||||
import 'package:toolbox/core/utils/sync/webdav.dart';
|
import 'package:toolbox/core/utils/sync/webdav.dart';
|
||||||
import 'package:toolbox/core/utils/ui.dart';
|
import 'package:toolbox/core/utils/ui.dart';
|
||||||
import 'package:toolbox/data/model/app/menu/server_func.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/app/version_related.dart';
|
||||||
import 'package:toolbox/data/model/server/custom.dart';
|
import 'package:toolbox/data/model/server/custom.dart';
|
||||||
import 'package:toolbox/data/res/build_data.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/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
import 'core/analysis.dart';
|
|
||||||
import 'data/model/app/net_view.dart';
|
import 'data/model/app/net_view.dart';
|
||||||
import 'data/model/server/private_key_info.dart';
|
import 'data/model/server/private_key_info.dart';
|
||||||
import 'data/model/server/server_private_info.dart';
|
import 'data/model/server/server_private_info.dart';
|
||||||
import 'data/model/server/snippet.dart';
|
import 'data/model/server/snippet.dart';
|
||||||
import 'data/model/ssh/virtual_key.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<void> main() async {
|
Future<void> main() async {
|
||||||
_runInZone(() async {
|
_runInZone(() async {
|
||||||
@@ -44,11 +34,11 @@ Future<void> main() async {
|
|||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider(create: (_) => locator<AppProvider>()),
|
ChangeNotifierProvider(create: (_) => Pros.app),
|
||||||
ChangeNotifierProvider(create: (_) => locator<ServerProvider>()),
|
ChangeNotifierProvider(create: (_) => Pros.server),
|
||||||
ChangeNotifierProvider(create: (_) => locator<SnippetProvider>()),
|
ChangeNotifierProvider(create: (_) => Pros.snippet),
|
||||||
ChangeNotifierProvider(create: (_) => locator<PrivateKeyProvider>()),
|
ChangeNotifierProvider(create: (_) => Pros.key),
|
||||||
ChangeNotifierProvider(create: (_) => locator<SftpProvider>()),
|
ChangeNotifierProvider(create: (_) => Pros.sftp),
|
||||||
],
|
],
|
||||||
child: const MyApp(),
|
child: const MyApp(),
|
||||||
),
|
),
|
||||||
@@ -76,30 +66,28 @@ void _runInZone(void Function() body) {
|
|||||||
Future<void> _initApp() async {
|
Future<void> _initApp() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
await Paths.init(BuildData.name);
|
||||||
|
|
||||||
// Base of all data.
|
// Base of all data.
|
||||||
await _initDb();
|
await _initDb();
|
||||||
await setupLocator();
|
|
||||||
await _initDesktopWindow();
|
_initDesktopWindow();
|
||||||
Computer.shared.turnOn(
|
|
||||||
// Plus 1 to avoid 0.
|
|
||||||
workersCount: (Stores.server.box.keys.length / 3).round() + 1,
|
|
||||||
);
|
|
||||||
_setupLogger();
|
_setupLogger();
|
||||||
_setupProviders();
|
|
||||||
|
|
||||||
// Load font
|
// Load font
|
||||||
loadFontFile(Stores.setting.fontPath.fetch());
|
loadFontFile(Stores.setting.fontPath.fetch());
|
||||||
|
|
||||||
if (isAndroid) {
|
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 is only used on Android for saving home widgets settings.
|
||||||
SharedPreferences.setPrefix('');
|
SharedPreferences.setPrefix('');
|
||||||
// try switch to highest refresh rate
|
// try switch to highest refresh rate
|
||||||
await FlutterDisplayMode.setHighRefreshRate();
|
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 (isIOS || isMacOS) {
|
||||||
if (Stores.setting.icloudSync.fetch()) ICloud.sync();
|
if (Stores.setting.icloudSync.fetch()) ICloud.sync();
|
||||||
}
|
}
|
||||||
@@ -108,11 +96,6 @@ Future<void> _initApp() async {
|
|||||||
_doVersionRelated();
|
_doVersionRelated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setupProviders() {
|
|
||||||
Pros.snippet.load();
|
|
||||||
Pros.key.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _initDb() async {
|
Future<void> _initDb() async {
|
||||||
// await SecureStore.init();
|
// await SecureStore.init();
|
||||||
await Hive.initFlutter();
|
await Hive.initFlutter();
|
||||||
@@ -124,6 +107,16 @@ Future<void> _initDb() async {
|
|||||||
Hive.registerAdapter(NetViewTypeAdapter()); // 5
|
Hive.registerAdapter(NetViewTypeAdapter()); // 5
|
||||||
Hive.registerAdapter(ServerFuncBtnAdapter()); // 6
|
Hive.registerAdapter(ServerFuncBtnAdapter()); // 6
|
||||||
Hive.registerAdapter(ServerCustomAdapter()); // 7
|
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() {
|
void _setupLogger() {
|
||||||
@@ -136,11 +129,11 @@ void _setupLogger() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initDesktopWindow() async {
|
void _initDesktopWindow() async {
|
||||||
if (!isDesktop) return;
|
if (!isDesktop) return;
|
||||||
|
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
await CustomAppBar.updateTitlebarHeight();
|
await CustomAppBar.updateTitlebarHeight(Stores.setting.hideTitleBar.fetch());
|
||||||
|
|
||||||
final windowOptions = WindowOptions(
|
final windowOptions = WindowOptions(
|
||||||
center: true,
|
center: true,
|
||||||
|
|||||||
@@ -2,31 +2,16 @@ import 'dart:convert';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.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/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/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/core/utils/sync/webdav.dart';
|
||||||
import 'package:toolbox/data/model/app/backup.dart';
|
import 'package:toolbox/data/model/app/backup.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.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/store.dart';
|
||||||
import 'package:toolbox/data/res/ui.dart';
|
|
||||||
import 'package:toolbox/data/res/url.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 {
|
class BackupPage extends StatelessWidget {
|
||||||
BackupPage({super.key});
|
BackupPage({super.key});
|
||||||
@@ -82,11 +67,12 @@ class BackupPage extends StatelessWidget {
|
|||||||
final path = await Backup.backup();
|
final path = await Backup.backup();
|
||||||
|
|
||||||
/// Issue #188
|
/// Issue #188
|
||||||
if (isWindows) {
|
final _ = switch (Pfs.type) {
|
||||||
await Shares.text(await File(path).readAsString());
|
Pfs.windows =>
|
||||||
} else {
|
await Process.run('explorer', ['/select,', path]),
|
||||||
await Shares.files([path]);
|
Pfs.linux => await Process.run('xdg-open', [path]),
|
||||||
}
|
_ => await Pfs.sharePath(path),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@@ -206,7 +192,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
trailing: const Icon(Icons.save),
|
trailing: const Icon(Icons.save),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final path = await Backup.backup();
|
final path = await Backup.backup();
|
||||||
Shares.copy(await File(path).readAsString());
|
Pfs.copy(await File(path).readAsString());
|
||||||
context.showSnackBar(l10n.success);
|
context.showSnackBar(l10n.success);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -232,25 +218,14 @@ class BackupPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
leading: const Icon(Icons.import_export),
|
leading: const Icon(Icons.import_export),
|
||||||
onTap: () => _onBulkImportServers(context),
|
onTap: () => _onBulkImportServers(context),
|
||||||
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onTapFileRestore(BuildContext context) async {
|
Future<void> _onTapFileRestore(BuildContext context) async {
|
||||||
final path = await pickOneFile();
|
final text = await Pfs.pickFileString();
|
||||||
if (path == null) return;
|
if (text == 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final backup = await context.showLoadingDialog(
|
final backup = await context.showLoadingDialog(
|
||||||
@@ -262,7 +237,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await context.showRoundDialog(
|
await context.showRoundDialog(
|
||||||
title: Text(l10n.restore),
|
title: l10n.restore,
|
||||||
child: Text(l10n.askContinue(
|
child: Text(l10n.askContinue(
|
||||||
'${l10n.restore} ${l10n.backup}(${backup.date})',
|
'${l10n.restore} ${l10n.backup}(${backup.date})',
|
||||||
)),
|
)),
|
||||||
@@ -296,7 +271,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final fileName = await context.showRoundDialog<String>(
|
final fileName = await context.showRoundDialog<String>(
|
||||||
title: Text(l10n.restore),
|
title: l10n.restore,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 300,
|
width: 300,
|
||||||
height: 300,
|
height: 300,
|
||||||
@@ -329,7 +304,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
webdavLoading.value = false;
|
webdavLoading.value = false;
|
||||||
return;
|
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);
|
final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile);
|
||||||
await dlBak.restore(force: true);
|
await dlBak.restore(force: true);
|
||||||
webdavLoading.value = false;
|
webdavLoading.value = false;
|
||||||
@@ -337,7 +312,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
|
|
||||||
Future<void> _onTapWebdavUp(BuildContext context) async {
|
Future<void> _onTapWebdavUp(BuildContext context) async {
|
||||||
webdavLoading.value = true;
|
webdavLoading.value = true;
|
||||||
final bakName = '${DateTime.now().numStr}-${Paths.bakName}';
|
final bakName = '${DateTime.now().ymdhms()}-${Paths.bakName}';
|
||||||
await Backup.backup(bakName);
|
await Backup.backup(bakName);
|
||||||
final uploadResult = await Webdav.upload(relativePath: bakName);
|
final uploadResult = await Webdav.upload(relativePath: bakName);
|
||||||
if (uploadResult != null) {
|
if (uploadResult != null) {
|
||||||
@@ -359,7 +334,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
text: Stores.setting.webdavPwd.fetch(),
|
text: Stores.setting.webdavPwd.fetch(),
|
||||||
);
|
);
|
||||||
final result = await context.showRoundDialog<bool>(
|
final result = await context.showRoundDialog<bool>(
|
||||||
title: const Text('WebDAV'),
|
title: 'WebDAV',
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -401,7 +376,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onTapClipboardRestore(BuildContext context) async {
|
void _onTapClipboardRestore(BuildContext context) async {
|
||||||
final text = await Shares.paste();
|
final text = await Pfs.paste();
|
||||||
if (text == null || text.isEmpty) {
|
if (text == null || text.isEmpty) {
|
||||||
context.showSnackBar(l10n.fieldMustNotEmpty);
|
context.showSnackBar(l10n.fieldMustNotEmpty);
|
||||||
return;
|
return;
|
||||||
@@ -418,7 +393,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await context.showRoundDialog(
|
await context.showRoundDialog(
|
||||||
title: Text(l10n.restore),
|
title: l10n.restore,
|
||||||
child: Text(l10n.askContinue(
|
child: Text(l10n.askContinue(
|
||||||
'${l10n.restore} ${l10n.backup}(${backup.date})',
|
'${l10n.restore} ${l10n.backup}(${backup.date})',
|
||||||
)),
|
)),
|
||||||
@@ -443,26 +418,8 @@ class BackupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onBulkImportServers(BuildContext context) async {
|
void _onBulkImportServers(BuildContext context) async {
|
||||||
final path = await pickOneFile();
|
final text = await Pfs.pickFileString();
|
||||||
if (path == null) return;
|
if (text == 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final spis = await context.showLoadingDialog(
|
final spis = await context.showLoadingDialog(
|
||||||
@@ -472,7 +429,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
}, text.trim()),
|
}, text.trim()),
|
||||||
);
|
);
|
||||||
final sure = await context.showRoundDialog<bool>(
|
final sure = await context.showRoundDialog<bool>(
|
||||||
title: Text(l10n.import),
|
title: l10n.import,
|
||||||
child: Text(l10n.askContinue('${spis.length} ${l10n.server}')),
|
child: Text(l10n.askContinue('${spis.length} ${l10n.server}')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -493,7 +450,7 @@ class BackupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text(e.toString()),
|
child: Text(e.toString()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,20 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.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/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/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/app/menu/container.dart';
|
||||||
import 'package:toolbox/data/model/container/image.dart';
|
import 'package:toolbox/data/model/container/image.dart';
|
||||||
import 'package:toolbox/data/model/container/type.dart';
|
import 'package:toolbox/data/model/container/type.dart';
|
||||||
import 'package:toolbox/data/res/store.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/container/ps.dart';
|
||||||
import '../../data/model/server/server_private_info.dart';
|
import '../../data/model/server/server_private_info.dart';
|
||||||
import '../../data/provider/container.dart';
|
import '../../data/provider/container.dart';
|
||||||
import '../../data/res/ui.dart';
|
|
||||||
import '../widget/appbar.dart';
|
|
||||||
import '../widget/popup_menu.dart';
|
import '../widget/popup_menu.dart';
|
||||||
import '../widget/cardx.dart';
|
|
||||||
import '../widget/two_line_text.dart';
|
import '../widget/two_line_text.dart';
|
||||||
|
|
||||||
class ContainerPage extends StatefulWidget {
|
class ContainerPage extends StatefulWidget {
|
||||||
@@ -267,7 +260,8 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
|
|
||||||
Widget _buildMoreBtn(ContainerPs dItem) {
|
Widget _buildMoreBtn(ContainerPs dItem) {
|
||||||
return PopupMenu(
|
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),
|
onSelected: (item) => _onTapMoreBtn(item, dItem),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -331,7 +325,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
final nameCtrl = TextEditingController();
|
final nameCtrl = TextEditingController();
|
||||||
final argsCtrl = TextEditingController();
|
final argsCtrl = TextEditingController();
|
||||||
await context.showRoundDialog(
|
await context.showRoundDialog(
|
||||||
title: Text(l10n.newContainer),
|
title: l10n.newContainer,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -380,7 +374,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
|
|
||||||
Future<void> _showAddCmdPreview(String cmd) async {
|
Future<void> _showAddCmdPreview(String cmd) async {
|
||||||
await context.showRoundDialog(
|
await context.showRoundDialog(
|
||||||
title: Text(l10n.preview),
|
title: l10n.preview,
|
||||||
child: Text(cmd),
|
child: Text(cmd),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -422,7 +416,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
final host = Stores.container.fetch(id);
|
final host = Stores.container.fetch(id);
|
||||||
final ctrl = TextEditingController(text: host);
|
final ctrl = TextEditingController(text: host);
|
||||||
await context.showRoundDialog(
|
await context.showRoundDialog(
|
||||||
title: Text(l10n.dockerEditHost),
|
title: l10n.dockerEditHost,
|
||||||
child: Input(
|
child: Input(
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
controller: ctrl,
|
controller: ctrl,
|
||||||
@@ -446,7 +440,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
|
|
||||||
void _showImageRmDialog(ContainerImg e) {
|
void _showImageRmDialog(ContainerImg e) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.askContinue('${l10n.delete} Image(${e.repository})')),
|
child: Text(l10n.askContinue('${l10n.delete} Image(${e.repository})')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -477,7 +471,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
case ContainerMenu.rm:
|
case ContainerMenu.rm:
|
||||||
var force = false;
|
var force = false;
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -510,7 +504,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text(result.message ?? l10n.unknownError),
|
child: Text(result.message ?? l10n.unknownError),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -526,7 +520,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text(result.message ?? l10n.unknownError),
|
child: Text(result.message ?? l10n.unknownError),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -537,7 +531,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text(result.message ?? l10n.unknownError),
|
child: Text(result.message ?? l10n.unknownError),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -548,19 +542,19 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text(result.message ?? l10n.unknownError),
|
child: Text(result.message ?? l10n.unknownError),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ContainerMenu.logs:
|
case ContainerMenu.logs:
|
||||||
AppRoute.ssh(
|
AppRoutes.ssh(
|
||||||
spi: widget.spi,
|
spi: widget.spi,
|
||||||
initCmd: 'docker logs -f --tail 100 ${dItem.id}',
|
initCmd: 'docker logs -f --tail 100 ${dItem.id}',
|
||||||
).go(context);
|
).go(context);
|
||||||
break;
|
break;
|
||||||
case ContainerMenu.terminal:
|
case ContainerMenu.terminal:
|
||||||
AppRoute.ssh(
|
AppRoutes.ssh(
|
||||||
spi: widget.spi,
|
spi: widget.spi,
|
||||||
initCmd: 'docker exec -it ${dItem.id} sh',
|
initCmd: 'docker exec -it ${dItem.id} sh',
|
||||||
).go(context);
|
).go(context);
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.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/provider/debug.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
|
|
||||||
import '../widget/appbar.dart';
|
|
||||||
|
|
||||||
class DebugPage extends StatelessWidget {
|
class DebugPage extends StatelessWidget {
|
||||||
const DebugPage({super.key});
|
const DebugPage({super.key});
|
||||||
|
|||||||
@@ -3,18 +3,16 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:code_text_field/code_text_field.dart';
|
import 'package:code_text_field/code_text_field.dart';
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_highlight/theme_map.dart';
|
import 'package:flutter_highlight/theme_map.dart';
|
||||||
import 'package:flutter_highlight/themes/a11y-light.dart';
|
import 'package:flutter_highlight/themes/a11y-light.dart';
|
||||||
import 'package:flutter_highlight/themes/monokai.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/extension/context/locale.dart';
|
||||||
import 'package:toolbox/core/utils/misc.dart';
|
import 'package:toolbox/core/utils/misc.dart';
|
||||||
import 'package:toolbox/data/res/highlight.dart';
|
import 'package:toolbox/data/res/highlight.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../widget/appbar.dart';
|
|
||||||
import '../widget/two_line_text.dart';
|
import '../widget/two_line_text.dart';
|
||||||
|
|
||||||
class EditorPage extends StatefulWidget {
|
class EditorPage extends StatefulWidget {
|
||||||
|
|||||||
@@ -1,38 +1,24 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:after_layout/after_layout.dart';
|
import 'package:after_layout/after_layout.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.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:icons_plus/icons_plus.dart';
|
||||||
import 'package:permission_handler/permission_handler.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/channel/home_widget.dart';
|
||||||
import 'package:toolbox/core/extension/build.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/extension/context/locale.dart';
|
||||||
import 'package:toolbox/core/persistant_store.dart';
|
|
||||||
import 'package:toolbox/core/route.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/core/utils/ui.dart';
|
||||||
import 'package:toolbox/data/model/app/github_id.dart';
|
import 'package:toolbox/data/model/app/github_id.dart';
|
||||||
import 'package:toolbox/data/model/app/tab.dart';
|
import 'package:toolbox/data/model/app/tab.dart';
|
||||||
import 'package:toolbox/data/res/build_data.dart';
|
import 'package:toolbox/data/res/build_data.dart';
|
||||||
import 'package:toolbox/data/res/github_id.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/misc.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.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/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';
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
|
|
||||||
part 'appbar.dart';
|
part 'appbar.dart';
|
||||||
@@ -100,7 +86,9 @@ class _HomePageState extends State<HomePage>
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
if (_shouldAuth) {
|
if (_shouldAuth) {
|
||||||
BioAuth.go().then((_) => _shouldAuth = false);
|
if (Stores.setting.useBioAuth.fetch()) {
|
||||||
|
BioAuth.go().then((_) => _shouldAuth = false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!Pros.server.isAutoRefreshOn) {
|
if (!Pros.server.isAutoRefreshOn) {
|
||||||
Pros.server.startAutoRefresh();
|
Pros.server.startAutoRefresh();
|
||||||
@@ -112,9 +100,9 @@ class _HomePageState extends State<HomePage>
|
|||||||
// Keep running in background on Android device
|
// Keep running in background on Android device
|
||||||
if (isAndroid && Stores.setting.bgRun.fetch()) {
|
if (isAndroid && Stores.setting.bgRun.fetch()) {
|
||||||
// Keep this if statement single
|
// Keep this if statement single
|
||||||
if (Pros.app.moveBg) {
|
// if (Pros.app.moveBg) {
|
||||||
BgRunMC.moveToBg();
|
// BgRunMC.moveToBg();
|
||||||
}
|
// }
|
||||||
} else {
|
} else {
|
||||||
//Pros.server.setDisconnected();
|
//Pros.server.setDisconnected();
|
||||||
Pros.server.stopAutoRefresh();
|
Pros.server.stopAutoRefresh();
|
||||||
@@ -152,7 +140,7 @@ class _HomePageState extends State<HomePage>
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.developer_mode, size: 21),
|
icon: const Icon(Icons.developer_mode, size: 21),
|
||||||
tooltip: l10n.debug,
|
tooltip: l10n.debug,
|
||||||
onPressed: () => AppRoute.debug().go(context),
|
onPressed: () => AppRoutes.debug().go(context),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -239,7 +227,7 @@ class _HomePageState extends State<HomePage>
|
|||||||
_buildIcon(),
|
_buildIcon(),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => context.showRoundDialog(
|
onPressed: () => context.showRoundDialog(
|
||||||
title: const Text(BuildDataX.versionStr),
|
title: BuildDataX.versionStr,
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'${BuildData.buildAt}\nFlutter ${BuildData.engine}'),
|
'${BuildData.buildAt}\nFlutter ${BuildData.engine}'),
|
||||||
),
|
),
|
||||||
@@ -264,23 +252,23 @@ class _HomePageState extends State<HomePage>
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.settings),
|
leading: const Icon(Icons.settings),
|
||||||
title: Text(l10n.setting),
|
title: Text(l10n.setting),
|
||||||
onTap: () => AppRoute.settings().go(context),
|
onTap: () => AppRoutes.settings().go(context),
|
||||||
onLongPress: _onLongPressSetting,
|
onLongPress: _onLongPressSetting,
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.vpn_key),
|
leading: const Icon(Icons.vpn_key),
|
||||||
title: Text(l10n.privateKey),
|
title: Text(l10n.privateKey),
|
||||||
onTap: () => AppRoute.keyList().go(context),
|
onTap: () => AppRoutes.keyList().go(context),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(BoxIcons.bxs_file_blank),
|
leading: const Icon(BoxIcons.bxs_file_blank),
|
||||||
title: Text(l10n.files),
|
title: Text(l10n.files),
|
||||||
onTap: () => AppRoute.localStorage().go(context),
|
onTap: () => AppRoutes.localStorage().go(context),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(MingCute.file_import_fill),
|
leading: const Icon(MingCute.file_import_fill),
|
||||||
title: Text(l10n.backup),
|
title: Text(l10n.backup),
|
||||||
onTap: () => AppRoute.backup().go(context),
|
onTap: () => AppRoutes.backup().go(context),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(OctIcons.feed_discussion),
|
leading: const Icon(OctIcons.feed_discussion),
|
||||||
@@ -294,7 +282,7 @@ class _HomePageState extends State<HomePage>
|
|||||||
|
|
||||||
void _showAboutDialog() {
|
void _showAboutDialog() {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.about),
|
title: l10n.about,
|
||||||
child: _buildAboutContent(),
|
child: _buildAboutContent(),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -348,15 +336,19 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')}
|
|||||||
@override
|
@override
|
||||||
Future<void> afterFirstLayout(BuildContext context) async {
|
Future<void> afterFirstLayout(BuildContext context) async {
|
||||||
// Auth required for first launch
|
// Auth required for first launch
|
||||||
BioAuth.go();
|
if (Stores.setting.useBioAuth.fetch()) BioAuth.go();
|
||||||
|
|
||||||
_reqNotiPerm();
|
_reqNotiPerm();
|
||||||
|
|
||||||
if (Stores.setting.autoCheckAppUpdate.fetch()) {
|
if (Stores.setting.autoCheckAppUpdate.fetch()) {
|
||||||
doUpdate(context);
|
AppUpdateIface.doUpdate(
|
||||||
|
build: BuildData.build,
|
||||||
|
url: '${Urls.cdnBase}/update.json',
|
||||||
|
context: context,
|
||||||
|
updateL10n: l10n.update,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
HomeWidgetMC.update();
|
HomeWidgetMC.update();
|
||||||
await GetIt.I.allReady();
|
|
||||||
await Pros.server.load();
|
await Pros.server.load();
|
||||||
await Pros.server.refresh();
|
await Pros.server.refresh();
|
||||||
}
|
}
|
||||||
@@ -369,7 +361,7 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')}
|
|||||||
final noNotiPerm = Stores.setting.noNotiPerm;
|
final noNotiPerm = Stores.setting.noNotiPerm;
|
||||||
if (noNotiPerm.fetch()) return;
|
if (noNotiPerm.fetch()) return;
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text(l10n.noNotiPerm),
|
child: Text(l10n.noNotiPerm),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -390,7 +382,7 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')}
|
|||||||
|
|
||||||
/// Encode [map] to String with indent `\t`
|
/// Encode [map] to String with indent `\t`
|
||||||
final text = Miscs.jsonEncoder.convert(map);
|
final text = Miscs.jsonEncoder.convert(map);
|
||||||
final result = await AppRoute.editor(
|
final result = await AppRoutes.editor(
|
||||||
text: text,
|
text: text,
|
||||||
langCode: 'json',
|
langCode: 'json',
|
||||||
title: l10n.setting,
|
title: l10n.setting,
|
||||||
@@ -408,7 +400,7 @@ ${GithubIds.participants.map((e) => '[$e](${e.url})').join(' ')}
|
|||||||
}
|
}
|
||||||
} catch (e, trace) {
|
} catch (e, trace) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text('${l10n.save}:\n$e'),
|
child: Text('${l10n.save}:\n$e'),
|
||||||
);
|
);
|
||||||
Loggers.app.warning('Update json settings failed', e, trace);
|
Loggers.app.warning('Update json settings failed', e, trace);
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.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/route.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.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 {
|
class IPerfPage extends StatefulWidget {
|
||||||
final ServerPrivateInfo spi;
|
final ServerPrivateInfo spi;
|
||||||
@@ -38,7 +36,7 @@ class _IPerfPageState extends State<IPerfPage> {
|
|||||||
context.showSnackBar(l10n.fieldMustNotEmpty);
|
context.showSnackBar(l10n.fieldMustNotEmpty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AppRoute.ssh(
|
AppRoutes.ssh(
|
||||||
spi: widget.spi,
|
spi: widget.spi,
|
||||||
initCmd: 'iperf -c ${_hostCtrl.text} -p ${_portCtrl.text}',
|
initCmd: 'iperf -c ${_hostCtrl.text} -p ${_portCtrl.text}',
|
||||||
).go(context);
|
).go(context);
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.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/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 'package:toolbox/data/res/provider.dart';
|
||||||
|
|
||||||
import '../../data/model/server/ping_result.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
|
/// Only permit ipv4 / ipv6 / domain chars
|
||||||
final targetReg = RegExp(r'[a-zA-Z0-9\.-_:]+');
|
final targetReg = RegExp(r'[a-zA-Z0-9\.-_:]+');
|
||||||
@@ -61,7 +53,7 @@ class _PingPageState extends State<PingPage>
|
|||||||
heroTag: 'ping',
|
heroTag: 'ping',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.choose),
|
title: l10n.choose,
|
||||||
child: Input(
|
child: Input(
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
controller: _textEditingController,
|
controller: _textEditingController,
|
||||||
@@ -84,11 +76,11 @@ class _PingPageState extends State<PingPage>
|
|||||||
await doPing();
|
await doPing();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text(e.toString()),
|
child: Text(e.toString()),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Shares.copy(e.toString()),
|
onPressed: () => Pfs.copy(e.toString()),
|
||||||
child: Text(l10n.copy),
|
child: Text(l10n.copy),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -125,7 +117,7 @@ class _PingPageState extends State<PingPage>
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: primaryColor,
|
color: UIs.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
@@ -136,7 +128,7 @@ class _PingPageState extends State<PingPage>
|
|||||||
'${l10n.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? l10n.unknown} $ms',
|
'${l10n.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? l10n.unknown} $ms',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: primaryColor,
|
color: UIs.primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,23 +1,15 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.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/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/misc.dart';
|
||||||
import 'package:toolbox/data/res/provider.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 '../../../core/utils/server.dart';
|
||||||
import '../../../data/model/server/private_key_info.dart';
|
import '../../../data/model/server/private_key_info.dart';
|
||||||
import '../../../data/res/ui.dart';
|
|
||||||
import '../../widget/appbar.dart';
|
|
||||||
|
|
||||||
const _format = 'text/plain';
|
const _format = 'text/plain';
|
||||||
|
|
||||||
@@ -91,7 +83,7 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
|
|||||||
tooltip: l10n.delete,
|
tooltip: l10n.delete,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.askContinue(
|
child: Text(l10n.askContinue(
|
||||||
'${l10n.delete} ${l10n.privateKey}(${widget.pki!.id})',
|
'${l10n.delete} ${l10n.privateKey}(${widget.pki!.id})',
|
||||||
)),
|
)),
|
||||||
@@ -181,7 +173,7 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final path = await pickOneFile();
|
final path = await Pfs.pickFilePath();
|
||||||
if (path == null) return;
|
if (path == null) return;
|
||||||
|
|
||||||
final file = File(path);
|
final file = File(path);
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:after_layout/after_layout.dart';
|
import 'package:after_layout/after_layout.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.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/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 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../../../core/route.dart';
|
import '../../../core/route.dart';
|
||||||
import '../../../data/model/server/private_key_info.dart';
|
import '../../../data/model/server/private_key_info.dart';
|
||||||
import '../../../data/provider/private_key.dart';
|
import '../../../data/provider/private_key.dart';
|
||||||
import '../../../data/res/ui.dart';
|
|
||||||
import '../../widget/appbar.dart';
|
|
||||||
import '../../widget/cardx.dart';
|
|
||||||
|
|
||||||
class PrivateKeysListPage extends StatefulWidget {
|
class PrivateKeysListPage extends StatefulWidget {
|
||||||
const PrivateKeysListPage({super.key});
|
const PrivateKeysListPage({super.key});
|
||||||
@@ -35,7 +29,7 @@ class _PrivateKeyListState extends State<PrivateKeysListPage>
|
|||||||
body: _buildBody(),
|
body: _buildBody(),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
child: const Icon(Icons.add),
|
child: const Icon(Icons.add),
|
||||||
onPressed: () => AppRoute.keyEdit().go(context),
|
onPressed: () => AppRoutes.keyEdit().go(context),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -64,7 +58,7 @@ class _PrivateKeyListState extends State<PrivateKeysListPage>
|
|||||||
),
|
),
|
||||||
title: Text(item.id),
|
title: Text(item.id),
|
||||||
subtitle: Text(item.type ?? l10n.unknown, style: UIs.textGrey),
|
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),
|
trailing: const Icon(Icons.edit),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -77,22 +71,22 @@ class _PrivateKeyListState extends State<PrivateKeysListPage>
|
|||||||
void autoAddSystemPriavteKey() {
|
void autoAddSystemPriavteKey() {
|
||||||
// Only trigger on desktop platform and no private key saved
|
// Only trigger on desktop platform and no private key saved
|
||||||
if (isDesktop && Stores.snippet.box.keys.isEmpty) {
|
if (isDesktop && Stores.snippet.box.keys.isEmpty) {
|
||||||
final home = getHomeDir();
|
final home = Pfs.homeDir;
|
||||||
if (home == null) return;
|
if (home == null) return;
|
||||||
final idRsaFile = File(joinPath(home, '.ssh/id_rsa'));
|
final idRsaFile = File(home.joinPath('.ssh/id_rsa'));
|
||||||
if (!idRsaFile.existsSync()) return;
|
if (!idRsaFile.existsSync()) return;
|
||||||
final sysPk = PrivateKeyInfo(
|
final sysPk = PrivateKeyInfo(
|
||||||
id: 'system',
|
id: 'system',
|
||||||
key: idRsaFile.readAsStringSync(),
|
key: idRsaFile.readAsStringSync(),
|
||||||
);
|
);
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.addSystemPrivateKeyTip),
|
child: Text(l10n.addSystemPrivateKeyTip),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pop();
|
context.pop();
|
||||||
AppRoute.keyEdit(pki: sysPk).go(context);
|
AppRoutes.keyEdit(pki: sysPk).go(context);
|
||||||
},
|
},
|
||||||
child: Text(l10n.ok),
|
child: Text(l10n.ok),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.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/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 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../../data/model/app/shell_func.dart';
|
import '../../data/model/app/shell_func.dart';
|
||||||
import '../../data/model/server/proc.dart';
|
import '../../data/model/server/proc.dart';
|
||||||
import '../../data/model/server/server_private_info.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';
|
import '../widget/two_line_text.dart';
|
||||||
|
|
||||||
class ProcessPage extends StatefulWidget {
|
class ProcessPage extends StatefulWidget {
|
||||||
@@ -107,11 +100,11 @@ class _ProcessPageState extends State<ProcessPage> {
|
|||||||
actions.add(IconButton(
|
actions.add(IconButton(
|
||||||
icon: const Icon(Icons.error),
|
icon: const Icon(Icons.error),
|
||||||
onPressed: () => context.showRoundDialog(
|
onPressed: () => context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: SingleChildScrollView(child: Text(_result.error!)),
|
child: SingleChildScrollView(child: Text(_result.error!)),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Shares.copy(_result.error!),
|
onPressed: () => Pfs.copy(_result.error!),
|
||||||
child: Text(l10n.copy),
|
child: Text(l10n.copy),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -160,7 +153,7 @@ class _ProcessPageState extends State<ProcessPage> {
|
|||||||
onTap: () => _lastFocusId = proc.pid,
|
onTap: () => _lastFocusId = proc.pid,
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.askContinue(
|
child: Text(l10n.askContinue(
|
||||||
'${l10n.stop} ${l10n.process}(${proc.pid})',
|
'${l10n.stop} ${l10n.process}(${proc.pid})',
|
||||||
)),
|
)),
|
||||||
|
|||||||
@@ -1,25 +1,14 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.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/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/pve.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.dart';
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
import 'package:toolbox/data/provider/pve.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/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/percent_circle.dart';
|
||||||
import 'package:toolbox/view/widget/row.dart';
|
|
||||||
import 'package:toolbox/view/widget/two_line_text.dart';
|
import 'package:toolbox/view/widget/two_line_text.dart';
|
||||||
import 'package:toolbox/view/widget/val_builder.dart';
|
|
||||||
|
|
||||||
final class PvePage extends StatefulWidget {
|
final class PvePage extends StatefulWidget {
|
||||||
final ServerPrivateInfo spi;
|
final ServerPrivateInfo spi;
|
||||||
@@ -156,7 +145,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildNode(PveNode item) {
|
Widget _buildNode(PveNode item) {
|
||||||
final valueAnim = AlwaysStoppedAnimation(primaryColor);
|
final valueAnim = AlwaysStoppedAnimation(UIs.primaryColor);
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 13, horizontal: 13),
|
padding: const EdgeInsets.symmetric(vertical: 13, horizontal: 13),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -216,7 +205,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
).card;
|
).cardx;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildQemu(PveQemu item) {
|
Widget _buildQemu(PveQemu item) {
|
||||||
@@ -224,7 +213,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(_wrapNodeName(item), style: UIs.text13Bold),
|
title: Text(_wrapNodeName(item), style: UIs.text13Bold),
|
||||||
trailing: _buildCtrlBtns(item),
|
trailing: _buildCtrlBtns(item),
|
||||||
).card;
|
).cardx;
|
||||||
}
|
}
|
||||||
final children = <Widget>[
|
final children = <Widget>[
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
@@ -293,7 +282,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: children,
|
children: children,
|
||||||
).card;
|
).cardx;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLxc(PveLxc item) {
|
Widget _buildLxc(PveLxc item) {
|
||||||
@@ -301,7 +290,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(_wrapNodeName(item), style: UIs.text13Bold),
|
title: Text(_wrapNodeName(item), style: UIs.text13Bold),
|
||||||
trailing: _buildCtrlBtns(item),
|
trailing: _buildCtrlBtns(item),
|
||||||
).card;
|
).cardx;
|
||||||
}
|
}
|
||||||
final children = <Widget>[
|
final children = <Widget>[
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
@@ -370,7 +359,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: children,
|
children: children,
|
||||||
).card;
|
).cardx;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStorage(PveStorage item) {
|
Widget _buildStorage(PveStorage item) {
|
||||||
@@ -392,14 +381,14 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
KvRow(k: l10n.plugInType, v: item.plugintype),
|
KvRow(k: l10n.plugInType, v: item.plugintype),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
).card;
|
).cardx;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSdn(PveSdn item) {
|
Widget _buildSdn(PveSdn item) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(_wrapNodeName(item)),
|
title: Text(_wrapNodeName(item)),
|
||||||
trailing: Text(item.summary),
|
trailing: Text(item.summary),
|
||||||
).card;
|
).cardx;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCtrlBtns(PveCtrlIface item) {
|
Widget _buildCtrlBtns(PveCtrlIface item) {
|
||||||
@@ -430,7 +419,7 @@ final class _PvePageState extends State<PvePage> {
|
|||||||
|
|
||||||
void _onCtrl(PveCtrlFunc func, String action, PveCtrlIface item) async {
|
void _onCtrl(PveCtrlFunc func, String action, PveCtrlIface item) async {
|
||||||
final sure = await context.showRoundDialog<bool>(
|
final sure = await context.showRoundDialog<bool>(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.askContinue('$action ${item.id}')),
|
child: Text(l10n.askContinue('$action ${item.id}')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ Widget _buildLineChart(
|
|||||||
isCurved: curve,
|
isCurved: curve,
|
||||||
barWidth: 2,
|
barWidth: 2,
|
||||||
isStrokeCapRound: true,
|
isStrokeCapRound: true,
|
||||||
color: primaryColor,
|
color: UIs.primaryColor,
|
||||||
dotData: const FlDotData(show: false),
|
dotData: const FlDotData(show: false),
|
||||||
belowBarData: BarAreaData(show: false),
|
belowBarData: BarAreaData(show: false),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import 'package:extended_image/extended_image.dart';
|
import 'package:extended_image/extended_image.dart';
|
||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:provider/provider.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/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/server_detail_card.dart';
|
||||||
import 'package:toolbox/data/model/app/shell_func.dart';
|
import 'package:toolbox/data/model/app/shell_func.dart';
|
||||||
import 'package:toolbox/data/model/server/battery.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/server_private_info.dart';
|
||||||
import 'package:toolbox/data/model/server/system.dart';
|
import 'package:toolbox/data/model/server/system.dart';
|
||||||
import 'package:toolbox/data/res/store.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/server_func_btns.dart';
|
||||||
import 'package:toolbox/view/widget/val_builder.dart';
|
|
||||||
|
|
||||||
import '../../../../core/extension/numx.dart';
|
|
||||||
import '../../../../core/route.dart';
|
import '../../../../core/route.dart';
|
||||||
import '../../../../data/model/server/server.dart';
|
import '../../../../data/model/server/server.dart';
|
||||||
import '../../../../data/provider/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';
|
part 'misc.dart';
|
||||||
|
|
||||||
@@ -139,7 +127,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.edit),
|
icon: const Icon(Icons.edit),
|
||||||
onPressed: () async {
|
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) {
|
if (delete == true) {
|
||||||
context.pop();
|
context.pop();
|
||||||
}
|
}
|
||||||
@@ -322,8 +310,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
return LinearProgressIndicator(
|
return LinearProgressIndicator(
|
||||||
value: percentWithinOne,
|
value: percentWithinOne,
|
||||||
minHeight: 7,
|
minHeight: 7,
|
||||||
backgroundColor: DynamicColors.progress.resolve(context),
|
backgroundColor: UIs.halfAlpha,
|
||||||
color: primaryColor,
|
color: UIs.primaryColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,7 +440,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
return processes.length * 47.0;
|
return processes.length * 47.0;
|
||||||
}();
|
}();
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(item.name),
|
title: item.name,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
height: height,
|
height: height,
|
||||||
@@ -494,10 +482,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
trailing: InkWell(
|
trailing: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: SizedBox(
|
title: '${process.pid}',
|
||||||
width: 377,
|
titleMaxLines: 1,
|
||||||
child: Text('${process.pid}', maxLines: 1),
|
|
||||||
),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -573,8 +559,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
value: disk.usedPercent / 100,
|
value: disk.usedPercent / 100,
|
||||||
strokeWidth: 5,
|
strokeWidth: 5,
|
||||||
backgroundColor: DynamicColors.progress.resolve(context),
|
backgroundColor: UIs.halfAlpha,
|
||||||
color: primaryColor,
|
color: UIs.primaryColor,
|
||||||
),
|
),
|
||||||
Text('${disk.usedPercent}%', style: UIs.text12Grey)
|
Text('${disk.usedPercent}%', style: UIs.text12Grey)
|
||||||
],
|
],
|
||||||
@@ -770,7 +756,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(si.device),
|
title: si.device,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: SimpleMarkdown(
|
child: SimpleMarkdown(
|
||||||
data: si.toMarkdown,
|
data: si.toMarkdown,
|
||||||
@@ -819,7 +805,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
subtitle: Text(addr, style: UIs.textGrey),
|
subtitle: Text(addr, style: UIs.textGrey),
|
||||||
leading: const Icon(FontAwesome.server_solid, size: 17),
|
leading: const Icon(FontAwesome.server_solid, size: 17),
|
||||||
trailing: const Icon(Icons.chevron_right),
|
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<ServerDetailPage>
|
|||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(cmd.key),
|
title: cmd.key,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Text(cmd.value, style: UIs.text13Grey),
|
child: Text(cmd.value, style: UIs.text13Grey),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,29 +1,19 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:provider/provider.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/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/core/utils/ui.dart';
|
||||||
import 'package:toolbox/data/model/app/shell_func.dart';
|
import 'package:toolbox/data/model/app/shell_func.dart';
|
||||||
import 'package:toolbox/data/model/server/custom.dart';
|
import 'package:toolbox/data/model/server/custom.dart';
|
||||||
import 'package:toolbox/data/model/server/wol_cfg.dart';
|
import 'package:toolbox/data/model/server/wol_cfg.dart';
|
||||||
import 'package:toolbox/data/res/provider.dart';
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
import 'package:toolbox/view/widget/expand_tile.dart';
|
|
||||||
|
|
||||||
import '../../../core/route.dart';
|
import '../../../core/route.dart';
|
||||||
import '../../../data/model/server/server_private_info.dart';
|
import '../../../data/model/server/server_private_info.dart';
|
||||||
import '../../../data/provider/private_key.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 {
|
class ServerEditPage extends StatefulWidget {
|
||||||
const ServerEditPage({super.key, this.spi});
|
const ServerEditPage({super.key, this.spi});
|
||||||
@@ -163,7 +153,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
var delScripts = false;
|
var delScripts = false;
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: StatefulBuilder(builder: (ctx, setState) {
|
child: StatefulBuilder(builder: (ctx, setState) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -224,7 +214,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
icon: BoxIcons.bx_rename,
|
icon: BoxIcons.bx_rename,
|
||||||
obscureText: false,
|
obscureText: false,
|
||||||
autoCorrect: true,
|
autoCorrect: true,
|
||||||
suggestiion: true,
|
suggestion: true,
|
||||||
),
|
),
|
||||||
Input(
|
Input(
|
||||||
controller: _ipController,
|
controller: _ipController,
|
||||||
@@ -266,6 +256,9 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
onChanged: (p0) => _tags = p0,
|
onChanged: (p0) => _tags = p0,
|
||||||
allTags: [...Pros.server.tags.value],
|
allTags: [...Pros.server.tags.value],
|
||||||
onRenameTag: Pros.server.renameTag,
|
onRenameTag: Pros.server.renameTag,
|
||||||
|
renameL10n: l10n.rename,
|
||||||
|
tagL10n: l10n.tag,
|
||||||
|
addL10n: l10n.add,
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(l10n.autoConnect),
|
title: Text(l10n.autoConnect),
|
||||||
@@ -367,7 +360,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
padding: EdgeInsets.only(right: 13),
|
padding: EdgeInsets.only(right: 13),
|
||||||
child: Icon(Icons.add),
|
child: Icon(Icons.add),
|
||||||
),
|
),
|
||||||
onTap: () => AppRoute.keyEdit().go(context),
|
onTap: () => AppRoutes.keyEdit().go(context),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return CardX(
|
return CardX(
|
||||||
@@ -440,7 +433,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).card,
|
).cardx,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +457,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
title: Text(l10n.doc),
|
title: Text(l10n.doc),
|
||||||
trailing: const Icon(Icons.open_in_new, size: 17),
|
trailing: const Icon(Icons.open_in_new, size: 17),
|
||||||
onTap: () => openUrl(l10n.customCmdDocUrl),
|
onTap: () => openUrl(l10n.customCmdDocUrl),
|
||||||
).card,
|
).cardx,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,7 +472,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
),
|
),
|
||||||
title: Text(l10n.about),
|
title: Text(l10n.about),
|
||||||
subtitle: Text(l10n.wolTip, style: UIs.text12Grey),
|
subtitle: Text(l10n.wolTip, style: UIs.text12Grey),
|
||||||
).card,
|
).cardx,
|
||||||
Input(
|
Input(
|
||||||
controller: _wolMacCtrl,
|
controller: _wolMacCtrl,
|
||||||
type: TextInputType.text,
|
type: TextInputType.text,
|
||||||
@@ -564,7 +557,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
|
|||||||
}
|
}
|
||||||
if (_keyIdx.value == null && _passwordController.text.isEmpty) {
|
if (_keyIdx.value == null && _passwordController.text.isEmpty) {
|
||||||
final cancel = await context.showRoundDialog<bool>(
|
final cancel = await context.showRoundDialog<bool>(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.askContinue(l10n.useNoPwd)),
|
child: Text(l10n.askContinue(l10n.useNoPwd)),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|||||||
@@ -2,26 +2,16 @@ import 'dart:async';
|
|||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:after_layout/after_layout.dart';
|
import 'package:after_layout/after_layout.dart';
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get_it/get_it.dart';
|
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:provider/provider.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/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/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/app/shell_func.dart';
|
||||||
import 'package:toolbox/data/model/server/try_limiter.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/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.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 'package:toolbox/view/widget/percent_circle.dart';
|
||||||
|
|
||||||
import '../../../core/route.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.dart';
|
||||||
import '../../../data/model/server/server_private_info.dart';
|
import '../../../data/model/server/server_private_info.dart';
|
||||||
import '../../../data/provider/server.dart';
|
import '../../../data/provider/server.dart';
|
||||||
import '../../../data/res/ui.dart';
|
|
||||||
import '../../widget/cardx.dart';
|
|
||||||
import '../../widget/server_func_btns.dart';
|
import '../../widget/server_func_btns.dart';
|
||||||
import '../../widget/tag.dart';
|
|
||||||
|
|
||||||
class ServerPage extends StatefulWidget {
|
class ServerPage extends StatefulWidget {
|
||||||
const ServerPage({super.key});
|
const ServerPage({super.key});
|
||||||
@@ -79,7 +66,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
_media = MediaQuery.of(context);
|
_media = MediaQuery.of(context);
|
||||||
_updateOffset();
|
_updateOffset();
|
||||||
_updateTextScaler();
|
_updateTextScaler();
|
||||||
_useDoubleColumn = _media.useDoubleColumn &&
|
_useDoubleColumn = _media.size.width > 639 &&
|
||||||
Stores.setting.doubleColumnServersPage.fetch();
|
Stores.setting.doubleColumnServersPage.fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +102,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
heroTag: 'addServer',
|
heroTag: 'addServer',
|
||||||
onPressed: () => AppRoute.serverEdit().go(context),
|
onPressed: () => AppRoutes.serverEdit().go(context),
|
||||||
tooltip: l10n.addAServer,
|
tooltip: l10n.addAServer,
|
||||||
child: const Icon(Icons.add),
|
child: const Icon(Icons.add),
|
||||||
),
|
),
|
||||||
@@ -137,7 +124,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () => AppRoute.settings().go(context),
|
onPressed: () => AppRoutes.settings().go(context),
|
||||||
icon: const Icon(Icons.settings, color: Colors.grey),
|
icon: const Icon(Icons.settings, color: Colors.grey),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -227,6 +214,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
_tag = p0;
|
_tag = p0;
|
||||||
}),
|
}),
|
||||||
initTag: _tag,
|
initTag: _tag,
|
||||||
|
allL10n: l10n.all,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,9 +273,9 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (srv.canViewDetails) {
|
if (srv.canViewDetails) {
|
||||||
AppRoute.serverDetail(spi: srv.spi).go(context);
|
AppRoutes.serverDetail(spi: srv.spi).go(context);
|
||||||
} else {
|
} else {
|
||||||
AppRoute.serverEdit(spi: srv.spi).go(context);
|
AppRoutes.serverEdit(spi: srv.spi).go(context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
@@ -298,7 +286,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
flip: !cardStatus.value.flip,
|
flip: !cardStatus.value.flip,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
AppRoute.serverEdit(spi: srv.spi).go(context);
|
AppRoutes.serverEdit(spi: srv.spi).go(context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -343,7 +331,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
height: _calcCardHeight(srv.conn, cardStatus.value.flip),
|
height: _calcCardHeight(srv.conn, cardStatus.value.flip),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: children,
|
children: children,
|
||||||
),
|
),
|
||||||
@@ -363,7 +351,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
func: () async {
|
func: () async {
|
||||||
if (Stores.setting.showSuspendTip.fetch()) {
|
if (Stores.setting.showSuspendTip.fetch()) {
|
||||||
await context.showRoundDialog(
|
await context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.suspendTip),
|
child: Text(l10n.suspendTip),
|
||||||
);
|
);
|
||||||
Stores.setting.showSuspendTip.put(false);
|
Stores.setting.showSuspendTip.put(false);
|
||||||
@@ -407,7 +395,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
text: l10n.reboot,
|
text: l10n.reboot,
|
||||||
),
|
),
|
||||||
IconTextBtn(
|
IconTextBtn(
|
||||||
onPressed: () => AppRoute.serverEdit(spi: srv.spi).go(context),
|
onPressed: () => AppRoutes.serverEdit(spi: srv.spi).go(context),
|
||||||
icon: Icons.edit,
|
icon: Icons.edit,
|
||||||
text: l10n.edit,
|
text: l10n.edit,
|
||||||
)
|
)
|
||||||
@@ -482,7 +470,7 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
height: 19,
|
height: 19,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
valueColor: AlwaysStoppedAnimation(primaryColor),
|
valueColor: AlwaysStoppedAnimation(UIs.primaryColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -549,11 +537,11 @@ ${ss.err?.solution ?? l10n.unknown}
|
|||||||
${ss.err?.message ?? l10n.unknownError}
|
${ss.err?.message ?? l10n.unknownError}
|
||||||
''';
|
''';
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: SingleChildScrollView(child: SimpleMarkdown(data: md)),
|
child: SingleChildScrollView(child: SimpleMarkdown(data: md)),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Shares.copy(md),
|
onPressed: () => Pfs.copy(md),
|
||||||
child: Text(l10n.copy),
|
child: Text(l10n.copy),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -649,7 +637,6 @@ ${ss.err?.message ?? l10n.unknownError}
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> afterFirstLayout(BuildContext context) async {
|
Future<void> afterFirstLayout(BuildContext context) async {
|
||||||
await GetIt.I.allReady();
|
|
||||||
await Pros.server.load();
|
await Pros.server.load();
|
||||||
Pros.server.startAutoRefresh();
|
Pros.server.startAutoRefresh();
|
||||||
}
|
}
|
||||||
@@ -682,7 +669,7 @@ ${ss.err?.message ?? l10n.unknownError}
|
|||||||
required String name,
|
required String name,
|
||||||
}) {
|
}) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.askContinue('$typ ${l10n.server}($name)')),
|
child: Text(l10n.askContinue('$typ ${l10n.server}($name)')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|||||||
@@ -1,42 +1,22 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_highlight/theme_map.dart';
|
import 'package:flutter_highlight/theme_map.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:provider/provider.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/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/provider.dart';
|
||||||
import 'package:toolbox/data/res/rebuild.dart';
|
import 'package:toolbox/data/res/rebuild.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
import 'package:toolbox/view/widget/expand_tile.dart';
|
import 'package:toolbox/data/res/url.dart';
|
||||||
import 'package:toolbox/view/widget/markdown.dart';
|
|
||||||
import 'package:toolbox/view/widget/val_builder.dart';
|
|
||||||
|
|
||||||
import '../../../core/persistant_store.dart';
|
|
||||||
import '../../../core/route.dart';
|
import '../../../core/route.dart';
|
||||||
import '../../../core/utils/misc.dart';
|
import '../../../core/utils/misc.dart';
|
||||||
import '../../../core/update.dart';
|
|
||||||
import '../../../data/model/app/net_view.dart';
|
import '../../../data/model/app/net_view.dart';
|
||||||
import '../../../data/provider/app.dart';
|
import '../../../data/provider/app.dart';
|
||||||
import '../../../data/res/build_data.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;
|
const _kIconSize = 23.0;
|
||||||
|
|
||||||
@@ -59,7 +39,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.delete),
|
icon: const Icon(Icons.delete),
|
||||||
onPressed: () => context.showRoundDialog(
|
onPressed: () => context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: SimpleMarkdown(
|
child: SimpleMarkdown(
|
||||||
data: l10n.askContinue(
|
data: l10n.askContinue(
|
||||||
'${l10n.delete} **${l10n.all}** ${l10n.setting}',
|
'${l10n.delete} **${l10n.all}** ${l10n.setting}',
|
||||||
@@ -220,7 +200,13 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
onTap: () => Funcs.throttle(
|
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),
|
trailing: StoreSwitch(prop: _setting.autoCheckAppUpdate),
|
||||||
);
|
);
|
||||||
@@ -237,6 +223,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final val = await context.showPickSingleDialog(
|
final val = await context.showPickSingleDialog(
|
||||||
|
title: l10n.setting,
|
||||||
items: List.generate(10, (idx) => idx == 1 ? null : idx),
|
items: List.generate(10, (idx) => idx == 1 ? null : idx),
|
||||||
initial: _setting.serverStatusUpdateInterval.fetch(),
|
initial: _setting.serverStatusUpdateInterval.fetch(),
|
||||||
name: (p0) => p0 == 0 ? l10n.manual : '$p0 ${l10n.second}',
|
name: (p0) => p0 == 0 ? l10n.manual : '$p0 ${l10n.second}',
|
||||||
@@ -260,12 +247,12 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
leading: const Icon(Icons.colorize),
|
leading: const Icon(Icons.colorize),
|
||||||
title: Text(l10n.primaryColorSeed),
|
title: Text(l10n.primaryColorSeed),
|
||||||
trailing: ClipOval(
|
trailing: ClipOval(
|
||||||
child: Container(color: primaryColor, height: 27, width: 27),
|
child: Container(color: UIs.primaryColor, height: 27, width: 27),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final ctrl = TextEditingController(text: primaryColor.toHex);
|
final ctrl = TextEditingController(text: UIs.primaryColor.toHex);
|
||||||
await context.showRoundDialog(
|
await context.showRoundDialog(
|
||||||
title: Text(l10n.primaryColorSeed),
|
title: l10n.primaryColorSeed,
|
||||||
child: StatefulBuilder(builder: (context, setState) {
|
child: StatefulBuilder(builder: (context, setState) {
|
||||||
final children = <Widget>[
|
final children = <Widget>[
|
||||||
/// Plugin [dynamic_color] is not supported on iOS
|
/// Plugin [dynamic_color] is not supported on iOS
|
||||||
@@ -316,7 +303,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
// Change [primaryColor] first, then change [_selectedColorValue],
|
// Change [primaryColor] first, then change [_selectedColorValue],
|
||||||
// So the [ValueBuilder] will be triggered with the new value
|
// So the [ValueBuilder] will be triggered with the new value
|
||||||
primaryColor = color;
|
UIs.colorSeed = color;
|
||||||
_setting.primaryColor.put(color.value);
|
_setting.primaryColor.put(color.value);
|
||||||
context.pop();
|
context.pop();
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -376,6 +363,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
style: UIs.textGrey),
|
style: UIs.textGrey),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final selected = await context.showPickSingleDialog(
|
final selected = await context.showPickSingleDialog(
|
||||||
|
title: l10n.maxRetryCount,
|
||||||
items: List.generate(10, (index) => index),
|
items: List.generate(10, (index) => index),
|
||||||
name: (p0) => '$p0 ${l10n.times}',
|
name: (p0) => '$p0 ${l10n.times}',
|
||||||
initial: val,
|
initial: val,
|
||||||
@@ -400,6 +388,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
title: Text(l10n.themeMode),
|
title: Text(l10n.themeMode),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final selected = await context.showPickSingleDialog(
|
final selected = await context.showPickSingleDialog(
|
||||||
|
title: l10n.themeMode,
|
||||||
items: List.generate(len + 2, (index) => index),
|
items: List.generate(len + 2, (index) => index),
|
||||||
name: (p0) => _buildThemeModeStr(p0),
|
name: (p0) => _buildThemeModeStr(p0),
|
||||||
initial: _setting.themeMode.fetch(),
|
initial: _setting.themeMode.fetch(),
|
||||||
@@ -445,7 +434,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.font),
|
title: l10n.font,
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async => await _pickFontFile(),
|
onPressed: () async => await _pickFontFile(),
|
||||||
@@ -466,23 +455,22 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pickFontFile() async {
|
Future<void> _pickFontFile() async {
|
||||||
final path = await pickOneFile();
|
final path = await Pfs.pickFilePath();
|
||||||
if (path != null) {
|
if (path == null) return;
|
||||||
// iOS can't copy file to app dir, so we need to use the original path
|
|
||||||
if (isIOS) {
|
// iOS can't copy file to app dir, so we need to use the original path
|
||||||
_setting.fontPath.put(path);
|
if (isIOS) {
|
||||||
} else {
|
_setting.fontPath.put(path);
|
||||||
final fontFile = File(path);
|
} else {
|
||||||
final newPath = '${await Paths.font}/${path.split('/').last}';
|
final fontFile = File(path);
|
||||||
await fontFile.copy(newPath);
|
final newPath = '${Paths.fontPath}/${path.split('/').last}';
|
||||||
_setting.fontPath.put(newPath);
|
await fontFile.copy(newPath);
|
||||||
}
|
_setting.fontPath.put(newPath);
|
||||||
|
|
||||||
context.pop();
|
|
||||||
RebuildNodes.app.rebuild();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
context.showSnackBar(l10n.failed);
|
|
||||||
|
context.pop();
|
||||||
|
RebuildNodes.app.rebuild();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTermFontSize() {
|
Widget _buildTermFontSize() {
|
||||||
@@ -544,6 +532,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
title: Text(l10n.language),
|
title: Text(l10n.language),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final selected = await context.showPickSingleDialog(
|
final selected = await context.showPickSingleDialog(
|
||||||
|
title: l10n.language,
|
||||||
items: S.supportedLocales,
|
items: S.supportedLocales,
|
||||||
name: (p0) => p0.code,
|
name: (p0) => p0.code,
|
||||||
initial: _setting.locale.fetch().toLocale,
|
initial: _setting.locale.fetch().toLocale,
|
||||||
@@ -583,6 +572,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final selected = await context.showPickSingleDialog(
|
final selected = await context.showPickSingleDialog(
|
||||||
|
title: l10n.theme,
|
||||||
items: themeMap.keys.toList(),
|
items: themeMap.keys.toList(),
|
||||||
name: (p0) => p0,
|
name: (p0) => p0,
|
||||||
initial: _setting.editorTheme.fetch(),
|
initial: _setting.editorTheme.fetch(),
|
||||||
@@ -604,6 +594,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final selected = await context.showPickSingleDialog(
|
final selected = await context.showPickSingleDialog(
|
||||||
|
title: l10n.theme,
|
||||||
items: themeMap.keys.toList(),
|
items: themeMap.keys.toList(),
|
||||||
name: (p0) => p0,
|
name: (p0) => p0,
|
||||||
initial: _setting.editorDarkTheme.fetch(),
|
initial: _setting.editorDarkTheme.fetch(),
|
||||||
@@ -687,7 +678,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
leading: const Icon(BoxIcons.bxs_keyboard),
|
leading: const Icon(BoxIcons.bxs_keyboard),
|
||||||
title: Text(l10n.editVirtKeys),
|
title: Text(l10n.editVirtKeys),
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
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<SettingPage> {
|
|||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final selected = await context.showPickSingleDialog(
|
final selected = await context.showPickSingleDialog(
|
||||||
|
title: l10n.netViewType,
|
||||||
items: NetViewType.values,
|
items: NetViewType.values,
|
||||||
name: (p0) => p0.toStr,
|
name: (p0) => p0.toStr,
|
||||||
initial: _setting.netViewType.fetch(),
|
initial: _setting.netViewType.fetch(),
|
||||||
@@ -749,7 +741,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
context.showRoundDialog<List<String>>(
|
context.showRoundDialog<List<String>>(
|
||||||
title: Text(l10n.choose),
|
title: l10n.choose,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: StatefulBuilder(builder: (ctx, setState) {
|
child: StatefulBuilder(builder: (ctx, setState) {
|
||||||
final keys = Stores.server.box.keys.toList();
|
final keys = Stores.server.box.keys.toList();
|
||||||
@@ -761,7 +753,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
title: Text(name ?? e),
|
title: Text(name ?? e),
|
||||||
subtitle: name != null ? Text(e) : null,
|
subtitle: name != null ? Text(e) : null,
|
||||||
onTap: () => context.showRoundDialog(
|
onTap: () => context.showRoundDialog(
|
||||||
title: Text(l10n.attention),
|
title: l10n.attention,
|
||||||
child: Text(l10n.askContinue(
|
child: Text(l10n.askContinue(
|
||||||
'${l10n.delete} ${l10n.server}($e)',
|
'${l10n.delete} ${l10n.server}($e)',
|
||||||
)),
|
)),
|
||||||
@@ -806,7 +798,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () => context.showRoundDialog(
|
onTap: () => context.showRoundDialog(
|
||||||
title: Text(l10n.textScaler),
|
title: l10n.textScaler,
|
||||||
child: Input(
|
child: Input(
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
type: TextInputType.number,
|
type: TextInputType.number,
|
||||||
@@ -859,7 +851,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(l10n.sequence),
|
title: Text(l10n.sequence),
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
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<SettingPage> {
|
|||||||
leading: const Icon(OctIcons.sort_desc, size: _kIconSize),
|
leading: const Icon(OctIcons.sort_desc, size: _kIconSize),
|
||||||
title: Text(l10n.serverOrder),
|
title: Text(l10n.serverOrder),
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
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<SettingPage> {
|
|||||||
leading: const Icon(OctIcons.sort_desc, size: _kIconSize),
|
leading: const Icon(OctIcons.sort_desc, size: _kIconSize),
|
||||||
title: Text(l10n.serverDetailOrder),
|
title: Text(l10n.serverDetailOrder),
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
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<SettingPage> {
|
|||||||
final fontSize = double.tryParse(ctrller.text);
|
final fontSize = double.tryParse(ctrller.text);
|
||||||
if (fontSize == null) {
|
if (fontSize == null) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.failed),
|
title: l10n.failed,
|
||||||
child: Text('Parsed failed: ${ctrller.text}'),
|
child: Text('Parsed failed: ${ctrller.text}'),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -912,7 +904,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.fontSize),
|
title: l10n.fontSize,
|
||||||
child: Input(
|
child: Input(
|
||||||
controller: ctrller,
|
controller: ctrller,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
@@ -947,15 +939,15 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget? _buildPlatformSetting() {
|
Widget? _buildPlatformSetting() {
|
||||||
final func = switch (OS.type) {
|
final func = switch (Pfs.type) {
|
||||||
OS.android => AppRoute.androidSettings().go,
|
Pfs.android => AppRoutes.androidSettings().go,
|
||||||
OS.ios => AppRoute.iosSettings().go,
|
Pfs.ios => AppRoutes.iosSettings().go,
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
if (func == null) return null;
|
if (func == null) return null;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: const Icon(Icons.phone_android),
|
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),
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: () => func(context),
|
onTap: () => func(context),
|
||||||
);
|
);
|
||||||
@@ -1061,6 +1053,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final selected = await context.showPickSingleDialog(
|
final selected = await context.showPickSingleDialog(
|
||||||
|
title: l10n.theme,
|
||||||
items: List.generate(3, (index) => index),
|
items: List.generate(3, (index) => index),
|
||||||
name: (p0) => index2Str(p0),
|
name: (p0) => index2Str(p0),
|
||||||
initial: _setting.termTheme.fetch(),
|
initial: _setting.termTheme.fetch(),
|
||||||
@@ -1153,7 +1146,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
void onSave(String url) {
|
void onSave(String url) {
|
||||||
if (url.isEmpty || !url.startsWith('http')) {
|
if (url.isEmpty || !url.startsWith('http')) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.failed),
|
title: l10n.failed,
|
||||||
child: Text('${l10n.invalid} URL'),
|
child: Text('${l10n.invalid} URL'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@@ -1169,14 +1162,15 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
leading: const Icon(Icons.image),
|
||||||
title: Text('Logo ${l10n.addr}'),
|
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),
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final ctrl =
|
final ctrl =
|
||||||
TextEditingController(text: _setting.serverLogoUrl.fetch());
|
TextEditingController(text: _setting.serverLogoUrl.fetch());
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text('Logo ${l10n.addr}'),
|
title: 'Logo ${l10n.addr}',
|
||||||
child: Input(
|
child: Input(
|
||||||
controller: ctrl,
|
controller: ctrl,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.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/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/store.dart';
|
||||||
import 'package:toolbox/data/res/ui.dart';
|
|
||||||
import 'package:toolbox/view/page/setting/platform/platform_pub.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 {
|
class AndroidSettingsPage extends StatefulWidget {
|
||||||
const AndroidSettingsPage({super.key});
|
const AndroidSettingsPage({super.key});
|
||||||
@@ -88,7 +80,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
|||||||
});
|
});
|
||||||
final ctrl = TextEditingController(text: json.encode(data));
|
final ctrl = TextEditingController(text: json.encode(data));
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.homeWidgetUrlConfig),
|
title: l10n.homeWidgetUrlConfig,
|
||||||
child: Input(
|
child: Input(
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
controller: ctrl,
|
controller: ctrl,
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.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/locale.dart';
|
||||||
import 'package:toolbox/core/extension/context/snackbar.dart';
|
|
||||||
import 'package:toolbox/core/route.dart';
|
import 'package:toolbox/core/route.dart';
|
||||||
import 'package:toolbox/core/utils/misc.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/misc.dart';
|
||||||
import 'package:toolbox/data/res/store.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/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';
|
import 'package:watch_connectivity/watch_connectivity.dart';
|
||||||
|
|
||||||
class IOSSettingsPage extends StatefulWidget {
|
class IOSSettingsPage extends StatefulWidget {
|
||||||
@@ -59,7 +50,7 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
|
|||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_pushToken.value != null) {
|
if (_pushToken.value != null) {
|
||||||
Shares.copy(_pushToken.value!);
|
Pfs.copy(_pushToken.value!);
|
||||||
context.showSnackBar(l10n.success);
|
context.showSnackBar(l10n.success);
|
||||||
} else {
|
} else {
|
||||||
context.showSnackBar(l10n.getPushTokenFailed);
|
context.showSnackBar(l10n.getPushTokenFailed);
|
||||||
@@ -126,7 +117,7 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
|
|||||||
void _onTapWatchApp(Map<String, dynamic> map) async {
|
void _onTapWatchApp(Map<String, dynamic> map) async {
|
||||||
/// Encode [map] to String with indent `\t`
|
/// Encode [map] to String with indent `\t`
|
||||||
final text = Miscs.jsonEncoder.convert(map);
|
final text = Miscs.jsonEncoder.convert(map);
|
||||||
final result = await AppRoute.editor(
|
final result = await AppRoutes.editor(
|
||||||
text: text,
|
text: text,
|
||||||
langCode: 'json',
|
langCode: 'json',
|
||||||
title: 'Watch app',
|
title: 'Watch app',
|
||||||
@@ -139,7 +130,7 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
|
|||||||
await wc.updateApplicationContext(newCtx);
|
await wc.updateApplicationContext(newCtx);
|
||||||
} catch (e, trace) {
|
} catch (e, trace) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: Text(l10n.error),
|
title: l10n.error,
|
||||||
child: Text('${l10n.save}:\n$e'),
|
child: Text('${l10n.save}:\n$e'),
|
||||||
);
|
);
|
||||||
Loggers.app.warning('Update watch config failed', e, trace);
|
Loggers.app.warning('Update watch config failed', e, trace);
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.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/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 {
|
abstract final class PlatformPublicSettings {
|
||||||
static Widget buildBioAuth() {
|
static Widget buildBioAuth() {
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.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/model/app/server_detail_card.dart';
|
||||||
import 'package:toolbox/data/res/store.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 {
|
class ServerDetailOrderPage extends StatefulWidget {
|
||||||
const ServerDetailOrderPage({super.key});
|
const ServerDetailOrderPage({super.key});
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.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/model/app/menu/server_func.dart';
|
||||||
import 'package:toolbox/data/res/store.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 {
|
class ServerFuncBtnsOrderPage extends StatefulWidget {
|
||||||
const ServerFuncBtnsOrderPage({super.key});
|
const ServerFuncBtnsOrderPage({super.key});
|
||||||
@@ -50,7 +44,7 @@ class _ServerDetailOrderPageState extends State<ServerFuncBtnsOrderPage> {
|
|||||||
title: RichText(
|
title: RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
children: [
|
children: [
|
||||||
WidgetSpan(child: funcBtn.icon(2)),
|
WidgetSpan(child: Icon(funcBtn.icon)),
|
||||||
const WidgetSpan(child: UIs.width7),
|
const WidgetSpan(child: UIs.width7),
|
||||||
TextSpan(text: funcBtn.toStr, style: UIs.textGrey),
|
TextSpan(text: funcBtn.toStr, style: UIs.textGrey),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:toolbox/core/extension/context/locale.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/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.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 {
|
class ServerOrderPage extends StatefulWidget {
|
||||||
const ServerOrderPage({super.key});
|
const ServerOrderPage({super.key});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user