From 9ce221935ef313e07a74073a03c7aec3ad1fd63d Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Wed, 19 Jul 2023 18:26:10 +0800 Subject: [PATCH] #26 android `home widget` --- .dart_tool/flutter_gen/gen_l10n/l10n.dart | 6 + .dart_tool/flutter_gen/gen_l10n/l10n_de.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_en.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_zh.dart | 6 + android/app/src/main/AndroidManifest.xml | 20 +++ .../tech/lolli/toolbox/widget/HomeWidget.kt | 76 +++++++++ .../app/src/main/res/drawable/memory_24.xml | 5 + android/app/src/main/res/drawable/net_24.xml | 5 + .../app/src/main/res/drawable/settings_24.xml | 5 + .../app/src/main/res/drawable/speed_24.xml | 5 + .../app/src/main/res/drawable/storage_24.xml | 5 + .../main/res/drawable/widget_background.xml | 5 + .../app/src/main/res/layout/home_widget.xml | 147 ++++++++++++++++++ .../app/src/main/res/values-night/colors.xml | 6 + android/app/src/main/res/values/colors.xml | 7 + android/app/src/main/res/xml/home_widget.xml | 11 ++ ios/Runner.xcodeproj/project.pbxproj | 28 ++-- .../StatusWidget.intentdefinition | 2 +- ios/StatusWidget/StatusWidget.swift | 8 +- lib/data/res/build_data.dart | 8 +- lib/l10n/app_de.arb | 1 + lib/l10n/app_en.arb | 1 + lib/l10n/app_zh.arb | 1 + lib/l10n/app_zh_tw.arb | 1 + lib/view/page/setting.dart | 57 +++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + macos/Runner.xcodeproj/project.pbxproj | 12 +- pubspec.lock | 56 +++++++ pubspec.yaml | 1 + 29 files changed, 461 insertions(+), 32 deletions(-) create mode 100644 android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt create mode 100644 android/app/src/main/res/drawable/memory_24.xml create mode 100644 android/app/src/main/res/drawable/net_24.xml create mode 100644 android/app/src/main/res/drawable/settings_24.xml create mode 100644 android/app/src/main/res/drawable/speed_24.xml create mode 100644 android/app/src/main/res/drawable/storage_24.xml create mode 100644 android/app/src/main/res/drawable/widget_background.xml create mode 100644 android/app/src/main/res/layout/home_widget.xml create mode 100644 android/app/src/main/res/values-night/colors.xml create mode 100644 android/app/src/main/res/values/colors.xml create mode 100644 android/app/src/main/res/xml/home_widget.xml diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart index bdc7df95..cac774c7 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart @@ -528,6 +528,12 @@ abstract class S { /// **'Go to'** String get goto; + /// No description provided for @homeWidgetUrlConfig. + /// + /// In en, this message translates to: + /// **'Config home widget url'** + String get homeWidgetUrlConfig; + /// No description provided for @host. /// /// In en, this message translates to: diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart index f62c4270..2aba3f1c 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart @@ -236,6 +236,9 @@ class SDe extends S { @override String get goto => 'Pfad öffnen'; + @override + String get homeWidgetUrlConfig => 'Home-Widget-Link konfigurieren'; + @override String get host => 'Host'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart index c670b806..b554f58c 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart @@ -236,6 +236,9 @@ class SEn extends S { @override String get goto => 'Go to'; + @override + String get homeWidgetUrlConfig => 'Config home widget url'; + @override String get host => 'Host'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart index d221b572..927588d7 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart @@ -236,6 +236,9 @@ class SZh extends S { @override String get goto => '前往'; + @override + String get homeWidgetUrlConfig => '桌面部件链接配置'; + @override String get host => '主机'; @@ -885,6 +888,9 @@ class SZhTw extends SZh { @override String get goto => '前往'; + @override + String get homeWidgetUrlConfig => '桌面部件鏈接配置'; + @override String get host => '主機'; diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 7b1ca95c..6a2f204b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -36,5 +36,25 @@ + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt b/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt new file mode 100644 index 00000000..64c4e2a8 --- /dev/null +++ b/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt @@ -0,0 +1,76 @@ +package tech.lolli.toolbox.widget + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import android.view.View +import android.widget.RemoteViews +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import org.json.JSONObject +import tech.lolli.toolbox.R +import java.net.URL + +class HomeWidget : AppWidgetProvider() { + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { + for (appWidgetId in appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId) + } + } + + @OptIn(DelicateCoroutinesApi::class) + private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) { + val views = RemoteViews(context.packageName, R.layout.home_widget) + val sp = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) + var url = sp.getString("$appWidgetId", null) + val gUrl = sp.getString("*", null) + if (url.isNullOrEmpty()) { + url = gUrl + } + + if (url.isNullOrEmpty()) { + views.setViewVisibility(R.id.widget_cpu_label, View.INVISIBLE) + views.setViewVisibility(R.id.widget_mem_label, View.INVISIBLE) + views.setViewVisibility(R.id.widget_disk_label, View.INVISIBLE) + views.setViewVisibility(R.id.widget_net_label, View.INVISIBLE) + views.setTextViewText(R.id.widget_name, "ID: $appWidgetId") + appWidgetManager.updateAppWidget(appWidgetId, views) + return + } + + GlobalScope.launch(Dispatchers.IO) { + val jsonStr = URL(url).readText() + val jsonObject = JSONObject(jsonStr) + val data = jsonObject.getJSONObject("data") + val server = data.getString("name") + val cpu = data.getString("cpu") + val mem = data.getString("mem") + val disk = data.getString("disk") + val net = data.getString("net") + + GlobalScope.launch(Dispatchers.Main) { + // mem or disk is empty -> get status failed + // (cpu | net) isEmpty -> data is not ready + if (mem.isEmpty() || disk.isEmpty()) { + return@launch + } + views.setTextViewText(R.id.widget_name, server) + + views.setTextViewText(R.id.widget_cpu, cpu) + views.setTextViewText(R.id.widget_mem, mem) + views.setTextViewText(R.id.widget_disk, disk) + views.setTextViewText(R.id.widget_net, net) + + // eg: 17:17 + val timeStr = android.text.format.DateFormat.format("HH:mm", java.util.Date()).toString() + views.setTextViewText(R.id.widget_time, timeStr) + + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/res/drawable/memory_24.xml b/android/app/src/main/res/drawable/memory_24.xml new file mode 100644 index 00000000..782f0334 --- /dev/null +++ b/android/app/src/main/res/drawable/memory_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/android/app/src/main/res/drawable/net_24.xml b/android/app/src/main/res/drawable/net_24.xml new file mode 100644 index 00000000..b42514db --- /dev/null +++ b/android/app/src/main/res/drawable/net_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/android/app/src/main/res/drawable/settings_24.xml b/android/app/src/main/res/drawable/settings_24.xml new file mode 100644 index 00000000..bc9438a9 --- /dev/null +++ b/android/app/src/main/res/drawable/settings_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/android/app/src/main/res/drawable/speed_24.xml b/android/app/src/main/res/drawable/speed_24.xml new file mode 100644 index 00000000..56ecc4d7 --- /dev/null +++ b/android/app/src/main/res/drawable/speed_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/android/app/src/main/res/drawable/storage_24.xml b/android/app/src/main/res/drawable/storage_24.xml new file mode 100644 index 00000000..2ae99d06 --- /dev/null +++ b/android/app/src/main/res/drawable/storage_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/android/app/src/main/res/drawable/widget_background.xml b/android/app/src/main/res/drawable/widget_background.xml new file mode 100644 index 00000000..a8a58821 --- /dev/null +++ b/android/app/src/main/res/drawable/widget_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/home_widget.xml b/android/app/src/main/res/layout/home_widget.xml new file mode 100644 index 00000000..df71bc78 --- /dev/null +++ b/android/app/src/main/res/layout/home_widget.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/values-night/colors.xml b/android/app/src/main/res/values-night/colors.xml new file mode 100644 index 00000000..252bf018 --- /dev/null +++ b/android/app/src/main/res/values-night/colors.xml @@ -0,0 +1,6 @@ + + + #000000 + #FFFFFF + #BBBBBB + \ No newline at end of file diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..e3ae284f --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #EEEEEE + #FFFFFF + #000000 + #333333 + \ No newline at end of file diff --git a/android/app/src/main/res/xml/home_widget.xml b/android/app/src/main/res/xml/home_widget.xml new file mode 100644 index 00000000..b26ca598 --- /dev/null +++ b/android/app/src/main/res/xml/home_widget.xml @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 77f5737a..5091e2dc 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ E33A3E392A626DCD009744AB /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E33A3E382A626DCD009744AB /* SwiftUI.framework */; }; E33A3E3C2A626DCE009744AB /* StatusWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E3B2A626DCE009744AB /* StatusWidgetBundle.swift */; }; E33A3E402A626DCE009744AB /* StatusWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E3F2A626DCE009744AB /* StatusWidget.swift */; }; - E33A3E432A626DD0009744AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E33A3E422A626DD0009744AB /* Assets.xcassets */; }; E33A3E452A626DD0009744AB /* StatusWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */; }; E33A3E462A626DD0009744AB /* StatusWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */; }; E33A3E492A626DD0009744AB /* StatusWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E33A3E352A626DCD009744AB /* StatusWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -81,7 +80,6 @@ E33A3E3B2A626DCE009744AB /* StatusWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusWidgetBundle.swift; sourceTree = ""; }; E33A3E3F2A626DCE009744AB /* StatusWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusWidget.swift; sourceTree = ""; }; E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = StatusWidget.intentdefinition; sourceTree = ""; }; - E33A3E422A626DD0009744AB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; E33A3E442A626DD0009744AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E398BF6A29BDB34500FE4FD5 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; E3DB67EC2A31FE200027B8CB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -182,7 +180,6 @@ E33A3E3B2A626DCE009744AB /* StatusWidgetBundle.swift */, E33A3E3F2A626DCE009744AB /* StatusWidget.swift */, E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */, - E33A3E422A626DD0009744AB /* Assets.xcassets */, E33A3E442A626DD0009744AB /* Info.plist */, ); path = StatusWidget; @@ -286,7 +283,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - E33A3E432A626DD0009744AB /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -474,7 +470,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 376; + CURRENT_PROJECT_VERSION = 377; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -482,7 +478,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.376; + MARKETING_VERSION = 1.0.377; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -606,7 +602,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 376; + CURRENT_PROJECT_VERSION = 377; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -614,7 +610,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.376; + MARKETING_VERSION = 1.0.377; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -632,7 +628,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 376; + CURRENT_PROJECT_VERSION = 377; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -640,7 +636,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.376; + MARKETING_VERSION = 1.0.377; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -661,7 +657,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 377; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -674,7 +670,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.377; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; @@ -700,7 +696,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 377; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -713,7 +709,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.377; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -736,7 +732,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 377; DEVELOPMENT_TEAM = BA88US33G6; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -749,7 +745,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.377; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/ios/StatusWidget/StatusWidget.intentdefinition b/ios/StatusWidget/StatusWidget.intentdefinition index addc6097..a1f860e8 100644 --- a/ios/StatusWidget/StatusWidget.intentdefinition +++ b/ios/StatusWidget/StatusWidget.intentdefinition @@ -47,7 +47,7 @@ INIntentParameterMetadataCapitalization Characters INIntentParameterMetadataDefaultValue - https://push.lolli.tech + https:// INIntentParameterMetadataDefaultValueID wwvqC2 INIntentParameterMetadataDisableAutocorrect diff --git a/ios/StatusWidget/StatusWidget.swift b/ios/StatusWidget/StatusWidget.swift index a14ab6ca..309c5317 100644 --- a/ios/StatusWidget/StatusWidget.swift +++ b/ios/StatusWidget/StatusWidget.swift @@ -70,7 +70,7 @@ struct StatusWidgetEntryView : View { case .loading: ProgressView().padding() case .error(let descriotion): - Text(descriotion) + Text(descriotion).padding(.all, 13) case .normal: VStack(alignment: .leading, spacing: 5.7) { Text(entry.data.name).font(.system(.title3)) @@ -108,8 +108,8 @@ struct StatusWidget_Previews: PreviewProvider { struct StatusLoader { static func fetch(completion: @escaping (Result) -> Void) { - if url == nil || url == "" { - completion(.failure(NSError(domain: domain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Please longpress it to config first."]))) + if let url = url, url.count < 12 { + completion(.failure(NSError(domain: domain, code: 1, userInfo: [NSLocalizedDescriptionKey: "https://github.com/lollipopkit/server_box_monitor/wiki"]))) return } let URL = URL(string: url!)! @@ -134,7 +134,6 @@ struct StatusLoader { } static func getStatus(fromData data: Foundation.Data) -> Result { - let jsonAll = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any] let code = jsonAll["code"] as! Int if (code != 0) { @@ -194,7 +193,6 @@ struct DetailItem: View { func date2String(_ date:Date, dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> String { let formatter = DateFormatter() - formatter.locale = Locale.init(identifier: "zh_CN") formatter.dateFormat = dateFormat let date = formatter.string(from: date) return date diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 57702af3..374139b5 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,8 +2,8 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 376; - static const String engine = "3.10.5"; - static const String buildAt = "2023-07-08 15:09:08.542818"; - static const int modifications = 2; + static const int build = 377; + static const String engine = "3.10.6"; + static const String buildAt = "2023-07-16 23:02:53.506145"; + static const int modifications = 3; } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 3a97bdf9..262dd163 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -72,6 +72,7 @@ "getPushTokenFailed": "Push-Token kann nicht abgerufen werden", "gettingToken": "Getting token...", "goto": "Pfad öffnen", + "homeWidgetUrlConfig": "Home-Widget-Link konfigurieren", "host": "Host", "httpFailedWithCode": "Anfrage fehlgeschlagen, Statuscode: {code}", "image": "Image", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 291d0bbd..2afc3d38 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -72,6 +72,7 @@ "getPushTokenFailed": "Can't fetch push token", "gettingToken": "Getting token...", "goto": "Go to", + "homeWidgetUrlConfig": "Config home widget url", "host": "Host", "httpFailedWithCode": "request failed, status code: {code}", "image": "Image", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index a153b1a0..f88704f0 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -72,6 +72,7 @@ "getPushTokenFailed": "未能获取到推送token", "gettingToken": "正在获取Token...", "goto": "前往", + "homeWidgetUrlConfig": "桌面部件链接配置", "host": "主机", "httpFailedWithCode": "请求失败, 状态码: {code}", "image": "镜像", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index eac1c0c6..57228939 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -72,6 +72,7 @@ "getPushTokenFailed": "未能獲取到推送token", "gettingToken": "正在獲取Token...", "goto": "前往", + "homeWidgetUrlConfig": "桌面部件鏈接配置", "host": "主機", "httpFailedWithCode": "請求失敗, 狀態碼: {code}", "image": "鏡像", diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index fa760546..e4edff05 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -6,6 +6,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_highlight/theme_map.dart'; import 'package:flutter_material_color_picker/flutter_material_color_picker.dart'; import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:toolbox/core/extension/locale.dart'; import 'package:toolbox/core/extension/navigator.dart'; import 'package:toolbox/core/route.dart'; @@ -51,6 +52,7 @@ class _SettingPageState extends State { late final ServerProvider _serverProvider; late MediaQueryData _media; late S _s; + late SharedPreferences _sp; final _selectedColorValue = ValueNotifier(0); final _launchPageIdx = ValueNotifier(0); @@ -89,6 +91,8 @@ class _SettingPageState extends State { _editorDarkTheme.value = _setting.editorDarkTheme.fetch()!; _keyboardType.value = _setting.keyboardType.fetch()!; _rotateQuarter.value = _setting.fullScreenRotateQuarter.fetch()!; + SharedPreferences.setPrefix(''); + SharedPreferences.getInstance().then((value) => _sp = value); } @override @@ -141,6 +145,7 @@ class _SettingPageState extends State { } if (isAndroid) { children.add(_buildBgRun()); + children.add(_buildAndroidWidgetSharedPreference()); } return Column( children: children.map((e) => RoundRectCard(e)).toList(), @@ -836,4 +841,56 @@ class _SettingPageState extends State { ).go(context), ); } + + void _saveWidgetSP(String data, Map old) { + context.pop(); + try { + final map = Map.from(json.decode(data)); + final keysDel = old.keys.toSet().difference(map.keys.toSet()); + for (final key in keysDel) { + _sp.remove(key); + } + map.forEach((key, value) { + _sp.setString(key, value); + }); + showSnackBar(context, Text(_s.success)); + } catch (e) { + showSnackBar(context, Text(e.toString())); + } + } + + Widget _buildAndroidWidgetSharedPreference() { + return ListTile( + title: Text(_s.homeWidgetUrlConfig), + trailing: const Icon(Icons.arrow_forward_ios, size: 13), + onTap: () { + final data = {}; + _sp.getKeys().forEach((key) { + final val = _sp.getString(key); + if (val != null) { + data[key] = val; + } + }); + final ctrl = TextEditingController(text: json.encode(data)); + showRoundDialog( + context: context, + title: Text(_s.homeWidgetUrlConfig), + child: Input( + controller: ctrl, + label: 'JSON', + type: TextInputType.visiblePassword, + maxLines: 7, + onSubmitted: (p0) => _saveWidgetSP(p0, data), + ), + actions: [ + TextButton( + onPressed: () { + _saveWidgetSP(ctrl.text, data); + }, + child: Text(_s.ok), + ), + ]); + }, + ); + } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index bd594ba3..04309f6e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,11 +8,13 @@ import Foundation import flutter_volume_controller import path_provider_foundation import share_plus +import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterVolumeControllerPlugin.register(with: registry.registrar(forPlugin: "FlutterVolumeControllerPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index b457ebf6..8763239f 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -475,9 +475,9 @@ baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 376; + CURRENT_PROJECT_VERSION = 377; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.376; + MARKETING_VERSION = 1.0.377; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -490,9 +490,9 @@ baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 376; + CURRENT_PROJECT_VERSION = 377; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.376; + MARKETING_VERSION = 1.0.377; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -505,9 +505,9 @@ baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 376; + CURRENT_PROJECT_VERSION = 377; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.376; + MARKETING_VERSION = 1.0.377; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/pubspec.lock b/pubspec.lock index a38bf6b6..cde191c5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -774,6 +774,62 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + url: "https://pub.dev" + source: hosted + version: "2.3.0" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 08573d85..eaae2714 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,7 @@ dependencies: code_text_field: ^1.1.0 flutter_volume_controller: ^1.2.6 nil: ^1.1.1 + shared_preferences: ^2.1.1 dev_dependencies: flutter_native_splash: ^2.1.6