From d8ea0b8aa6c540722607ce68d1e8a5a134995413 Mon Sep 17 00:00:00 2001 From: lollipopkit <10864310+lollipopkit@users.noreply.github.com> Date: Sun, 15 Dec 2024 23:30:50 +0800 Subject: [PATCH 1/2] opt.: display err if home widget fails Fixes #614 --- android/app/build.gradle | 2 + android/app/src/main/AndroidManifest.xml | 2 +- .../kotlin/tech/lolli/toolbox/MainActivity.kt | 10 +- .../tech/lolli/toolbox/widget/HomeWidget.kt | 91 +++---- .../app/src/main/res/layout/home_widget.xml | 228 ++++++++++-------- android/app/src/main/res/values/strings.xml | 4 + lib/core/{channel/bg_run.dart => chan.dart} | 10 +- lib/core/channel/home_widget.dart | 12 - lib/view/page/home/home.dart | 6 +- lib/view/page/setting/seq/srv_seq.dart | 8 +- lib/view/page/ssh/page.dart | 6 +- pubspec.lock | 4 +- pubspec.yaml | 2 +- 13 files changed, 211 insertions(+), 174 deletions(-) create mode 100644 android/app/src/main/res/values/strings.xml rename lib/core/{channel/bg_run.dart => chan.dart} (57%) delete mode 100644 lib/core/channel/home_widget.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 27376a3f3..91fc5add8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -86,10 +86,12 @@ android { debug { applicationIdSuffix '.debug' + resValue "string", "app_name", "SrvBxD" } profile { applicationIdSuffix '.debug' + resValue "string", "app_name", "SrvBxP" } } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index bd4fe308e..f4938dc5e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ when (method.method) { "sendToBackground" -> { @@ -36,6 +38,12 @@ class MainActivity: FlutterFragmentActivity() { stopService(serviceIntent) result.success(null) } + "updateHomeWidget" -> { + val intent = Intent(this@MainActivity, HomeWidget::class.java) + intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE + sendBroadcast(intent) + result.success(null) + } else -> { result.notImplemented() } 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 index 4f425ada7..f233b8bdb 100644 --- a/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt +++ b/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt @@ -6,15 +6,18 @@ import android.appwidget.AppWidgetProvider import android.content.Context import android.content.Intent import android.os.Build +import android.util.Log import android.view.View import android.widget.RemoteViews -import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.json.JSONObject import tech.lolli.toolbox.R import java.net.URL +import java.net.HttpURLConnection +import java.io.FileNotFoundException class HomeWidget : AppWidgetProvider() { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { @@ -23,7 +26,6 @@ class HomeWidget : AppWidgetProvider() { } } - @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) @@ -36,6 +38,10 @@ class HomeWidget : AppWidgetProvider() { url = gUrl } + if (url.isNullOrEmpty()) { + Log.e("HomeWidget", "未找到 URL") + } + val intentUpdate = Intent(context, HomeWidget::class.java) intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE val ids = intArrayOf(appWidgetId) @@ -54,11 +60,11 @@ class HomeWidget : AppWidgetProvider() { views.setOnClickPendingIntent(R.id.widget_container, pendingUpdate) 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") + views.setTextViewText(R.id.widget_name, "No URL") + // Update the widget to display a message for missing URL + views.setViewVisibility(R.id.error_message, View.VISIBLE) + views.setTextViewText(R.id.error_message, "Please configure the widget URL.") + views.setViewVisibility(R.id.widget_content, View.GONE) appWidgetManager.updateAppWidget(appWidgetId, views) return } else { @@ -68,44 +74,45 @@ class HomeWidget : AppWidgetProvider() { views.setViewVisibility(R.id.widget_net_label, View.VISIBLE) } - GlobalScope.launch(Dispatchers.IO) { + CoroutineScope(Dispatchers.IO).launch { try { - 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) main@ { - // mem or disk is empty -> get status failed - // (cpu | net) isEmpty -> data is not ready - if (mem.isEmpty() || disk.isEmpty()) { - return@main + val connection = URL(url).openConnection() as HttpURLConnection + connection.requestMethod = "GET" + val responseCode = connection.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) { + val jsonStr = connection.inputStream.bufferedReader().use { it.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") + withContext(Dispatchers.Main) { + if (mem.isEmpty() || disk.isEmpty()) { + Log.e("HomeWidget", "获取状态失败:内存或磁盘信息为空") + return@withContext + } + 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) + val timeStr = android.text.format.DateFormat.format("HH:mm", java.util.Date()).toString() + views.setTextViewText(R.id.widget_time, timeStr) + appWidgetManager.updateAppWidget(appWidgetId, views) } - 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) - - val timeStr = android.text.format.DateFormat.format("HH:mm", java.util.Date()).toString() - views.setTextViewText(R.id.widget_time, timeStr) - - appWidgetManager.updateAppWidget(appWidgetId, views) + } else { + throw FileNotFoundException("HTTP response code: $responseCode") } } catch (e: Exception) { - println("ServerBoxHomeWidget: ${e.localizedMessage}") - GlobalScope.launch(Dispatchers.Main) main@ { - 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") - views.setTextViewText(R.id.widget_mem, e.localizedMessage) + Log.e("HomeWidget", "更新小部件时出错:${e.localizedMessage}", e) + withContext(Dispatchers.Main) { + views.setTextViewText(R.id.widget_name, "Error") + // Update the widget to display a message for data retrieval failure + views.setViewVisibility(R.id.error_message, View.VISIBLE) + views.setTextViewText(R.id.error_message, "Failed to retrieve data.") + views.setViewVisibility(R.id.widget_content, View.GONE) appWidgetManager.updateAppWidget(appWidgetId, views) } } diff --git a/android/app/src/main/res/layout/home_widget.xml b/android/app/src/main/res/layout/home_widget.xml index 0d04ca951..615a320e4 100644 --- a/android/app/src/main/res/layout/home_widget.xml +++ b/android/app/src/main/res/layout/home_widget.xml @@ -18,122 +18,144 @@ android:maxLines="1" tools:text="Server Name" /> - + - - - - + android:paddingTop="13dp"> - - - - - - - - - - - + + + + + + + + + + - - - - + android:paddingBottom="2.7dp" + android:layout_below="@id/widget_cpu_label" + android:gravity="center_vertical" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + + - - + + - - - - - + - - + - + - + - + + + + ServerBox + \ No newline at end of file diff --git a/lib/core/channel/bg_run.dart b/lib/core/chan.dart similarity index 57% rename from lib/core/channel/bg_run.dart rename to lib/core/chan.dart index e020b93b8..d55e4aca0 100644 --- a/lib/core/channel/bg_run.dart +++ b/lib/core/chan.dart @@ -1,14 +1,15 @@ import 'package:flutter/services.dart'; import 'package:server_box/data/res/misc.dart'; -abstract final class BgRunMC { - static const _channel = MethodChannel('${Miscs.pkgName}/app_retain'); +abstract final class MethodChans { + static const _channel = MethodChannel('${Miscs.pkgName}/main_chan'); static void moveToBg() { _channel.invokeMethod('sendToBackground'); } /// TODO: try fix the fn, then uncomment it and [stopService] + /// Issues #639 static void startService() { // _channel.invokeMethod('startService'); } @@ -16,4 +17,9 @@ abstract final class BgRunMC { static void stopService() { // _channel.invokeMethod('stopService'); } + + static void updateHomeWidget() async { + //if (!Stores.setting.autoUpdateHomeWidget.fetch()) return; + await _channel.invokeMethod('updateHomeWidget'); + } } diff --git a/lib/core/channel/home_widget.dart b/lib/core/channel/home_widget.dart deleted file mode 100644 index 5ac0828f6..000000000 --- a/lib/core/channel/home_widget.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:server_box/data/res/misc.dart'; -import 'package:server_box/data/res/store.dart'; - -abstract final class HomeWidgetMC { - static const _channel = MethodChannel('${Miscs.pkgName}/home_widget'); - - static void update() { - if (!Stores.setting.autoUpdateHomeWidget.fetch()) return; - _channel.invokeMethod('update'); - } -} diff --git a/lib/view/page/home/home.dart b/lib/view/page/home/home.dart index e74b2ccd7..e006d11c8 100644 --- a/lib/view/page/home/home.dart +++ b/lib/view/page/home/home.dart @@ -1,6 +1,6 @@ import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; -import 'package:server_box/core/channel/home_widget.dart'; +import 'package:server_box/core/chan.dart'; import 'package:server_box/data/model/app/tab.dart'; import 'package:server_box/data/provider/app.dart'; import 'package:server_box/data/provider/server.dart'; @@ -76,7 +76,7 @@ class _HomePageState extends State if (!ServerProvider.isAutoRefreshOn) { ServerProvider.startAutoRefresh(); } - HomeWidgetMC.update(); + MethodChans.updateHomeWidget(); break; case AppLifecycleState.paused: _shouldAuth = true; @@ -172,7 +172,7 @@ class _HomePageState extends State context: context, ); } - HomeWidgetMC.update(); + MethodChans.updateHomeWidget(); await ServerProvider.refresh(); } diff --git a/lib/view/page/setting/seq/srv_seq.dart b/lib/view/page/setting/seq/srv_seq.dart index b7a393dec..d74970ba4 100644 --- a/lib/view/page/setting/seq/srv_seq.dart +++ b/lib/view/page/setting/seq/srv_seq.dart @@ -45,20 +45,20 @@ class _ServerOrderPageState extends State { } Widget _buildBody() { - final orderNode = ServerProvider.serverOrder; - return orderNode.listenVal((order) { + final orders = ServerProvider.serverOrder; + return orders.listenVal((order) { if (order.isEmpty) { return Center(child: Text(libL10n.empty)); } return ReorderableListView.builder( footer: const SizedBox(height: 77), onReorder: (oldIndex, newIndex) => setState(() { - orderNode.value.move( + orders.value.move( oldIndex, newIndex, property: Stores.setting.serverOrder, ); - orderNode.notify(); + orders.notify(); }), padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3), buildDefaultDragHandles: false, diff --git a/lib/view/page/ssh/page.dart b/lib/view/page/ssh/page.dart index 01e16bd67..cc485fc9c 100644 --- a/lib/view/page/ssh/page.dart +++ b/lib/view/page/ssh/page.dart @@ -6,7 +6,7 @@ import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; -import 'package:server_box/core/channel/bg_run.dart'; +import 'package:server_box/core/chan.dart'; import 'package:server_box/core/extension/context/locale.dart'; import 'package:server_box/core/utils/ssh_auth.dart'; import 'package:server_box/core/utils/server.dart'; @@ -84,7 +84,7 @@ class SSHPageState extends State if (--_sshConnCount <= 0) { WakelockPlus.disable(); if (isAndroid) { - BgRunMC.stopService(); + MethodChans.stopService(); } } } @@ -99,7 +99,7 @@ class SSHPageState extends State if (++_sshConnCount == 1) { WakelockPlus.enable(); if (isAndroid) { - BgRunMC.startService(); + MethodChans.startService(); } } } diff --git a/pubspec.lock b/pubspec.lock index b7f4873bb..c0fd7c8de 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -478,8 +478,8 @@ packages: dependency: "direct main" description: path: "." - ref: "v1.0.224" - resolved-ref: ce532383b50fd3bfe74017a2799510c014b0f4f4 + ref: "v1.0.225" + resolved-ref: "9ca92213fea15b8c245ed2cc2958e14baea5cdbe" url: "https://github.com/lppcg/fl_lib" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index 0c7193de5..347afb6be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: fl_lib: git: url: https://github.com/lppcg/fl_lib - ref: v1.0.224 + ref: v1.0.225 dependency_overrides: # dartssh2: From d37ebe0ee91bc67de0c5f23bdb854ac15028fc44 Mon Sep 17 00:00:00 2001 From: lollipopkit <10864310+lollipopkit@users.noreply.github.com> Date: Sun, 15 Dec 2024 23:33:04 +0800 Subject: [PATCH 2/2] chore: en log --- .../src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 index f233b8bdb..59c57e10f 100644 --- a/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt +++ b/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt @@ -39,7 +39,7 @@ class HomeWidget : AppWidgetProvider() { } if (url.isNullOrEmpty()) { - Log.e("HomeWidget", "未找到 URL") + Log.e("HomeWidget", "URL not found") } val intentUpdate = Intent(context, HomeWidget::class.java) @@ -90,7 +90,7 @@ class HomeWidget : AppWidgetProvider() { val net = data.getString("net") withContext(Dispatchers.Main) { if (mem.isEmpty() || disk.isEmpty()) { - Log.e("HomeWidget", "获取状态失败:内存或磁盘信息为空") + Log.e("HomeWidget", "Failed to retrieve status: Memory or disk information is empty") return@withContext } views.setTextViewText(R.id.widget_name, server) @@ -106,7 +106,7 @@ class HomeWidget : AppWidgetProvider() { throw FileNotFoundException("HTTP response code: $responseCode") } } catch (e: Exception) { - Log.e("HomeWidget", "更新小部件时出错:${e.localizedMessage}", e) + Log.e("HomeWidget", "Error updating widget: ${e.localizedMessage}", e) withContext(Dispatchers.Main) { views.setTextViewText(R.id.widget_name, "Error") // Update the widget to display a message for data retrieval failure