From 8afb220076a78cf9a232d0ed817a4ce316530d19 Mon Sep 17 00:00:00 2001 From: ming7466464 Date: Wed, 1 Apr 2026 06:14:18 -0400 Subject: [PATCH] feat: add Chinese i18n, tablet layout, 9Router integration, and log visualization --- flutter_app/.flutter-plugins-dependencies | 1 + flutter_app/android/app/build.gradle | 2 +- .../android/app/jniLibs/arm64-v8a/libproot.so | Bin 0 -> 214416 bytes .../app/jniLibs/arm64-v8a/libprootloader.so | Bin 0 -> 18136 bytes .../app/jniLibs/arm64-v8a/libtalloc.so | 0 .../app/jniLibs/armeabi-v7a/libproot.so | Bin 0 -> 140792 bytes .../app/jniLibs/armeabi-v7a/libprootloader.so | Bin 0 -> 5632 bytes .../app/jniLibs/armeabi-v7a/libtalloc.so | 0 .../android/app/jniLibs/x86_64/libproot.so | Bin 0 -> 227552 bytes .../app/jniLibs/x86_64/libprootloader.so | Bin 0 -> 18352 bytes .../android/app/jniLibs/x86_64/libtalloc.so | 0 .../android/app/src/main/AndroidManifest.xml | 5 + .../plugins/GeneratedPluginRegistrant.java | 69 + .../com/nxg/openclawproot/MainActivity.kt | 19 + .../nxg/openclawproot/NineRouterService.kt | 110 ++ .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- flutter_app/android/gradlew | 160 +++ flutter_app/android/gradlew.bat | 90 ++ flutter_app/android/settings.gradle | 4 +- flutter_app/lib/app.dart | 10 +- flutter_app/lib/constants.dart | 2 +- flutter_app/lib/l10n/app_en.arb | 171 +++ flutter_app/lib/l10n/app_localizations.dart | 1141 +++++++++++++++++ .../lib/l10n/app_localizations_en.dart | 521 ++++++++ .../lib/l10n/app_localizations_zh.dart | 514 ++++++++ flutter_app/lib/l10n/app_strings.dart | 381 ++++++ flutter_app/lib/l10n/app_zh.arb | 171 +++ flutter_app/lib/models/ai_provider.dart | 28 +- flutter_app/lib/providers/node_provider.dart | 12 +- .../lib/screens/cliproxy_install_screen.dart | 238 ++++ flutter_app/lib/screens/cliproxy_screen.dart | 494 +++++++ flutter_app/lib/screens/configure_screen.dart | 4 +- flutter_app/lib/screens/dashboard_screen.dart | 402 +++--- flutter_app/lib/screens/logs_screen.dart | 278 ++-- .../screens/nine_router_terminal_screen.dart | 221 ++++ .../screens/nine_router_webview_screen.dart | 125 ++ flutter_app/lib/screens/node_screen.dart | 378 +++--- .../lib/screens/onboarding_screen.dart | 25 +- .../lib/screens/package_install_screen.dart | 4 +- flutter_app/lib/screens/packages_screen.dart | 4 +- .../lib/screens/provider_detail_screen.dart | 290 +++-- flutter_app/lib/screens/providers_screen.dart | 118 +- flutter_app/lib/screens/settings_screen.dart | 454 +++---- .../lib/screens/setup_wizard_screen.dart | 217 ++-- flutter_app/lib/screens/splash_screen.dart | 15 +- flutter_app/lib/screens/ssh_screen.dart | 6 +- flutter_app/lib/screens/terminal_screen.dart | 57 +- .../lib/services/bootstrap_service.dart | 12 +- .../capabilities/flash_capability.dart | 2 +- flutter_app/lib/services/gateway_service.dart | 14 +- flutter_app/lib/services/native_bridge.dart | 49 +- flutter_app/lib/services/node_service.dart | 2 +- flutter_app/lib/services/package_service.dart | 2 +- .../lib/services/provider_config_service.dart | 31 +- .../lib/services/terminal_service.dart | 10 +- flutter_app/lib/utils/log_parser.dart | 227 ++++ flutter_app/lib/utils/responsive.dart | 19 + flutter_app/lib/widgets/gateway_controls.dart | 35 +- flutter_app/lib/widgets/node_controls.dart | 23 +- flutter_app/lib/widgets/progress_step.dart | 4 +- flutter_app/lib/widgets/terminal_toolbar.dart | 2 +- flutter_app/pubspec.lock | 954 ++++++++++++++ scripts/fetch-proot-windows.ps1 | 98 ++ ...64\345\220\210\346\226\271\346\241\210.md" | 32 + ...10\347\253\257\346\227\245\345\277\227.md" | 0 66 files changed, 7104 insertions(+), 1155 deletions(-) create mode 100644 flutter_app/.flutter-plugins-dependencies create mode 100644 flutter_app/android/app/jniLibs/arm64-v8a/libproot.so create mode 100644 flutter_app/android/app/jniLibs/arm64-v8a/libprootloader.so create mode 100644 flutter_app/android/app/jniLibs/arm64-v8a/libtalloc.so create mode 100644 flutter_app/android/app/jniLibs/armeabi-v7a/libproot.so create mode 100644 flutter_app/android/app/jniLibs/armeabi-v7a/libprootloader.so create mode 100644 flutter_app/android/app/jniLibs/armeabi-v7a/libtalloc.so create mode 100644 flutter_app/android/app/jniLibs/x86_64/libproot.so create mode 100644 flutter_app/android/app/jniLibs/x86_64/libprootloader.so create mode 100644 flutter_app/android/app/jniLibs/x86_64/libtalloc.so create mode 100644 flutter_app/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java create mode 100644 flutter_app/android/app/src/main/kotlin/com/nxg/openclawproot/NineRouterService.kt create mode 100644 flutter_app/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 flutter_app/android/gradlew create mode 100644 flutter_app/android/gradlew.bat create mode 100644 flutter_app/lib/l10n/app_en.arb create mode 100644 flutter_app/lib/l10n/app_localizations.dart create mode 100644 flutter_app/lib/l10n/app_localizations_en.dart create mode 100644 flutter_app/lib/l10n/app_localizations_zh.dart create mode 100644 flutter_app/lib/l10n/app_strings.dart create mode 100644 flutter_app/lib/l10n/app_zh.arb create mode 100644 flutter_app/lib/screens/cliproxy_install_screen.dart create mode 100644 flutter_app/lib/screens/cliproxy_screen.dart create mode 100644 flutter_app/lib/screens/nine_router_terminal_screen.dart create mode 100644 flutter_app/lib/screens/nine_router_webview_screen.dart create mode 100644 flutter_app/lib/utils/log_parser.dart create mode 100644 flutter_app/lib/utils/responsive.dart create mode 100644 flutter_app/pubspec.lock create mode 100644 scripts/fetch-proot-windows.ps1 create mode 100644 "\346\225\264\345\220\210\346\226\271\346\241\210.md" create mode 100644 "\347\273\210\347\253\257\346\227\245\345\277\227.md" diff --git a/flutter_app/.flutter-plugins-dependencies b/flutter_app/.flutter-plugins-dependencies new file mode 100644 index 0000000..e7d553b --- /dev/null +++ b/flutter_app/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"camera_avfoundation","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\camera_avfoundation-0.9.23+2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_blue_plus_darwin","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_blue_plus_darwin-7.0.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_pty","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_pty-0.4.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_apple","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\geolocator_apple-2.3.13\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.6.0\\\\","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"permission_handler_apple","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\permission_handler_apple-9.4.7\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\shared_preferences_foundation-2.5.6\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_ios","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\url_launcher_ios-6.4.1\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"webview_flutter_wkwebview","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\webview_flutter_wkwebview-3.24.2\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"camera_android_camerax","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\camera_android_camerax-0.6.30\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_blue_plus_android","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_blue_plus_android-7.0.4\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_plugin_android_lifecycle-2.0.34\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_pty","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_pty-0.4.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_android","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\geolocator_android-4.6.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.2.23\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"permission_handler_android","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\permission_handler_android-12.1.0\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\shared_preferences_android-2.4.23\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\url_launcher_android-6.3.29\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"usb_serial","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\usb_serial-0.5.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"webview_flutter_android","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\webview_flutter_android-4.10.15\\\\","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"flutter_blue_plus_darwin","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_blue_plus_darwin-7.0.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_pty","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_pty-0.4.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_apple","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\geolocator_apple-2.3.13\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.6.0\\\\","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\shared_preferences_foundation-2.5.6\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\url_launcher_macos-3.2.5\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"webview_flutter_wkwebview","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\webview_flutter_wkwebview-3.24.2\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"flutter_blue_plus_linux","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_blue_plus_linux-7.0.3\\\\","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_pty","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_pty-0.4.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.2.1\\\\","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\shared_preferences_linux-2.4.1\\\\","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"url_launcher_linux","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\url_launcher_linux-3.2.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"flutter_pty","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_pty-0.4.2\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"geolocator_windows","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\geolocator_windows-0.2.5\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.3.0\\\\","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"permission_handler_windows","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\permission_handler_windows-0.2.1\\\\","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\shared_preferences_windows-2.4.1\\\\","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"url_launcher_windows","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\url_launcher_windows-3.1.5\\\\","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"camera_web","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\camera_web-0.3.5+3\\\\","dependencies":[],"dev_dependency":false},{"name":"flutter_blue_plus_web","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\flutter_blue_plus_web-7.0.2\\\\","dependencies":[],"dev_dependency":false},{"name":"geolocator_web","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\geolocator_web-4.1.3\\\\","dependencies":[],"dev_dependency":false},{"name":"permission_handler_html","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\permission_handler_html-0.1.3+5\\\\","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\shared_preferences_web-2.4.3\\\\","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"C:\\\\Users\\\\YouTube\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\url_launcher_web-2.4.2\\\\","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"camera","dependencies":["camera_android_camerax","camera_avfoundation","camera_web","flutter_plugin_android_lifecycle"]},{"name":"camera_android_camerax","dependencies":[]},{"name":"camera_avfoundation","dependencies":[]},{"name":"camera_web","dependencies":[]},{"name":"flutter_blue_plus","dependencies":["flutter_blue_plus_android","flutter_blue_plus_darwin","flutter_blue_plus_linux","flutter_blue_plus_web"]},{"name":"flutter_blue_plus_android","dependencies":[]},{"name":"flutter_blue_plus_darwin","dependencies":[]},{"name":"flutter_blue_plus_linux","dependencies":[]},{"name":"flutter_blue_plus_web","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_pty","dependencies":[]},{"name":"geolocator","dependencies":["geolocator_android","geolocator_apple","geolocator_web","geolocator_windows"]},{"name":"geolocator_android","dependencies":[]},{"name":"geolocator_apple","dependencies":[]},{"name":"geolocator_web","dependencies":[]},{"name":"geolocator_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_html","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_html","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"usb_serial","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2026-03-31 11:11:33.051186","version":"3.41.6","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/flutter_app/android/app/build.gradle b/flutter_app/android/app/build.gradle index fd928c9..bd373e6 100644 --- a/flutter_app/android/app/build.gradle +++ b/flutter_app/android/app/build.gradle @@ -35,7 +35,7 @@ def hasKeystore = keystoreProperties.containsKey('storeFile') && android { namespace = "com.nxg.openclawproot" - compileSdk = 35 + compileSdk = 36 ndkVersion = flutter.ndkVersion compileOptions { diff --git a/flutter_app/android/app/jniLibs/arm64-v8a/libproot.so b/flutter_app/android/app/jniLibs/arm64-v8a/libproot.so new file mode 100644 index 0000000000000000000000000000000000000000..591fc5630144bd2e1c387f937d1688ccf1908fea GIT binary patch literal 214416 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

*Lm_iOo+dqk`;p$?&r`hu{~HGf|2c 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 Y>A^XE-MrPkV%|fu)l!(!va{5`1M{sPC;$Ke literal 0 HcmV?d00001 diff --git a/flutter_app/android/app/jniLibs/arm64-v8a/libtalloc.so b/flutter_app/android/app/jniLibs/arm64-v8a/libtalloc.so new file mode 100644 index 0000000..e69de29 diff --git a/flutter_app/android/app/jniLibs/armeabi-v7a/libproot.so b/flutter_app/android/app/jniLibs/armeabi-v7a/libproot.so new file mode 100644 index 0000000000000000000000000000000000000000..a28666c906b20bb781aee438e8451bdf404be31a GIT binary patch literal 140792 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 Vr9C-_zB`=h&yx*tZvM>pzX8I{-J1Xa literal 0 HcmV?d00001 diff --git a/flutter_app/android/app/jniLibs/x86_64/libprootloader.so b/flutter_app/android/app/jniLibs/x86_64/libprootloader.so new file mode 100644 index 0000000000000000000000000000000000000000..391b6b57c09b2b82c6c0480187d352dba4c29205 GIT binary patch literal 18352 zcmeI4OKcle6hLPZJ8`SR7{n(+pp1|}F*LE=CaEW>Di2NCJLwdJ`eRwgpCqjlhw(T> zu%OZ;(2-@SY!E`~28lIg0ZI#Mod9-Rsx|?XvO+0RRTUSKR&8QF&2XRXNt3bxsqF5R z-n;L6KWEv*WXoHTh_SG z)+eeaY;Es*^{O6WIg$_oB0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y z2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y z2oM1xKm>>Y5%@m|902pGd`LbhACUL&1M^S$GhWH(ER=4)rDmS%!vD()hqA?IApMqW zVk3rfmi?9fOg+c(g7dT++rWPd=~^&Kb;7$J)^MB>c8sa~yfr^ji?gb^EI7xr!tpum zm5tyM&cEdUPH-w_u6uk*IQ|Jvq2uByHV^5f8`Aq4)bt*4Vgs&~&pe9tUUN}!Lg!AG zF#bW=(w-(5F9>6GXbx(3y1|?R&w0r7)Pr%Q1k!oIxPaRrqwyf!1Y!40@XRUZ3>Yi* z!aEoWnS*tRhWow^@qD&zRe6vL7<9yFj{ydEEl@5-eW^ei_V* zU|0=WCrmEXf|Xayl48vN)stzR?DiKb{#bkk7GDA5n{@1zrc*aCNc~Bn@mM*IeEDk! zVC2yJoVEzklrZ)Y3(%Yeqkt@@(dRUC<(UKXGQ&CYW*MauK@>MD<{~QISfi-&855?=REnm(7A~T&Y(*7a2=V6b3Y# zTG%^Y&>z3YJ6F$PrXc0DJLN|tFMY%74i(Q)xBpi>nb$*iElcI6Fx2Ar6Wh_$xzDi@ zoboBYSc?(kadWBZhar8?wf4M@CVMgt#F-UiOje&S7^91LsDiH49Y_x^Lgt|zGRGAg z(2OWF1`*S63DQ2?=!WqnT|$s|k7493}5Zzvg!h>0OlYir*c2>8MtF&qyK z^@$@{$wW#EM_a;)L9d=j#KZlefgx`^ zJ~G%mtR;>_!@AfOmD=0erI@eXw{4qGl0uef3rq7ib(MN33NdWfBx2O;dpva;@*EQfI*hy`W! zyDyb4$6iot)vA_Rfe-~!;`!AL0`@T`baroXV?`N-rwNk?0awe}Z<7>q3 Y+M30Kua1An?p>9kXYZS__u0dL1GTK3@c;k- literal 0 HcmV?d00001 diff --git a/flutter_app/android/app/jniLibs/x86_64/libtalloc.so b/flutter_app/android/app/jniLibs/x86_64/libtalloc.so new file mode 100644 index 0000000..e69de29 diff --git a/flutter_app/android/app/src/main/AndroidManifest.xml b/flutter_app/android/app/src/main/AndroidManifest.xml index 63c1511..9b8c648 100644 --- a/flutter_app/android/app/src/main/AndroidManifest.xml +++ b/flutter_app/android/app/src/main/AndroidManifest.xml @@ -65,6 +65,11 @@ android:exported="false" android:foregroundServiceType="specialUse" /> + + { result.success(TerminalSessionService.isRunning) } + "startNineRouterService" -> { + try { + NineRouterService.start(applicationContext) + result.success(true) + } catch (e: Exception) { + result.error("SERVICE_ERROR", e.message, null) + } + } + "stopNineRouterService" -> { + try { + NineRouterService.stop(applicationContext) + result.success(true) + } catch (e: Exception) { + result.error("SERVICE_ERROR", e.message, null) + } + } + "isNineRouterServiceRunning" -> { + result.success(NineRouterService.isRunning) + } "startNodeService" -> { try { NodeForegroundService.start(applicationContext) diff --git a/flutter_app/android/app/src/main/kotlin/com/nxg/openclawproot/NineRouterService.kt b/flutter_app/android/app/src/main/kotlin/com/nxg/openclawproot/NineRouterService.kt new file mode 100644 index 0000000..f20343f --- /dev/null +++ b/flutter_app/android/app/src/main/kotlin/com/nxg/openclawproot/NineRouterService.kt @@ -0,0 +1,110 @@ +package com.nxg.openclawproot + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.Build +import android.os.IBinder +import android.os.PowerManager + +class NineRouterService : Service() { + companion object { + const val NOTIFICATION_ID = 7 + var isRunning = false + private set + + fun start(context: Context) { + val intent = Intent(context, NineRouterService::class.java) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(intent) + } else { + context.startService(intent) + } + } + + fun stop(context: Context) { + val intent = Intent(context, NineRouterService::class.java) + context.stopService(intent) + } + } + + private var wakeLock: PowerManager.WakeLock? = null + + override fun onBind(intent: Intent?): IBinder? = null + + override fun onCreate() { + super.onCreate() + createNotificationChannel() + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + startForeground(NOTIFICATION_ID, buildNotification()) + if (isRunning) return START_STICKY + isRunning = true + acquireWakeLock() + return START_STICKY + } + + override fun onDestroy() { + isRunning = false + releaseWakeLock() + super.onDestroy() + } + + private fun acquireWakeLock() { + releaseWakeLock() + val pm = getSystemService(Context.POWER_SERVICE) as PowerManager + wakeLock = pm.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, + "OpenClaw::NineRouterWakeLock" + ) + wakeLock?.acquire(24 * 60 * 60 * 1000L) + } + + private fun releaseWakeLock() { + wakeLock?.let { if (it.isHeld) it.release() } + wakeLock = null + } + + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + GatewayService.CHANNEL_ID, + "OpenClaw Gateway", + NotificationManager.IMPORTANCE_LOW + ) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + } + + private fun buildNotification(): Notification { + val intent = Intent(this, MainActivity::class.java) + val pendingIntent = PendingIntent.getActivity( + this, 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Notification.Builder(this, GatewayService.CHANNEL_ID) + .setContentTitle("9Router") + .setContentText("9Router is running on port 20128") + .setSmallIcon(android.R.drawable.ic_menu_manage) + .setContentIntent(pendingIntent) + .setOngoing(true) + .build() + } else { + @Suppress("DEPRECATION") + Notification.Builder(this) + .setContentTitle("9Router") + .setContentText("9Router is running on port 20128") + .setSmallIcon(android.R.drawable.ic_menu_manage) + .setContentIntent(pendingIntent) + .setOngoing(true) + .build() + } + } +} diff --git a/flutter_app/android/gradle/wrapper/gradle-wrapper.jar b/flutter_app/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659 GIT binary patch literal 53636 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ⅅ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 H-+%o-(+5aQ literal 0 HcmV?d00001 diff --git a/flutter_app/android/gradle/wrapper/gradle-wrapper.properties b/flutter_app/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6..efdcc4a 100644 --- a/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +++ b/flutter_app/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/flutter_app/android/gradlew b/flutter_app/android/gradlew new file mode 100644 index 0000000..9d82f78 --- /dev/null +++ b/flutter_app/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/flutter_app/android/gradlew.bat b/flutter_app/android/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/flutter_app/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/flutter_app/android/settings.gradle b/flutter_app/android/settings.gradle index 54b690d..b507b94 100644 --- a/flutter_app/android/settings.gradle +++ b/flutter_app/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.9.0" apply false + id "com.android.application" version "8.9.1" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false } include ":app" diff --git a/flutter_app/lib/app.dart b/flutter_app/lib/app.dart index 5732c6a..9512211 100644 --- a/flutter_app/lib/app.dart +++ b/flutter_app/lib/app.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'providers/setup_provider.dart'; @@ -95,7 +95,7 @@ class OpenClawApp extends StatelessWidget { color: Colors.white, ), ), - cardTheme: CardTheme( + cardTheme: CardThemeData( elevation: 0, color: AppColors.darkSurface, shape: RoundedRectangleBorder( @@ -165,7 +165,7 @@ class OpenClawApp extends StatelessWidget { color: AppColors.darkBorder, space: 1, ), - dialogTheme: DialogTheme( + dialogTheme: DialogThemeData( backgroundColor: AppColors.darkSurface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), @@ -226,7 +226,7 @@ class OpenClawApp extends StatelessWidget { color: const Color(0xFF0A0A0A), ), ), - cardTheme: CardTheme( + cardTheme: CardThemeData( elevation: 0, color: AppColors.lightBg, shape: RoundedRectangleBorder( @@ -296,7 +296,7 @@ class OpenClawApp extends StatelessWidget { color: AppColors.lightBorder, space: 1, ), - dialogTheme: DialogTheme( + dialogTheme: DialogThemeData( backgroundColor: AppColors.lightBg, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), diff --git a/flutter_app/lib/constants.dart b/flutter_app/lib/constants.dart index 3beefbd..44619cf 100644 --- a/flutter_app/lib/constants.dart +++ b/flutter_app/lib/constants.dart @@ -31,7 +31,7 @@ class AppConstants { static const String rootfsArmhf = '${ubuntuRootfsUrl}armhf.tar.gz'; static const String rootfsAmd64 = '${ubuntuRootfsUrl}amd64.tar.gz'; - // Node.js binary tarball — downloaded directly by Flutter, extracted by Java. + // Node.js binary tarball ?downloaded directly by Flutter, extracted by Java. // Bypasses curl/gpg/NodeSource which fail inside proot. static const String nodeVersion = '22.14.0'; static const String nodeBaseUrl = diff --git a/flutter_app/lib/l10n/app_en.arb b/flutter_app/lib/l10n/app_en.arb new file mode 100644 index 0000000..fa1840b --- /dev/null +++ b/flutter_app/lib/l10n/app_en.arb @@ -0,0 +1,171 @@ +{ + "@@locale": "en", + "appName": "OpenClaw", + "cancel": "Cancel", + "confirm": "Confirm", + "retry": "Retry", + "done": "Done", + "save": "Save", + "remove": "Remove", + "install": "Install", + "loading": "Loading...", + "error": "Error", + "copy": "Copy", + "paste": "Paste", + "openUrl": "Open URL", + "screenshot": "Screenshot", + "restart": "Restart", + "later": "Later", + "download": "Download", + "copied": "Copied to clipboard", + "noUrlFound": "No URL found in selection", + "linkCopied": "Link copied", + "openLink": "Open Link", + "aiGatewayForAndroid": "AI Gateway for Android", + "checkingSetup": "Checking setup status...", + "repairingBypass": "Repairing bionic bypass...", + "reinstallingNode": "Reinstalling Node.js...", + "reinstallingOpenClaw": "Reinstalling OpenClaw...", + "quickActions": "QUICK ACTIONS", + "terminal": "Terminal", + "terminalSubtitle": "Open Ubuntu shell with OpenClaw", + "webDashboard": "Web Dashboard", + "webDashboardSubtitle": "Open OpenClaw dashboard in browser", + "startGatewayFirst": "Start gateway first", + "onboarding": "Onboarding", + "onboardingSubtitle": "Configure API keys and binding", + "configure": "Configure", + "configureSubtitle": "Manage gateway settings", + "aiProviders": "AI Providers", + "aiProvidersSubtitle": "Configure models and API keys", + "packages": "Packages", + "packagesSubtitle": "Install optional tools (Go, Homebrew, SSH)", + "sshAccess": "SSH Access", + "sshAccessSubtitle": "Remote terminal access via SSH", + "logs": "Logs", + "logsSubtitle": "View gateway output and errors", + "snapshot": "Snapshot", + "snapshotSubtitle": "Backup or restore your config", + "node": "Node", + "nodeConnected": "Connected to gateway", + "nodeCapabilities": "Device capabilities for AI", + "dashboardUrlCopied": "Dashboard URL copied", + "copyDashboardUrl": "Copy dashboard URL", + "cliProxy": "CLIProxy Manager", + "cliProxySubtitle": "Manage free AI account proxy", + "gateway": "Gateway", + "startGateway": "Start Gateway", + "stopGateway": "Stop Gateway", + "viewLogs": "View Logs", + "urlCopied": "URL copied to clipboard", + "copyUrl": "Copy URL", + "openDashboard": "Open dashboard", + "gatewayRunning": "Running", + "gatewayStarting": "Starting", + "gatewayError": "Error", + "gatewayStopped": "Stopped", + "enableNode": "Enable Node", + "disableNode": "Disable Node", + "reconnect": "Reconnect", + "nodePaired": "Paired", + "nodeConnecting": "Connecting", + "nodeDisconnected": "Disconnected", + "nodeDisabled": "Disabled", + "nodeConfigure": "Configure", + "settings": "Settings", + "general": "GENERAL", + "autoStartGateway": "Auto-start gateway", + "autoStartSubtitle": "Start the gateway when the app opens", + "batteryOptimization": "Battery Optimization", + "batteryOptimized": "Optimized (may kill background sessions)", + "batteryUnrestricted": "Unrestricted (recommended)", + "setupStorage": "Setup Storage", + "storageGranted": "Granted — proot can access /sdcard. Revoke if not needed.", + "storageNotGranted": "Allow access to shared storage", + "nodeSection": "NODE", + "enableNodeTitle": "Enable Node", + "enableNodeSubtitle": "Provide device capabilities to the gateway", + "nodeConfiguration": "Node Configuration", + "nodeConfigSubtitle": "Connection, pairing, and capabilities", + "systemInfo": "SYSTEM INFO", + "architecture": "Architecture", + "prootPath": "PRoot path", + "rootfs": "Rootfs", + "installed": "Installed", + "notInstalled": "Not installed", + "maintenance": "MAINTENANCE", + "exportSnapshot": "Export Snapshot", + "exportSnapshotSubtitle": "Backup config to Downloads", + "importSnapshot": "Import Snapshot", + "importSnapshotSubtitle": "Restore config from backup", + "rerunSetup": "Re-run setup", + "rerunSetupSubtitle": "Reinstall or repair the environment", + "about": "ABOUT", + "checkForUpdates": "Check for Updates", + "checkUpdatesSubtitle": "Check GitHub for a newer release", + "developer": "Developer", + "github": "GitHub", + "contact": "Contact", + "license": "License", + "updateAvailable": "Update Available", + "currentVersion": "Current", + "latestVersion": "Latest", + "alreadyLatest": "You're on the latest version", + "checkUpdateFailed": "Could not check for updates", + "snapshotSaved": "Snapshot saved to", + "exportFailed": "Export failed", + "noSnapshotFound": "No snapshot found at", + "snapshotRestored": "Snapshot restored successfully. Restart the gateway to apply.", + "importFailed": "Import failed", + "setupOpenClaw": "Setup OpenClaw", + "setupRunning": "Setting up the environment. This may take several minutes.", + "setupDescription": "This will download Ubuntu, Node.js, and OpenClaw into a self-contained environment.", + "downloadRootfs": "Download Ubuntu rootfs", + "extractRootfs": "Extract rootfs", + "installNode": "Install Node.js", + "installOpenClaw": "Install OpenClaw", + "configureBionicBypass": "Configure Bionic Bypass", + "setupComplete": "Setup complete!", + "configureApiKeys": "Configure API Keys", + "beginSetup": "Begin Setup", + "retrySetup": "Retry Setup", + "storageRequired": "Requires ~500MB of storage and an internet connection", + "optionalPackages": "OPTIONAL PACKAGES", + "gatewayLogs": "Gateway Logs", + "filterLogs": "Filter logs...", + "noLogsYet": "No logs yet. Start the gateway.", + "noMatchingLogs": "No matching logs.", + "copyAllLogs": "Copy all logs", + "autoScrollOn": "Auto-scroll on", + "autoScrollOff": "Auto-scroll off", + "activeModel": "Active Model", + "selectProvider": "Select a provider to configure its API key and model.", + "active": "Active", + "configured": "Configured", + "apiKey": "API Key", + "model": "Model", + "customModel": "Custom...", + "customModelHint": "e.g. meta/llama-3.3-70b-instruct", + "customModelLabel": "Custom model name", + "saveAndActivate": "Save & Activate", + "removeConfiguration": "Remove Configuration", + "apiKeyEmpty": "API key cannot be empty", + "modelEmpty": "Model name cannot be empty", + "configuredAndActivated": "configured and activated", + "saveFailed": "Failed to save", + "removeFailed": "Failed to remove", + "removeProvider": "Remove", + "removeProviderContent": "This will delete the API key and deactivate the model.", + "startingTerminal": "Starting terminal...", + "failedToStartTerminal": "Failed to start terminal", + "openClawOnboarding": "OpenClaw Onboarding", + "startingOnboarding": "Starting onboarding...", + "failedToStartOnboarding": "Failed to start onboarding", + "goToDashboard": "Go to Dashboard", + "cliProxyManagement": "CLIProxy Management", + "cliProxyNotRunning": "CLIProxy service is not running", + "openInBrowser": "Open in browser", + "refresh": "Refresh", + "reconnectProxy": "Reconnect", + "installedBadge": "Installed" +} diff --git a/flutter_app/lib/l10n/app_localizations.dart b/flutter_app/lib/l10n/app_localizations.dart new file mode 100644 index 0000000..186d611 --- /dev/null +++ b/flutter_app/lib/l10n/app_localizations.dart @@ -0,0 +1,1141 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_en.dart'; +import 'app_localizations_zh.dart'; + +// ignore_for_file: type=lint + +/// Callers can lookup localized strings with an instance of AppLocalizations +/// returned by `AppLocalizations.of(context)`. +/// +/// Applications need to include `AppLocalizations.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'l10n/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocalizations.localizationsDelegates, +/// supportedLocales: AppLocalizations.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocalizations.supportedLocales +/// property. +abstract class AppLocalizations { + AppLocalizations(String locale) + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocalizations? of(BuildContext context) { + return Localizations.of(context, AppLocalizations); + } + + static const LocalizationsDelegate delegate = + _AppLocalizationsDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = + >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('en'), + Locale('zh') + ]; + + /// No description provided for @appName. + /// + /// In en, this message translates to: + /// **'OpenClaw'** + String get appName; + + /// No description provided for @cancel. + /// + /// In en, this message translates to: + /// **'Cancel'** + String get cancel; + + /// No description provided for @confirm. + /// + /// In en, this message translates to: + /// **'Confirm'** + String get confirm; + + /// No description provided for @retry. + /// + /// In en, this message translates to: + /// **'Retry'** + String get retry; + + /// No description provided for @done. + /// + /// In en, this message translates to: + /// **'Done'** + String get done; + + /// No description provided for @save. + /// + /// In en, this message translates to: + /// **'Save'** + String get save; + + /// No description provided for @remove. + /// + /// In en, this message translates to: + /// **'Remove'** + String get remove; + + /// No description provided for @install. + /// + /// In en, this message translates to: + /// **'Install'** + String get install; + + /// No description provided for @loading. + /// + /// In en, this message translates to: + /// **'Loading...'** + String get loading; + + /// No description provided for @error. + /// + /// In en, this message translates to: + /// **'Error'** + String get error; + + /// No description provided for @copy. + /// + /// In en, this message translates to: + /// **'Copy'** + String get copy; + + /// No description provided for @paste. + /// + /// In en, this message translates to: + /// **'Paste'** + String get paste; + + /// No description provided for @openUrl. + /// + /// In en, this message translates to: + /// **'Open URL'** + String get openUrl; + + /// No description provided for @screenshot. + /// + /// In en, this message translates to: + /// **'Screenshot'** + String get screenshot; + + /// No description provided for @restart. + /// + /// In en, this message translates to: + /// **'Restart'** + String get restart; + + /// No description provided for @later. + /// + /// In en, this message translates to: + /// **'Later'** + String get later; + + /// No description provided for @download. + /// + /// In en, this message translates to: + /// **'Download'** + String get download; + + /// No description provided for @copied. + /// + /// In en, this message translates to: + /// **'Copied to clipboard'** + String get copied; + + /// No description provided for @noUrlFound. + /// + /// In en, this message translates to: + /// **'No URL found in selection'** + String get noUrlFound; + + /// No description provided for @linkCopied. + /// + /// In en, this message translates to: + /// **'Link copied'** + String get linkCopied; + + /// No description provided for @openLink. + /// + /// In en, this message translates to: + /// **'Open Link'** + String get openLink; + + /// No description provided for @aiGatewayForAndroid. + /// + /// In en, this message translates to: + /// **'AI Gateway for Android'** + String get aiGatewayForAndroid; + + /// No description provided for @checkingSetup. + /// + /// In en, this message translates to: + /// **'Checking setup status...'** + String get checkingSetup; + + /// No description provided for @repairingBypass. + /// + /// In en, this message translates to: + /// **'Repairing bionic bypass...'** + String get repairingBypass; + + /// No description provided for @reinstallingNode. + /// + /// In en, this message translates to: + /// **'Reinstalling Node.js...'** + String get reinstallingNode; + + /// No description provided for @reinstallingOpenClaw. + /// + /// In en, this message translates to: + /// **'Reinstalling OpenClaw...'** + String get reinstallingOpenClaw; + + /// No description provided for @quickActions. + /// + /// In en, this message translates to: + /// **'QUICK ACTIONS'** + String get quickActions; + + /// No description provided for @terminal. + /// + /// In en, this message translates to: + /// **'Terminal'** + String get terminal; + + /// No description provided for @terminalSubtitle. + /// + /// In en, this message translates to: + /// **'Open Ubuntu shell with OpenClaw'** + String get terminalSubtitle; + + /// No description provided for @webDashboard. + /// + /// In en, this message translates to: + /// **'Web Dashboard'** + String get webDashboard; + + /// No description provided for @webDashboardSubtitle. + /// + /// In en, this message translates to: + /// **'Open OpenClaw dashboard in browser'** + String get webDashboardSubtitle; + + /// No description provided for @startGatewayFirst. + /// + /// In en, this message translates to: + /// **'Start gateway first'** + String get startGatewayFirst; + + /// No description provided for @onboarding. + /// + /// In en, this message translates to: + /// **'Onboarding'** + String get onboarding; + + /// No description provided for @onboardingSubtitle. + /// + /// In en, this message translates to: + /// **'Configure API keys and binding'** + String get onboardingSubtitle; + + /// No description provided for @configure. + /// + /// In en, this message translates to: + /// **'Configure'** + String get configure; + + /// No description provided for @configureSubtitle. + /// + /// In en, this message translates to: + /// **'Manage gateway settings'** + String get configureSubtitle; + + /// No description provided for @aiProviders. + /// + /// In en, this message translates to: + /// **'AI Providers'** + String get aiProviders; + + /// No description provided for @aiProvidersSubtitle. + /// + /// In en, this message translates to: + /// **'Configure models and API keys'** + String get aiProvidersSubtitle; + + /// No description provided for @packages. + /// + /// In en, this message translates to: + /// **'Packages'** + String get packages; + + /// No description provided for @packagesSubtitle. + /// + /// In en, this message translates to: + /// **'Install optional tools (Go, Homebrew, SSH)'** + String get packagesSubtitle; + + /// No description provided for @sshAccess. + /// + /// In en, this message translates to: + /// **'SSH Access'** + String get sshAccess; + + /// No description provided for @sshAccessSubtitle. + /// + /// In en, this message translates to: + /// **'Remote terminal access via SSH'** + String get sshAccessSubtitle; + + /// No description provided for @logs. + /// + /// In en, this message translates to: + /// **'Logs'** + String get logs; + + /// No description provided for @logsSubtitle. + /// + /// In en, this message translates to: + /// **'View gateway output and errors'** + String get logsSubtitle; + + /// No description provided for @snapshot. + /// + /// In en, this message translates to: + /// **'Snapshot'** + String get snapshot; + + /// No description provided for @snapshotSubtitle. + /// + /// In en, this message translates to: + /// **'Backup or restore your config'** + String get snapshotSubtitle; + + /// No description provided for @node. + /// + /// In en, this message translates to: + /// **'Node'** + String get node; + + /// No description provided for @nodeConnected. + /// + /// In en, this message translates to: + /// **'Connected to gateway'** + String get nodeConnected; + + /// No description provided for @nodeCapabilities. + /// + /// In en, this message translates to: + /// **'Device capabilities for AI'** + String get nodeCapabilities; + + /// No description provided for @dashboardUrlCopied. + /// + /// In en, this message translates to: + /// **'Dashboard URL copied'** + String get dashboardUrlCopied; + + /// No description provided for @copyDashboardUrl. + /// + /// In en, this message translates to: + /// **'Copy dashboard URL'** + String get copyDashboardUrl; + + /// No description provided for @cliProxy. + /// + /// In en, this message translates to: + /// **'CLIProxy Manager'** + String get cliProxy; + + /// No description provided for @cliProxySubtitle. + /// + /// In en, this message translates to: + /// **'Manage free AI account proxy'** + String get cliProxySubtitle; + + /// No description provided for @gateway. + /// + /// In en, this message translates to: + /// **'Gateway'** + String get gateway; + + /// No description provided for @startGateway. + /// + /// In en, this message translates to: + /// **'Start Gateway'** + String get startGateway; + + /// No description provided for @stopGateway. + /// + /// In en, this message translates to: + /// **'Stop Gateway'** + String get stopGateway; + + /// No description provided for @viewLogs. + /// + /// In en, this message translates to: + /// **'View Logs'** + String get viewLogs; + + /// No description provided for @urlCopied. + /// + /// In en, this message translates to: + /// **'URL copied to clipboard'** + String get urlCopied; + + /// No description provided for @copyUrl. + /// + /// In en, this message translates to: + /// **'Copy URL'** + String get copyUrl; + + /// No description provided for @openDashboard. + /// + /// In en, this message translates to: + /// **'Open dashboard'** + String get openDashboard; + + /// No description provided for @gatewayRunning. + /// + /// In en, this message translates to: + /// **'Running'** + String get gatewayRunning; + + /// No description provided for @gatewayStarting. + /// + /// In en, this message translates to: + /// **'Starting'** + String get gatewayStarting; + + /// No description provided for @gatewayError. + /// + /// In en, this message translates to: + /// **'Error'** + String get gatewayError; + + /// No description provided for @gatewayStopped. + /// + /// In en, this message translates to: + /// **'Stopped'** + String get gatewayStopped; + + /// No description provided for @enableNode. + /// + /// In en, this message translates to: + /// **'Enable Node'** + String get enableNode; + + /// No description provided for @disableNode. + /// + /// In en, this message translates to: + /// **'Disable Node'** + String get disableNode; + + /// No description provided for @reconnect. + /// + /// In en, this message translates to: + /// **'Reconnect'** + String get reconnect; + + /// No description provided for @nodePaired. + /// + /// In en, this message translates to: + /// **'Paired'** + String get nodePaired; + + /// No description provided for @nodeConnecting. + /// + /// In en, this message translates to: + /// **'Connecting'** + String get nodeConnecting; + + /// No description provided for @nodeDisconnected. + /// + /// In en, this message translates to: + /// **'Disconnected'** + String get nodeDisconnected; + + /// No description provided for @nodeDisabled. + /// + /// In en, this message translates to: + /// **'Disabled'** + String get nodeDisabled; + + /// No description provided for @nodeConfigure. + /// + /// In en, this message translates to: + /// **'Configure'** + String get nodeConfigure; + + /// No description provided for @settings. + /// + /// In en, this message translates to: + /// **'Settings'** + String get settings; + + /// No description provided for @general. + /// + /// In en, this message translates to: + /// **'GENERAL'** + String get general; + + /// No description provided for @autoStartGateway. + /// + /// In en, this message translates to: + /// **'Auto-start gateway'** + String get autoStartGateway; + + /// No description provided for @autoStartSubtitle. + /// + /// In en, this message translates to: + /// **'Start the gateway when the app opens'** + String get autoStartSubtitle; + + /// No description provided for @batteryOptimization. + /// + /// In en, this message translates to: + /// **'Battery Optimization'** + String get batteryOptimization; + + /// No description provided for @batteryOptimized. + /// + /// In en, this message translates to: + /// **'Optimized (may kill background sessions)'** + String get batteryOptimized; + + /// No description provided for @batteryUnrestricted. + /// + /// In en, this message translates to: + /// **'Unrestricted (recommended)'** + String get batteryUnrestricted; + + /// No description provided for @setupStorage. + /// + /// In en, this message translates to: + /// **'Setup Storage'** + String get setupStorage; + + /// No description provided for @storageGranted. + /// + /// In en, this message translates to: + /// **'Granted — proot can access /sdcard. Revoke if not needed.'** + String get storageGranted; + + /// No description provided for @storageNotGranted. + /// + /// In en, this message translates to: + /// **'Allow access to shared storage'** + String get storageNotGranted; + + /// No description provided for @nodeSection. + /// + /// In en, this message translates to: + /// **'NODE'** + String get nodeSection; + + /// No description provided for @enableNodeTitle. + /// + /// In en, this message translates to: + /// **'Enable Node'** + String get enableNodeTitle; + + /// No description provided for @enableNodeSubtitle. + /// + /// In en, this message translates to: + /// **'Provide device capabilities to the gateway'** + String get enableNodeSubtitle; + + /// No description provided for @nodeConfiguration. + /// + /// In en, this message translates to: + /// **'Node Configuration'** + String get nodeConfiguration; + + /// No description provided for @nodeConfigSubtitle. + /// + /// In en, this message translates to: + /// **'Connection, pairing, and capabilities'** + String get nodeConfigSubtitle; + + /// No description provided for @systemInfo. + /// + /// In en, this message translates to: + /// **'SYSTEM INFO'** + String get systemInfo; + + /// No description provided for @architecture. + /// + /// In en, this message translates to: + /// **'Architecture'** + String get architecture; + + /// No description provided for @prootPath. + /// + /// In en, this message translates to: + /// **'PRoot path'** + String get prootPath; + + /// No description provided for @rootfs. + /// + /// In en, this message translates to: + /// **'Rootfs'** + String get rootfs; + + /// No description provided for @installed. + /// + /// In en, this message translates to: + /// **'Installed'** + String get installed; + + /// No description provided for @notInstalled. + /// + /// In en, this message translates to: + /// **'Not installed'** + String get notInstalled; + + /// No description provided for @maintenance. + /// + /// In en, this message translates to: + /// **'MAINTENANCE'** + String get maintenance; + + /// No description provided for @exportSnapshot. + /// + /// In en, this message translates to: + /// **'Export Snapshot'** + String get exportSnapshot; + + /// No description provided for @exportSnapshotSubtitle. + /// + /// In en, this message translates to: + /// **'Backup config to Downloads'** + String get exportSnapshotSubtitle; + + /// No description provided for @importSnapshot. + /// + /// In en, this message translates to: + /// **'Import Snapshot'** + String get importSnapshot; + + /// No description provided for @importSnapshotSubtitle. + /// + /// In en, this message translates to: + /// **'Restore config from backup'** + String get importSnapshotSubtitle; + + /// No description provided for @rerunSetup. + /// + /// In en, this message translates to: + /// **'Re-run setup'** + String get rerunSetup; + + /// No description provided for @rerunSetupSubtitle. + /// + /// In en, this message translates to: + /// **'Reinstall or repair the environment'** + String get rerunSetupSubtitle; + + /// No description provided for @about. + /// + /// In en, this message translates to: + /// **'ABOUT'** + String get about; + + /// No description provided for @checkForUpdates. + /// + /// In en, this message translates to: + /// **'Check for Updates'** + String get checkForUpdates; + + /// No description provided for @checkUpdatesSubtitle. + /// + /// In en, this message translates to: + /// **'Check GitHub for a newer release'** + String get checkUpdatesSubtitle; + + /// No description provided for @developer. + /// + /// In en, this message translates to: + /// **'Developer'** + String get developer; + + /// No description provided for @github. + /// + /// In en, this message translates to: + /// **'GitHub'** + String get github; + + /// No description provided for @contact. + /// + /// In en, this message translates to: + /// **'Contact'** + String get contact; + + /// No description provided for @license. + /// + /// In en, this message translates to: + /// **'License'** + String get license; + + /// No description provided for @updateAvailable. + /// + /// In en, this message translates to: + /// **'Update Available'** + String get updateAvailable; + + /// No description provided for @currentVersion. + /// + /// In en, this message translates to: + /// **'Current'** + String get currentVersion; + + /// No description provided for @latestVersion. + /// + /// In en, this message translates to: + /// **'Latest'** + String get latestVersion; + + /// No description provided for @alreadyLatest. + /// + /// In en, this message translates to: + /// **'You\'re on the latest version'** + String get alreadyLatest; + + /// No description provided for @checkUpdateFailed. + /// + /// In en, this message translates to: + /// **'Could not check for updates'** + String get checkUpdateFailed; + + /// No description provided for @snapshotSaved. + /// + /// In en, this message translates to: + /// **'Snapshot saved to'** + String get snapshotSaved; + + /// No description provided for @exportFailed. + /// + /// In en, this message translates to: + /// **'Export failed'** + String get exportFailed; + + /// No description provided for @noSnapshotFound. + /// + /// In en, this message translates to: + /// **'No snapshot found at'** + String get noSnapshotFound; + + /// No description provided for @snapshotRestored. + /// + /// In en, this message translates to: + /// **'Snapshot restored successfully. Restart the gateway to apply.'** + String get snapshotRestored; + + /// No description provided for @importFailed. + /// + /// In en, this message translates to: + /// **'Import failed'** + String get importFailed; + + /// No description provided for @setupOpenClaw. + /// + /// In en, this message translates to: + /// **'Setup OpenClaw'** + String get setupOpenClaw; + + /// No description provided for @setupRunning. + /// + /// In en, this message translates to: + /// **'Setting up the environment. This may take several minutes.'** + String get setupRunning; + + /// No description provided for @setupDescription. + /// + /// In en, this message translates to: + /// **'This will download Ubuntu, Node.js, and OpenClaw into a self-contained environment.'** + String get setupDescription; + + /// No description provided for @downloadRootfs. + /// + /// In en, this message translates to: + /// **'Download Ubuntu rootfs'** + String get downloadRootfs; + + /// No description provided for @extractRootfs. + /// + /// In en, this message translates to: + /// **'Extract rootfs'** + String get extractRootfs; + + /// No description provided for @installNode. + /// + /// In en, this message translates to: + /// **'Install Node.js'** + String get installNode; + + /// No description provided for @installOpenClaw. + /// + /// In en, this message translates to: + /// **'Install OpenClaw'** + String get installOpenClaw; + + /// No description provided for @configureBionicBypass. + /// + /// In en, this message translates to: + /// **'Configure Bionic Bypass'** + String get configureBionicBypass; + + /// No description provided for @setupComplete. + /// + /// In en, this message translates to: + /// **'Setup complete!'** + String get setupComplete; + + /// No description provided for @configureApiKeys. + /// + /// In en, this message translates to: + /// **'Configure API Keys'** + String get configureApiKeys; + + /// No description provided for @beginSetup. + /// + /// In en, this message translates to: + /// **'Begin Setup'** + String get beginSetup; + + /// No description provided for @retrySetup. + /// + /// In en, this message translates to: + /// **'Retry Setup'** + String get retrySetup; + + /// No description provided for @storageRequired. + /// + /// In en, this message translates to: + /// **'Requires ~500MB of storage and an internet connection'** + String get storageRequired; + + /// No description provided for @optionalPackages. + /// + /// In en, this message translates to: + /// **'OPTIONAL PACKAGES'** + String get optionalPackages; + + /// No description provided for @gatewayLogs. + /// + /// In en, this message translates to: + /// **'Gateway Logs'** + String get gatewayLogs; + + /// No description provided for @filterLogs. + /// + /// In en, this message translates to: + /// **'Filter logs...'** + String get filterLogs; + + /// No description provided for @noLogsYet. + /// + /// In en, this message translates to: + /// **'No logs yet. Start the gateway.'** + String get noLogsYet; + + /// No description provided for @noMatchingLogs. + /// + /// In en, this message translates to: + /// **'No matching logs.'** + String get noMatchingLogs; + + /// No description provided for @copyAllLogs. + /// + /// In en, this message translates to: + /// **'Copy all logs'** + String get copyAllLogs; + + /// No description provided for @autoScrollOn. + /// + /// In en, this message translates to: + /// **'Auto-scroll on'** + String get autoScrollOn; + + /// No description provided for @autoScrollOff. + /// + /// In en, this message translates to: + /// **'Auto-scroll off'** + String get autoScrollOff; + + /// No description provided for @activeModel. + /// + /// In en, this message translates to: + /// **'Active Model'** + String get activeModel; + + /// No description provided for @selectProvider. + /// + /// In en, this message translates to: + /// **'Select a provider to configure its API key and model.'** + String get selectProvider; + + /// No description provided for @active. + /// + /// In en, this message translates to: + /// **'Active'** + String get active; + + /// No description provided for @configured. + /// + /// In en, this message translates to: + /// **'Configured'** + String get configured; + + /// No description provided for @apiKey. + /// + /// In en, this message translates to: + /// **'API Key'** + String get apiKey; + + /// No description provided for @model. + /// + /// In en, this message translates to: + /// **'Model'** + String get model; + + /// No description provided for @customModel. + /// + /// In en, this message translates to: + /// **'Custom...'** + String get customModel; + + /// No description provided for @customModelHint. + /// + /// In en, this message translates to: + /// **'e.g. meta/llama-3.3-70b-instruct'** + String get customModelHint; + + /// No description provided for @customModelLabel. + /// + /// In en, this message translates to: + /// **'Custom model name'** + String get customModelLabel; + + /// No description provided for @saveAndActivate. + /// + /// In en, this message translates to: + /// **'Save & Activate'** + String get saveAndActivate; + + /// No description provided for @removeConfiguration. + /// + /// In en, this message translates to: + /// **'Remove Configuration'** + String get removeConfiguration; + + /// No description provided for @apiKeyEmpty. + /// + /// In en, this message translates to: + /// **'API key cannot be empty'** + String get apiKeyEmpty; + + /// No description provided for @modelEmpty. + /// + /// In en, this message translates to: + /// **'Model name cannot be empty'** + String get modelEmpty; + + /// No description provided for @configuredAndActivated. + /// + /// In en, this message translates to: + /// **'configured and activated'** + String get configuredAndActivated; + + /// No description provided for @saveFailed. + /// + /// In en, this message translates to: + /// **'Failed to save'** + String get saveFailed; + + /// No description provided for @removeFailed. + /// + /// In en, this message translates to: + /// **'Failed to remove'** + String get removeFailed; + + /// No description provided for @removeProvider. + /// + /// In en, this message translates to: + /// **'Remove'** + String get removeProvider; + + /// No description provided for @removeProviderContent. + /// + /// In en, this message translates to: + /// **'This will delete the API key and deactivate the model.'** + String get removeProviderContent; + + /// No description provided for @startingTerminal. + /// + /// In en, this message translates to: + /// **'Starting terminal...'** + String get startingTerminal; + + /// No description provided for @failedToStartTerminal. + /// + /// In en, this message translates to: + /// **'Failed to start terminal'** + String get failedToStartTerminal; + + /// No description provided for @openClawOnboarding. + /// + /// In en, this message translates to: + /// **'OpenClaw Onboarding'** + String get openClawOnboarding; + + /// No description provided for @startingOnboarding. + /// + /// In en, this message translates to: + /// **'Starting onboarding...'** + String get startingOnboarding; + + /// No description provided for @failedToStartOnboarding. + /// + /// In en, this message translates to: + /// **'Failed to start onboarding'** + String get failedToStartOnboarding; + + /// No description provided for @goToDashboard. + /// + /// In en, this message translates to: + /// **'Go to Dashboard'** + String get goToDashboard; + + /// No description provided for @cliProxyManagement. + /// + /// In en, this message translates to: + /// **'CLIProxy Management'** + String get cliProxyManagement; + + /// No description provided for @cliProxyNotRunning. + /// + /// In en, this message translates to: + /// **'CLIProxy service is not running'** + String get cliProxyNotRunning; + + /// No description provided for @openInBrowser. + /// + /// In en, this message translates to: + /// **'Open in browser'** + String get openInBrowser; + + /// No description provided for @refresh. + /// + /// In en, this message translates to: + /// **'Refresh'** + String get refresh; + + /// No description provided for @reconnectProxy. + /// + /// In en, this message translates to: + /// **'Reconnect'** + String get reconnectProxy; + + /// No description provided for @installedBadge. + /// + /// In en, this message translates to: + /// **'Installed'** + String get installedBadge; +} + +class _AppLocalizationsDelegate + extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) => + ['en', 'zh'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} + +AppLocalizations lookupAppLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'en': + return AppLocalizationsEn(); + case 'zh': + return AppLocalizationsZh(); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); +} diff --git a/flutter_app/lib/l10n/app_localizations_en.dart b/flutter_app/lib/l10n/app_localizations_en.dart new file mode 100644 index 0000000..76839e9 --- /dev/null +++ b/flutter_app/lib/l10n/app_localizations_en.dart @@ -0,0 +1,521 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for English (`en`). +class AppLocalizationsEn extends AppLocalizations { + AppLocalizationsEn([String locale = 'en']) : super(locale); + + @override + String get appName => 'OpenClaw'; + + @override + String get cancel => 'Cancel'; + + @override + String get confirm => 'Confirm'; + + @override + String get retry => 'Retry'; + + @override + String get done => 'Done'; + + @override + String get save => 'Save'; + + @override + String get remove => 'Remove'; + + @override + String get install => 'Install'; + + @override + String get loading => 'Loading...'; + + @override + String get error => 'Error'; + + @override + String get copy => 'Copy'; + + @override + String get paste => 'Paste'; + + @override + String get openUrl => 'Open URL'; + + @override + String get screenshot => 'Screenshot'; + + @override + String get restart => 'Restart'; + + @override + String get later => 'Later'; + + @override + String get download => 'Download'; + + @override + String get copied => 'Copied to clipboard'; + + @override + String get noUrlFound => 'No URL found in selection'; + + @override + String get linkCopied => 'Link copied'; + + @override + String get openLink => 'Open Link'; + + @override + String get aiGatewayForAndroid => 'AI Gateway for Android'; + + @override + String get checkingSetup => 'Checking setup status...'; + + @override + String get repairingBypass => 'Repairing bionic bypass...'; + + @override + String get reinstallingNode => 'Reinstalling Node.js...'; + + @override + String get reinstallingOpenClaw => 'Reinstalling OpenClaw...'; + + @override + String get quickActions => 'QUICK ACTIONS'; + + @override + String get terminal => 'Terminal'; + + @override + String get terminalSubtitle => 'Open Ubuntu shell with OpenClaw'; + + @override + String get webDashboard => 'Web Dashboard'; + + @override + String get webDashboardSubtitle => 'Open OpenClaw dashboard in browser'; + + @override + String get startGatewayFirst => 'Start gateway first'; + + @override + String get onboarding => 'Onboarding'; + + @override + String get onboardingSubtitle => 'Configure API keys and binding'; + + @override + String get configure => 'Configure'; + + @override + String get configureSubtitle => 'Manage gateway settings'; + + @override + String get aiProviders => 'AI Providers'; + + @override + String get aiProvidersSubtitle => 'Configure models and API keys'; + + @override + String get packages => 'Packages'; + + @override + String get packagesSubtitle => 'Install optional tools (Go, Homebrew, SSH)'; + + @override + String get sshAccess => 'SSH Access'; + + @override + String get sshAccessSubtitle => 'Remote terminal access via SSH'; + + @override + String get logs => 'Logs'; + + @override + String get logsSubtitle => 'View gateway output and errors'; + + @override + String get snapshot => 'Snapshot'; + + @override + String get snapshotSubtitle => 'Backup or restore your config'; + + @override + String get node => 'Node'; + + @override + String get nodeConnected => 'Connected to gateway'; + + @override + String get nodeCapabilities => 'Device capabilities for AI'; + + @override + String get dashboardUrlCopied => 'Dashboard URL copied'; + + @override + String get copyDashboardUrl => 'Copy dashboard URL'; + + @override + String get cliProxy => 'CLIProxy Manager'; + + @override + String get cliProxySubtitle => 'Manage free AI account proxy'; + + @override + String get gateway => 'Gateway'; + + @override + String get startGateway => 'Start Gateway'; + + @override + String get stopGateway => 'Stop Gateway'; + + @override + String get viewLogs => 'View Logs'; + + @override + String get urlCopied => 'URL copied to clipboard'; + + @override + String get copyUrl => 'Copy URL'; + + @override + String get openDashboard => 'Open dashboard'; + + @override + String get gatewayRunning => 'Running'; + + @override + String get gatewayStarting => 'Starting'; + + @override + String get gatewayError => 'Error'; + + @override + String get gatewayStopped => 'Stopped'; + + @override + String get enableNode => 'Enable Node'; + + @override + String get disableNode => 'Disable Node'; + + @override + String get reconnect => 'Reconnect'; + + @override + String get nodePaired => 'Paired'; + + @override + String get nodeConnecting => 'Connecting'; + + @override + String get nodeDisconnected => 'Disconnected'; + + @override + String get nodeDisabled => 'Disabled'; + + @override + String get nodeConfigure => 'Configure'; + + @override + String get settings => 'Settings'; + + @override + String get general => 'GENERAL'; + + @override + String get autoStartGateway => 'Auto-start gateway'; + + @override + String get autoStartSubtitle => 'Start the gateway when the app opens'; + + @override + String get batteryOptimization => 'Battery Optimization'; + + @override + String get batteryOptimized => 'Optimized (may kill background sessions)'; + + @override + String get batteryUnrestricted => 'Unrestricted (recommended)'; + + @override + String get setupStorage => 'Setup Storage'; + + @override + String get storageGranted => + 'Granted — proot can access /sdcard. Revoke if not needed.'; + + @override + String get storageNotGranted => 'Allow access to shared storage'; + + @override + String get nodeSection => 'NODE'; + + @override + String get enableNodeTitle => 'Enable Node'; + + @override + String get enableNodeSubtitle => 'Provide device capabilities to the gateway'; + + @override + String get nodeConfiguration => 'Node Configuration'; + + @override + String get nodeConfigSubtitle => 'Connection, pairing, and capabilities'; + + @override + String get systemInfo => 'SYSTEM INFO'; + + @override + String get architecture => 'Architecture'; + + @override + String get prootPath => 'PRoot path'; + + @override + String get rootfs => 'Rootfs'; + + @override + String get installed => 'Installed'; + + @override + String get notInstalled => 'Not installed'; + + @override + String get maintenance => 'MAINTENANCE'; + + @override + String get exportSnapshot => 'Export Snapshot'; + + @override + String get exportSnapshotSubtitle => 'Backup config to Downloads'; + + @override + String get importSnapshot => 'Import Snapshot'; + + @override + String get importSnapshotSubtitle => 'Restore config from backup'; + + @override + String get rerunSetup => 'Re-run setup'; + + @override + String get rerunSetupSubtitle => 'Reinstall or repair the environment'; + + @override + String get about => 'ABOUT'; + + @override + String get checkForUpdates => 'Check for Updates'; + + @override + String get checkUpdatesSubtitle => 'Check GitHub for a newer release'; + + @override + String get developer => 'Developer'; + + @override + String get github => 'GitHub'; + + @override + String get contact => 'Contact'; + + @override + String get license => 'License'; + + @override + String get updateAvailable => 'Update Available'; + + @override + String get currentVersion => 'Current'; + + @override + String get latestVersion => 'Latest'; + + @override + String get alreadyLatest => 'You\'re on the latest version'; + + @override + String get checkUpdateFailed => 'Could not check for updates'; + + @override + String get snapshotSaved => 'Snapshot saved to'; + + @override + String get exportFailed => 'Export failed'; + + @override + String get noSnapshotFound => 'No snapshot found at'; + + @override + String get snapshotRestored => + 'Snapshot restored successfully. Restart the gateway to apply.'; + + @override + String get importFailed => 'Import failed'; + + @override + String get setupOpenClaw => 'Setup OpenClaw'; + + @override + String get setupRunning => + 'Setting up the environment. This may take several minutes.'; + + @override + String get setupDescription => + 'This will download Ubuntu, Node.js, and OpenClaw into a self-contained environment.'; + + @override + String get downloadRootfs => 'Download Ubuntu rootfs'; + + @override + String get extractRootfs => 'Extract rootfs'; + + @override + String get installNode => 'Install Node.js'; + + @override + String get installOpenClaw => 'Install OpenClaw'; + + @override + String get configureBionicBypass => 'Configure Bionic Bypass'; + + @override + String get setupComplete => 'Setup complete!'; + + @override + String get configureApiKeys => 'Configure API Keys'; + + @override + String get beginSetup => 'Begin Setup'; + + @override + String get retrySetup => 'Retry Setup'; + + @override + String get storageRequired => + 'Requires ~500MB of storage and an internet connection'; + + @override + String get optionalPackages => 'OPTIONAL PACKAGES'; + + @override + String get gatewayLogs => 'Gateway Logs'; + + @override + String get filterLogs => 'Filter logs...'; + + @override + String get noLogsYet => 'No logs yet. Start the gateway.'; + + @override + String get noMatchingLogs => 'No matching logs.'; + + @override + String get copyAllLogs => 'Copy all logs'; + + @override + String get autoScrollOn => 'Auto-scroll on'; + + @override + String get autoScrollOff => 'Auto-scroll off'; + + @override + String get activeModel => 'Active Model'; + + @override + String get selectProvider => + 'Select a provider to configure its API key and model.'; + + @override + String get active => 'Active'; + + @override + String get configured => 'Configured'; + + @override + String get apiKey => 'API Key'; + + @override + String get model => 'Model'; + + @override + String get customModel => 'Custom...'; + + @override + String get customModelHint => 'e.g. meta/llama-3.3-70b-instruct'; + + @override + String get customModelLabel => 'Custom model name'; + + @override + String get saveAndActivate => 'Save & Activate'; + + @override + String get removeConfiguration => 'Remove Configuration'; + + @override + String get apiKeyEmpty => 'API key cannot be empty'; + + @override + String get modelEmpty => 'Model name cannot be empty'; + + @override + String get configuredAndActivated => 'configured and activated'; + + @override + String get saveFailed => 'Failed to save'; + + @override + String get removeFailed => 'Failed to remove'; + + @override + String get removeProvider => 'Remove'; + + @override + String get removeProviderContent => + 'This will delete the API key and deactivate the model.'; + + @override + String get startingTerminal => 'Starting terminal...'; + + @override + String get failedToStartTerminal => 'Failed to start terminal'; + + @override + String get openClawOnboarding => 'OpenClaw Onboarding'; + + @override + String get startingOnboarding => 'Starting onboarding...'; + + @override + String get failedToStartOnboarding => 'Failed to start onboarding'; + + @override + String get goToDashboard => 'Go to Dashboard'; + + @override + String get cliProxyManagement => 'CLIProxy Management'; + + @override + String get cliProxyNotRunning => 'CLIProxy service is not running'; + + @override + String get openInBrowser => 'Open in browser'; + + @override + String get refresh => 'Refresh'; + + @override + String get reconnectProxy => 'Reconnect'; + + @override + String get installedBadge => 'Installed'; +} diff --git a/flutter_app/lib/l10n/app_localizations_zh.dart b/flutter_app/lib/l10n/app_localizations_zh.dart new file mode 100644 index 0000000..1cefea7 --- /dev/null +++ b/flutter_app/lib/l10n/app_localizations_zh.dart @@ -0,0 +1,514 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Chinese (`zh`). +class AppLocalizationsZh extends AppLocalizations { + AppLocalizationsZh([String locale = 'zh']) : super(locale); + + @override + String get appName => 'OpenClaw'; + + @override + String get cancel => '取消'; + + @override + String get confirm => '确认'; + + @override + String get retry => '重试'; + + @override + String get done => '完成'; + + @override + String get save => '保存'; + + @override + String get remove => '移除'; + + @override + String get install => '安装'; + + @override + String get loading => '加载中...'; + + @override + String get error => '错误'; + + @override + String get copy => '复制'; + + @override + String get paste => '粘贴'; + + @override + String get openUrl => '打开链接'; + + @override + String get screenshot => '截图'; + + @override + String get restart => '重启'; + + @override + String get later => '稍后'; + + @override + String get download => '下载'; + + @override + String get copied => '已复制到剪贴板'; + + @override + String get noUrlFound => '未找到链接'; + + @override + String get linkCopied => '链接已复制'; + + @override + String get openLink => '打开链接'; + + @override + String get aiGatewayForAndroid => 'Android AI 网关'; + + @override + String get checkingSetup => '检查安装状态...'; + + @override + String get repairingBypass => '修复 Bionic Bypass...'; + + @override + String get reinstallingNode => '重新安装 Node.js...'; + + @override + String get reinstallingOpenClaw => '重新安装 OpenClaw...'; + + @override + String get quickActions => '快捷操作'; + + @override + String get terminal => '终端'; + + @override + String get terminalSubtitle => '打开 Ubuntu Shell'; + + @override + String get webDashboard => 'Web 控制台'; + + @override + String get webDashboardSubtitle => '在浏览器中打开 OpenClaw 控制台'; + + @override + String get startGatewayFirst => '请先启动网关'; + + @override + String get onboarding => '初始配置'; + + @override + String get onboardingSubtitle => '配置 API 密钥和绑定设置'; + + @override + String get configure => '网关配置'; + + @override + String get configureSubtitle => '管理网关设置'; + + @override + String get aiProviders => 'AI 提供商'; + + @override + String get aiProvidersSubtitle => '配置模型和 API 密钥'; + + @override + String get packages => '扩展包'; + + @override + String get packagesSubtitle => '安装可选工具 (Go, Homebrew, SSH)'; + + @override + String get sshAccess => 'SSH 访问'; + + @override + String get sshAccessSubtitle => '通过 SSH 远程访问终端'; + + @override + String get logs => '日志'; + + @override + String get logsSubtitle => '查看网关输出和错误'; + + @override + String get snapshot => '快照'; + + @override + String get snapshotSubtitle => '备份或恢复配置'; + + @override + String get node => '节点'; + + @override + String get nodeConnected => '已连接到网关'; + + @override + String get nodeCapabilities => '为 AI 提供设备能力'; + + @override + String get dashboardUrlCopied => '控制台链接已复制'; + + @override + String get copyDashboardUrl => '复制控制台链接'; + + @override + String get cliProxy => 'CLIProxy 管理'; + + @override + String get cliProxySubtitle => '管理免费 AI 账号代理'; + + @override + String get gateway => '网关'; + + @override + String get startGateway => '启动网关'; + + @override + String get stopGateway => '停止网关'; + + @override + String get viewLogs => '查看日志'; + + @override + String get urlCopied => '链接已复制'; + + @override + String get copyUrl => '复制链接'; + + @override + String get openDashboard => '打开控制台'; + + @override + String get gatewayRunning => '运行中'; + + @override + String get gatewayStarting => '启动中'; + + @override + String get gatewayError => '错误'; + + @override + String get gatewayStopped => '已停止'; + + @override + String get enableNode => '启用节点'; + + @override + String get disableNode => '禁用节点'; + + @override + String get reconnect => '重新连接'; + + @override + String get nodePaired => '已配对'; + + @override + String get nodeConnecting => '连接中'; + + @override + String get nodeDisconnected => '已断开'; + + @override + String get nodeDisabled => '已禁用'; + + @override + String get nodeConfigure => '配置'; + + @override + String get settings => '设置'; + + @override + String get general => '通用'; + + @override + String get autoStartGateway => '自动启动网关'; + + @override + String get autoStartSubtitle => '应用打开时自动启动网关'; + + @override + String get batteryOptimization => '电池优化'; + + @override + String get batteryOptimized => '已优化(可能终止后台会话)'; + + @override + String get batteryUnrestricted => '无限制(推荐)'; + + @override + String get setupStorage => '存储权限'; + + @override + String get storageGranted => '已授权 — proot 可访问 /sdcard,不需要时请撤销'; + + @override + String get storageNotGranted => '允许访问共享存储'; + + @override + String get nodeSection => '节点'; + + @override + String get enableNodeTitle => '启用节点'; + + @override + String get enableNodeSubtitle => '为网关提供设备能力'; + + @override + String get nodeConfiguration => '节点配置'; + + @override + String get nodeConfigSubtitle => '连接、配对和能力设置'; + + @override + String get systemInfo => '系统信息'; + + @override + String get architecture => '架构'; + + @override + String get prootPath => 'PRoot 路径'; + + @override + String get rootfs => '根文件系统'; + + @override + String get installed => '已安装'; + + @override + String get notInstalled => '未安装'; + + @override + String get maintenance => '维护'; + + @override + String get exportSnapshot => '导出快照'; + + @override + String get exportSnapshotSubtitle => '备份配置到下载目录'; + + @override + String get importSnapshot => '导入快照'; + + @override + String get importSnapshotSubtitle => '从备份恢复配置'; + + @override + String get rerunSetup => '重新安装'; + + @override + String get rerunSetupSubtitle => '重新安装或修复环境'; + + @override + String get about => '关于'; + + @override + String get checkForUpdates => '检查更新'; + + @override + String get checkUpdatesSubtitle => '在 GitHub 检查新版本'; + + @override + String get developer => '开发者'; + + @override + String get github => 'GitHub'; + + @override + String get contact => '联系方式'; + + @override + String get license => '许可证'; + + @override + String get updateAvailable => '发现新版本'; + + @override + String get currentVersion => '当前版本'; + + @override + String get latestVersion => '最新版本'; + + @override + String get alreadyLatest => '已是最新版本'; + + @override + String get checkUpdateFailed => '无法检查更新'; + + @override + String get snapshotSaved => '快照已保存至'; + + @override + String get exportFailed => '导出失败'; + + @override + String get noSnapshotFound => '未找到快照文件'; + + @override + String get snapshotRestored => '快照已恢复,重启网关以应用更改'; + + @override + String get importFailed => '导入失败'; + + @override + String get setupOpenClaw => '安装 OpenClaw'; + + @override + String get setupRunning => '正在配置环境,可能需要几分钟。'; + + @override + String get setupDescription => '将下载 Ubuntu、Node.js 和 OpenClaw 到独立环境中。'; + + @override + String get downloadRootfs => '下载 Ubuntu 根文件系统'; + + @override + String get extractRootfs => '解压根文件系统'; + + @override + String get installNode => '安装 Node.js'; + + @override + String get installOpenClaw => '安装 OpenClaw'; + + @override + String get configureBionicBypass => '配置 Bionic Bypass'; + + @override + String get setupComplete => '安装完成!'; + + @override + String get configureApiKeys => '配置 API 密钥'; + + @override + String get beginSetup => '开始安装'; + + @override + String get retrySetup => '重试安装'; + + @override + String get storageRequired => '需要约 500MB 存储空间和网络连接'; + + @override + String get optionalPackages => '可选扩展包'; + + @override + String get gatewayLogs => '网关日志'; + + @override + String get filterLogs => '过滤日志...'; + + @override + String get noLogsYet => '暂无日志,请启动网关。'; + + @override + String get noMatchingLogs => '没有匹配的日志。'; + + @override + String get copyAllLogs => '复制全部日志'; + + @override + String get autoScrollOn => '自动滚动已开启'; + + @override + String get autoScrollOff => '自动滚动已关闭'; + + @override + String get activeModel => '当前模型'; + + @override + String get selectProvider => '选择提供商配置 API 密钥和模型。'; + + @override + String get active => '使用中'; + + @override + String get configured => '已配置'; + + @override + String get apiKey => 'API 密钥'; + + @override + String get model => '模型'; + + @override + String get customModel => '自定义...'; + + @override + String get customModelHint => '例如:meta/llama-3.3-70b-instruct'; + + @override + String get customModelLabel => '自定义模型名称'; + + @override + String get saveAndActivate => '保存并激活'; + + @override + String get removeConfiguration => '移除配置'; + + @override + String get apiKeyEmpty => 'API 密钥不能为空'; + + @override + String get modelEmpty => '模型名称不能为空'; + + @override + String get configuredAndActivated => '已配置并激活'; + + @override + String get saveFailed => '保存失败'; + + @override + String get removeFailed => '移除失败'; + + @override + String get removeProvider => '移除提供商'; + + @override + String get removeProviderContent => '这将删除 API 密钥并停用该模型。'; + + @override + String get startingTerminal => '正在启动终端...'; + + @override + String get failedToStartTerminal => '启动终端失败'; + + @override + String get openClawOnboarding => 'OpenClaw 初始配置'; + + @override + String get startingOnboarding => '正在启动配置向导...'; + + @override + String get failedToStartOnboarding => '启动配置向导失败'; + + @override + String get goToDashboard => '前往控制台'; + + @override + String get cliProxyManagement => 'CLIProxy 管理中心'; + + @override + String get cliProxyNotRunning => 'CLIProxy 服务未运行'; + + @override + String get openInBrowser => '在浏览器中打开'; + + @override + String get refresh => '刷新'; + + @override + String get reconnectProxy => '重新连接'; + + @override + String get installedBadge => '已安装'; +} diff --git a/flutter_app/lib/l10n/app_strings.dart b/flutter_app/lib/l10n/app_strings.dart new file mode 100644 index 0000000..4c42dc4 --- /dev/null +++ b/flutter_app/lib/l10n/app_strings.dart @@ -0,0 +1,381 @@ +import 'dart:ui'; + +class AppStrings { + AppStrings._(); + + static bool get _isChinese => + PlatformDispatcher.instance.locale.languageCode == 'zh'; + + static bool get isChinese => _isChinese; + + static String get appName => 'OpenClaw'; + static String get cancel => _isChinese ? '取消' : 'Cancel'; + static String get retry => _isChinese ? '重试' : 'Retry'; + static String get remove => _isChinese ? '移除' : 'Remove'; + static String get done => _isChinese ? '完成' : 'Done'; + static String get install => _isChinese ? '安装' : 'Install'; + static String get loading => _isChinese ? '加载中...' : 'Loading...'; + static String get copy => _isChinese ? '复制' : 'Copy'; + static String get paste => _isChinese ? '粘贴' : 'Paste'; + static String get openUrl => _isChinese ? '打开链接' : 'Open URL'; + static String get screenshot => _isChinese ? '截图' : 'Screenshot'; + static String get restart => _isChinese ? '重启' : 'Restart'; + static String get later => _isChinese ? '稍后' : 'Later'; + static String get download => _isChinese ? '下载' : 'Download'; + static String get copied => _isChinese ? '已复制到剪贴板' : 'Copied to clipboard'; + static String get noUrlFound => + _isChinese ? '未找到链接' : 'No URL found in selection'; + static String get linkCopied => _isChinese ? '链接已复制' : 'Link copied'; + + static String get aiGatewayForAndroid => + _isChinese ? 'Android AI 网关' : 'AI Gateway for Android'; + static String get checkingSetup => + _isChinese ? '检查安装状态...' : 'Checking setup status...'; + static String get repairingBypass => + _isChinese ? '修复 Bionic Bypass...' : 'Repairing bionic bypass...'; + static String get reinstallingNode => + _isChinese ? '重新安装 Node.js...' : 'Reinstalling Node.js...'; + static String get reinstallingOpenClaw => + _isChinese ? '重新安装 OpenClaw...' : 'Reinstalling OpenClaw...'; + + static String get quickActions => _isChinese ? '快捷操作' : 'QUICK ACTIONS'; + static String get terminal => _isChinese ? '终端' : 'Terminal'; + static String get terminalSubtitle => + _isChinese ? '打开 Ubuntu Shell' : 'Open Ubuntu shell with OpenClaw'; + static String get webDashboard => _isChinese ? 'Web 控制台' : 'Web Dashboard'; + static String get webDashboardSubtitle => _isChinese + ? '在浏览器中打开 OpenClaw 控制台' + : 'Open OpenClaw dashboard in browser'; + static String get startGatewayFirst => + _isChinese ? '请先启动网关' : 'Start gateway first'; + static String get onboarding => _isChinese ? '初始配置' : 'Onboarding'; + static String get onboardingSubtitle => + _isChinese ? '配置 API 密钥和绑定设置' : 'Configure API keys and binding'; + static String get configure => _isChinese ? '网关配置' : 'Configure'; + static String get configureSubtitle => + _isChinese ? '管理网关设置' : 'Manage gateway settings'; + static String get aiProviders => _isChinese ? 'AI 提供商' : 'AI Providers'; + static String get aiProvidersSubtitle => + _isChinese ? '配置模型和 API 密钥' : 'Configure models and API keys'; + static String get packages => _isChinese ? '扩展包' : 'Packages'; + static String get packagesSubtitle => _isChinese + ? '安装可选工具 (Go, Homebrew, SSH)' + : 'Install optional tools (Go, Homebrew, SSH)'; + static String get sshAccess => _isChinese ? 'SSH 访问' : 'SSH Access'; + static String get sshAccessSubtitle => + _isChinese ? '通过 SSH 远程访问终端' : 'Remote terminal access via SSH'; + static String get logs => _isChinese ? '日志' : 'Logs'; + static String get logsSubtitle => + _isChinese ? '查看网关输出和错误' : 'View gateway output and errors'; + static String get snapshot => _isChinese ? '快照' : 'Snapshot'; + static String get snapshotSubtitle => + _isChinese ? '备份或恢复配置' : 'Backup or restore your config'; + static String get node => _isChinese ? '节点' : 'Node'; + static String get nodeConnected => + _isChinese ? '已连接到网关' : 'Connected to gateway'; + static String get nodeCapabilities => + _isChinese ? '为 AI 提供设备能力' : 'Device capabilities for AI'; + static String get dashboardUrlCopied => + _isChinese ? '控制台链接已复制' : 'Dashboard URL copied'; + static String get copyDashboardUrl => + _isChinese ? '复制控制台链接' : 'Copy dashboard URL'; + static String get cliProxy => _isChinese ? 'CLIProxy 管理' : 'CLIProxy Manager'; + static String get cliProxySubtitle => + _isChinese ? '管理免费 AI 账号代理' : 'Manage free AI account proxy'; + + static String get gateway => _isChinese ? '网关' : 'Gateway'; + static String get startGateway => _isChinese ? '启动网关' : 'Start Gateway'; + static String get stopGateway => _isChinese ? '停止网关' : 'Stop Gateway'; + static String get viewLogs => _isChinese ? '查看日志' : 'View Logs'; + static String get urlCopied => + _isChinese ? '链接已复制' : 'URL copied to clipboard'; + static String get copyUrl => _isChinese ? '复制链接' : 'Copy URL'; + static String get openDashboard => _isChinese ? '打开控制台' : 'Open dashboard'; + static String get gatewayRunning => _isChinese ? '运行中' : 'Running'; + static String get gatewayStarting => _isChinese ? '启动中' : 'Starting'; + static String get gatewayError => _isChinese ? '错误' : 'Error'; + static String get gatewayStopped => _isChinese ? '已停止' : 'Stopped'; + + static String get enableNode => _isChinese ? '启用节点' : 'Enable Node'; + static String get disableNode => _isChinese ? '禁用节点' : 'Disable Node'; + static String get reconnect => _isChinese ? '重新连接' : 'Reconnect'; + static String get nodePaired => _isChinese ? '已配对' : 'Paired'; + static String get nodeConnecting => _isChinese ? '连接中' : 'Connecting'; + static String get nodeDisconnected => _isChinese ? '已断开' : 'Disconnected'; + static String get nodeDisabled => _isChinese ? '已禁用' : 'Disabled'; + static String get nodeConfigure => _isChinese ? '配置' : 'Configure'; + + static String get settings => _isChinese ? '设置' : 'Settings'; + static String get general => _isChinese ? '通用' : 'GENERAL'; + static String get autoStartGateway => + _isChinese ? '自动启动网关' : 'Auto-start gateway'; + static String get autoStartSubtitle => + _isChinese ? '应用打开时自动启动网关' : 'Start the gateway when the app opens'; + static String get batteryOptimization => + _isChinese ? '电池优化' : 'Battery Optimization'; + static String get batteryOptimized => + _isChinese ? '已优化(可能终止后台会话)' : 'Optimized (may kill background sessions)'; + static String get batteryUnrestricted => + _isChinese ? '无限制(推荐)' : 'Unrestricted (recommended)'; + static String get setupStorage => _isChinese ? '存储权限' : 'Setup Storage'; + static String get storageGranted => _isChinese + ? '已授权 — proot 可访问 /sdcard,不需要时请撤销' + : 'Granted — proot can access /sdcard. Revoke if not needed.'; + static String get storageNotGranted => + _isChinese ? '允许访问共享存储' : 'Allow access to shared storage'; + static String get nodeSection => _isChinese ? '节点' : 'NODE'; + static String get enableNodeTitle => _isChinese ? '启用节点' : 'Enable Node'; + static String get enableNodeSubtitle => + _isChinese ? '为网关提供设备能力' : 'Provide device capabilities to the gateway'; + static String get nodeConfiguration => + _isChinese ? '节点配置' : 'Node Configuration'; + static String get nodeConfigSubtitle => + _isChinese ? '连接、配对和能力设置' : 'Connection, pairing, and capabilities'; + static String get systemInfo => _isChinese ? '系统信息' : 'SYSTEM INFO'; + static String get architecture => _isChinese ? '架构' : 'Architecture'; + static String get prootPath => _isChinese ? 'PRoot 路径' : 'PRoot path'; + static String get rootfs => _isChinese ? '根文件系统' : 'Rootfs'; + static String get installed => _isChinese ? '已安装' : 'Installed'; + static String get notInstalled => _isChinese ? '未安装' : 'Not installed'; + static String get maintenance => _isChinese ? '维护' : 'MAINTENANCE'; + static String get exportSnapshot => _isChinese ? '导出快照' : 'Export Snapshot'; + static String get exportSnapshotSubtitle => + _isChinese ? '备份配置到下载目录' : 'Backup config to Downloads'; + static String get importSnapshot => _isChinese ? '导入快照' : 'Import Snapshot'; + static String get importSnapshotSubtitle => + _isChinese ? '从备份恢复配置' : 'Restore config from backup'; + static String get rerunSetup => _isChinese ? '重新安装' : 'Re-run setup'; + static String get rerunSetupSubtitle => + _isChinese ? '重新安装或修复环境' : 'Reinstall or repair the environment'; + static String get about => _isChinese ? '关于' : 'ABOUT'; + static String get checkForUpdates => + _isChinese ? '检查更新' : 'Check for Updates'; + static String get checkUpdatesSubtitle => + _isChinese ? '在 GitHub 检查新版本' : 'Check GitHub for a newer release'; + static String get developer => _isChinese ? '开发者' : 'Developer'; + static String get github => 'GitHub'; + static String get contact => _isChinese ? '联系方式' : 'Contact'; + static String get license => _isChinese ? '许可证' : 'License'; + static String get updateAvailable => + _isChinese ? '发现新版本' : 'Update Available'; + static String get currentVersion => _isChinese ? '当前版本' : 'Current'; + static String get latestVersion => _isChinese ? '最新版本' : 'Latest'; + static String get alreadyLatest => + _isChinese ? '已是最新版本' : "You're on the latest version"; + static String get checkUpdateFailed => + _isChinese ? '无法检查更新' : 'Could not check for updates'; + static String get snapshotSaved => + _isChinese ? '快照已保存至' : 'Snapshot saved to'; + static String get exportFailed => _isChinese ? '导出失败' : 'Export failed'; + static String get noSnapshotFound => + _isChinese ? '未找到快照文件' : 'No snapshot found at'; + static String get snapshotRestored => _isChinese + ? '快照已恢复,重启网关以应用更改' + : 'Snapshot restored successfully. Restart the gateway to apply.'; + static String get importFailed => _isChinese ? '导入失败' : 'Import failed'; + + static String get setupOpenClaw => + _isChinese ? '安装 OpenClaw' : 'Setup OpenClaw'; + static String get setupRunning => _isChinese + ? '正在配置环境,可能需要几分钟。' + : 'Setting up the environment. This may take several minutes.'; + static String get setupDescription => _isChinese + ? '将下载 Ubuntu、Node.js 和 OpenClaw 到独立环境中。' + : 'This will download Ubuntu, Node.js, and OpenClaw into a self-contained environment.'; + static String get downloadRootfs => + _isChinese ? '下载 Ubuntu 根文件系统' : 'Download Ubuntu rootfs'; + static String get extractRootfs => _isChinese ? '解压根文件系统' : 'Extract rootfs'; + static String get installNode => + _isChinese ? '安装 Node.js' : 'Install Node.js'; + static String get installOpenClaw => + _isChinese ? '安装 OpenClaw' : 'Install OpenClaw'; + static String get configureBionicBypass => + _isChinese ? '配置 Bionic Bypass' : 'Configure Bionic Bypass'; + static String get setupComplete => _isChinese ? '安装完成!' : 'Setup complete!'; + static String get configureApiKeys => + _isChinese ? '配置 API 密钥' : 'Configure API Keys'; + static String get beginSetup => _isChinese ? '开始安装' : 'Begin Setup'; + static String get retrySetup => _isChinese ? '重试安装' : 'Retry Setup'; + static String get storageRequired => _isChinese + ? '需要约 500MB 存储空间和网络连接' + : 'Requires ~500MB of storage and an internet connection'; + static String get optionalPackages => + _isChinese ? '可选扩展包' : 'OPTIONAL PACKAGES'; + + static String get gatewayLogs => _isChinese ? '网关日志' : 'Gateway Logs'; + static String get filterLogs => _isChinese ? '过滤日志...' : 'Filter logs...'; + static String get noLogsYet => + _isChinese ? '暂无日志,请启动网关。' : 'No logs yet. Start the gateway.'; + static String get noMatchingLogs => + _isChinese ? '没有匹配的日志。' : 'No matching logs.'; + static String get copyAllLogs => _isChinese ? '复制全部日志' : 'Copy all logs'; + static String get autoScrollOn => _isChinese ? '自动滚动已开启' : 'Auto-scroll on'; + static String get autoScrollOff => _isChinese ? '自动滚动已关闭' : 'Auto-scroll off'; + + static String get activeModel => _isChinese ? '当前模型' : 'Active Model'; + static String get selectProvider => _isChinese + ? '选择提供商配置 API 密钥和模型。' + : 'Select a provider to configure its API key and model.'; + static String get active => _isChinese ? '使用中' : 'Active'; + static String get configured => _isChinese ? '已配置' : 'Configured'; + static String get apiKey => _isChinese ? 'API 密钥' : 'API Key'; + static String get model => _isChinese ? '模型' : 'Model'; + static String get customModel => _isChinese ? '自定义...' : 'Custom...'; + static String get customModelHint => _isChinese + ? '例如:meta/llama-3.3-70b-instruct' + : 'e.g. meta/llama-3.3-70b-instruct'; + static String get customModelLabel => + _isChinese ? '自定义模型名称' : 'Custom model name'; + static String get saveAndActivate => _isChinese ? '保存并激活' : 'Save & Activate'; + static String get removeConfiguration => + _isChinese ? '移除配置' : 'Remove Configuration'; + static String get apiKeyEmpty => + _isChinese ? 'API 密钥不能为空' : 'API key cannot be empty'; + static String get modelEmpty => + _isChinese ? '模型名称不能为空' : 'Model name cannot be empty'; + static String get configuredAndActivated => + _isChinese ? '已配置并激活' : 'configured and activated'; + static String get saveFailed => _isChinese ? '保存失败' : 'Failed to save'; + static String get removeFailed => _isChinese ? '移除失败' : 'Failed to remove'; + static String get removeProvider => _isChinese ? '移除' : 'Remove'; + static String get removeProviderContent => _isChinese + ? '这将删除 API 密钥并停用该模型。' + : 'This will delete the API key and deactivate the model.'; + + static String get startingTerminal => + _isChinese ? '正在启动终端...' : 'Starting terminal...'; + static String get failedToStartTerminal => + _isChinese ? '启动终端失败' : 'Failed to start terminal'; + + static String get openClawOnboarding => + _isChinese ? 'OpenClaw 初始配置' : 'OpenClaw Onboarding'; + static String get startingOnboarding => + _isChinese ? '正在启动配置向导...' : 'Starting onboarding...'; + static String get goToDashboard => _isChinese ? '前往控制台' : 'Go to Dashboard'; + + static String get cliProxyManagement => + _isChinese ? 'CLIProxy 管理中心' : 'CLIProxy Management'; + static String get cliProxyNotRunning => + _isChinese ? 'CLIProxy 服务未运行' : 'CLIProxy service is not running'; + static String get openInBrowser => _isChinese ? '在浏览器中打开' : 'Open in browser'; + + static String translateError(String error) { + if (!_isChinese) return error; + if (error.contains('Download failed') || error.contains('download')) { + return '下载失败:请检查网络连接后重试。\n$error'; + } + if (error.contains('PROOT_ERROR') || error.contains('libproot')) { + return '运行环境错误:proot 库缺失或不兼容当前设备架构。\n$error'; + } + if (error.contains('No such file or directory')) { + return '文件不存在:安装包可能不完整,请重试安装。\n$error'; + } + if (error.contains('Permission denied')) { + return '权限不足:请检查存储权限设置。\n$error'; + } + if (error.contains('timeout') || error.contains('Timeout')) { + return '连接超时:请检查网络后重试。\n$error'; + } + if (error.contains('Setup failed')) { + return '安装失败:$error'; + } + return error; + } + +// Node Screen + static String get gatewayConnection => + _isChinese ? '网关连接' : 'GATEWAY CONNECTION'; + static String get localGateway => _isChinese ? '本地网关' : 'Local Gateway'; + static String get localGatewaySubtitle => + _isChinese ? '自动与本设备上的网关配对' : 'Auto-pair with gateway on this device'; + static String get remoteGateway => _isChinese ? '远程网关' : 'Remote Gateway'; + static String get remoteGatewaySubtitle => + _isChinese ? '连接到另一台设备上的网关' : 'Connect to a gateway on another device'; + static String get gatewayHost => _isChinese ? '网关地址' : 'Gateway Host'; + static String get gatewayPort => _isChinese ? '网关端口' : 'Gateway Port'; + static String get gatewayToken => _isChinese ? '网关令牌' : 'Gateway Token'; + static String get gatewayTokenHint => _isChinese + ? '从网关控制台 URL 中粘贴令牌' + : 'Paste token from gateway dashboard URL'; + static String get gatewayTokenHelper => _isChinese + ? '在控制台 URL 的 #token= 后面找到' + : 'Found in dashboard URL after #token='; + static String get connect => _isChinese ? '连接' : 'Connect'; + static String get pairing => _isChinese ? '配对' : 'PAIRING'; + static String get pairingPrompt => + _isChinese ? '在网关上批准此配对码:' : 'Approve this code on the gateway:'; + static String get capabilities => _isChinese ? '设备能力' : 'CAPABILITIES'; + static String get capCamera => _isChinese ? '摄像头' : 'Camera'; + static String get capCameraDesc => + _isChinese ? '拍摄照片和视频' : 'Capture photos and video clips'; + static String get capCanvas => _isChinese ? '画布' : 'Canvas'; + static String get capCanvasDesc => + _isChinese ? '移动端不可用' : 'Not available on mobile'; + static String get capLocation => _isChinese ? '位置' : 'Location'; + static String get capLocationDesc => + _isChinese ? '获取设备 GPS 坐标' : 'Get device GPS coordinates'; + static String get capScreen => _isChinese ? '屏幕录制' : 'Screen Recording'; + static String get capScreenDesc => _isChinese + ? '录制设备屏幕(每次需要授权)' + : 'Record device screen (requires consent each time)'; + static String get capFlash => _isChinese ? '手电筒' : 'Flashlight'; + static String get capFlashDesc => + _isChinese ? '开关设备手电筒' : 'Toggle device torch on/off'; + static String get capVibration => _isChinese ? '振动' : 'Vibration'; + static String get capVibrationDesc => _isChinese + ? '触发触觉反馈和振动' + : 'Trigger haptic feedback and vibration patterns'; + static String get capSensors => _isChinese ? '传感器' : 'Sensors'; + static String get capSensorsDesc => _isChinese + ? '读取加速度计、陀螺仪、磁力计、气压计' + : 'Read accelerometer, gyroscope, magnetometer, barometer'; + static String get capSerial => _isChinese ? '串口' : 'Serial'; + static String get capSerialDesc => + _isChinese ? '蓝牙和 USB 串口通信' : 'Bluetooth and USB serial communication'; + static String get deviceInfo => _isChinese ? '设备信息' : 'DEVICE INFO'; + static String get deviceId => _isChinese ? '设备 ID' : 'Device ID'; + static String get nodeLogs => _isChinese ? '节点日志' : 'NODE LOGS'; + static String get noLogsYetNode => _isChinese ? '暂无日志' : 'No logs yet'; + + // Provider Detail + static String get baseUrl => 'Base URL'; + static String get baseUrlHelper => _isChinese + ? 'CLIProxy 默认: http://127.0.0.1:18790/v1' + : 'CLIProxy default: http://127.0.0.1:18790/v1'; + + // AI Provider descriptions + static String get providerAnthropicDesc => _isChinese + ? 'Claude 系列模型,擅长推理和编程' + : 'Claude models for advanced reasoning and coding'; + static String get providerCustomDesc => _isChinese + ? '任意 OpenAI 兼容 API(如 CLIProxy 18790 端口)' + : 'Any OpenAI-compatible API (e.g. CLIProxy on port 18790)'; + // CLIProxy Screen + static String get cliProxyRunning => _isChinese ? '运行中' : 'Running'; + static String get cliProxyStopped => _isChinese ? '已停止' : 'Stopped'; + static String get cliProxyRefresh => _isChinese ? '刷新' : 'Refresh'; + static String get cliProxyStop => + _isChinese ? '停止 CLIProxy' : 'Stop CLIProxy'; + static String get cliProxyStart => + _isChinese ? '启动 CLIProxy' : 'Start CLIProxy'; + static String get cliProxyStarting => _isChinese ? '正在启动...' : 'Starting...'; + static String get cliProxyInstall => + _isChinese ? '安装 CLIProxy' : 'Install CLIProxy'; + static String get cliProxyInstallTitle => + _isChinese ? '安装 CLIProxy' : 'Install CLIProxy'; + static String get cliProxyInstallDone => + _isChinese ? '安装完成,返回' : 'Done, go back'; + static String get cliProxyInstallStarting => + _isChinese ? '正在启动安装...' : 'Starting install...'; + static String get cliProxyGuide => _isChinese + ? '点击下方按钮启动服务,或先安装 CLIProxy。' + : 'Tap the button below to start the service, or install CLIProxy first.'; + // CLIProxy Screen + static String get cliProxyInstallBtn => + _isChinese ? '安装 CLIProxy' : 'Install CLIProxy'; + // 9Router + static String get nineRouterTerminal => _isChinese ? '9Router 终端' : '9Router Terminal'; + static String get nineRouterTerminalSubtitle => _isChinese ? '启动免费 AI 账号代理服务' : 'Start free AI account proxy'; + static String get nineRouterConsole => _isChinese ? '9Router 控制台' : '9Router Console'; + static String get nineRouterConsoleSubtitle => _isChinese ? '打开 9Router Web 管理界面' : 'Open 9Router web dashboard'; +} \ No newline at end of file diff --git a/flutter_app/lib/l10n/app_zh.arb b/flutter_app/lib/l10n/app_zh.arb new file mode 100644 index 0000000..ec3432f --- /dev/null +++ b/flutter_app/lib/l10n/app_zh.arb @@ -0,0 +1,171 @@ +{ + "@@locale": "zh", + "appName": "OpenClaw", + "cancel": "取消", + "confirm": "确认", + "retry": "重试", + "done": "完成", + "save": "保存", + "remove": "移除", + "install": "安装", + "loading": "加载中...", + "error": "错误", + "copy": "复制", + "paste": "粘贴", + "openUrl": "打开链接", + "screenshot": "截图", + "restart": "重启", + "later": "稍后", + "download": "下载", + "copied": "已复制到剪贴板", + "noUrlFound": "未找到链接", + "linkCopied": "链接已复制", + "openLink": "打开链接", + "aiGatewayForAndroid": "Android AI 网关", + "checkingSetup": "检查安装状态...", + "repairingBypass": "修复 Bionic Bypass...", + "reinstallingNode": "重新安装 Node.js...", + "reinstallingOpenClaw": "重新安装 OpenClaw...", + "quickActions": "快捷操作", + "terminal": "终端", + "terminalSubtitle": "打开 Ubuntu Shell", + "webDashboard": "Web 控制台", + "webDashboardSubtitle": "在浏览器中打开 OpenClaw 控制台", + "startGatewayFirst": "请先启动网关", + "onboarding": "初始配置", + "onboardingSubtitle": "配置 API 密钥和绑定设置", + "configure": "网关配置", + "configureSubtitle": "管理网关设置", + "aiProviders": "AI 提供商", + "aiProvidersSubtitle": "配置模型和 API 密钥", + "packages": "扩展包", + "packagesSubtitle": "安装可选工具 (Go, Homebrew, SSH)", + "sshAccess": "SSH 访问", + "sshAccessSubtitle": "通过 SSH 远程访问终端", + "logs": "日志", + "logsSubtitle": "查看网关输出和错误", + "snapshot": "快照", + "snapshotSubtitle": "备份或恢复配置", + "node": "节点", + "nodeConnected": "已连接到网关", + "nodeCapabilities": "为 AI 提供设备能力", + "dashboardUrlCopied": "控制台链接已复制", + "copyDashboardUrl": "复制控制台链接", + "cliProxy": "CLIProxy 管理", + "cliProxySubtitle": "管理免费 AI 账号代理", + "gateway": "网关", + "startGateway": "启动网关", + "stopGateway": "停止网关", + "viewLogs": "查看日志", + "urlCopied": "链接已复制", + "copyUrl": "复制链接", + "openDashboard": "打开控制台", + "gatewayRunning": "运行中", + "gatewayStarting": "启动中", + "gatewayError": "错误", + "gatewayStopped": "已停止", + "enableNode": "启用节点", + "disableNode": "禁用节点", + "reconnect": "重新连接", + "nodePaired": "已配对", + "nodeConnecting": "连接中", + "nodeDisconnected": "已断开", + "nodeDisabled": "已禁用", + "nodeConfigure": "配置", + "settings": "设置", + "general": "通用", + "autoStartGateway": "自动启动网关", + "autoStartSubtitle": "应用打开时自动启动网关", + "batteryOptimization": "电池优化", + "batteryOptimized": "已优化(可能终止后台会话)", + "batteryUnrestricted": "无限制(推荐)", + "setupStorage": "存储权限", + "storageGranted": "已授权 — proot 可访问 /sdcard,不需要时请撤销", + "storageNotGranted": "允许访问共享存储", + "nodeSection": "节点", + "enableNodeTitle": "启用节点", + "enableNodeSubtitle": "为网关提供设备能力", + "nodeConfiguration": "节点配置", + "nodeConfigSubtitle": "连接、配对和能力设置", + "systemInfo": "系统信息", + "architecture": "架构", + "prootPath": "PRoot 路径", + "rootfs": "根文件系统", + "installed": "已安装", + "notInstalled": "未安装", + "maintenance": "维护", + "exportSnapshot": "导出快照", + "exportSnapshotSubtitle": "备份配置到下载目录", + "importSnapshot": "导入快照", + "importSnapshotSubtitle": "从备份恢复配置", + "rerunSetup": "重新安装", + "rerunSetupSubtitle": "重新安装或修复环境", + "about": "关于", + "checkForUpdates": "检查更新", + "checkUpdatesSubtitle": "在 GitHub 检查新版本", + "developer": "开发者", + "github": "GitHub", + "contact": "联系方式", + "license": "许可证", + "updateAvailable": "发现新版本", + "currentVersion": "当前版本", + "latestVersion": "最新版本", + "alreadyLatest": "已是最新版本", + "checkUpdateFailed": "无法检查更新", + "snapshotSaved": "快照已保存至", + "exportFailed": "导出失败", + "noSnapshotFound": "未找到快照文件", + "snapshotRestored": "快照已恢复,重启网关以应用更改", + "importFailed": "导入失败", + "setupOpenClaw": "安装 OpenClaw", + "setupRunning": "正在配置环境,可能需要几分钟。", + "setupDescription": "将下载 Ubuntu、Node.js 和 OpenClaw 到独立环境中。", + "downloadRootfs": "下载 Ubuntu 根文件系统", + "extractRootfs": "解压根文件系统", + "installNode": "安装 Node.js", + "installOpenClaw": "安装 OpenClaw", + "configureBionicBypass": "配置 Bionic Bypass", + "setupComplete": "安装完成!", + "configureApiKeys": "配置 API 密钥", + "beginSetup": "开始安装", + "retrySetup": "重试安装", + "storageRequired": "需要约 500MB 存储空间和网络连接", + "optionalPackages": "可选扩展包", + "gatewayLogs": "网关日志", + "filterLogs": "过滤日志...", + "noLogsYet": "暂无日志,请启动网关。", + "noMatchingLogs": "没有匹配的日志。", + "copyAllLogs": "复制全部日志", + "autoScrollOn": "自动滚动已开启", + "autoScrollOff": "自动滚动已关闭", + "activeModel": "当前模型", + "selectProvider": "选择提供商配置 API 密钥和模型。", + "active": "使用中", + "configured": "已配置", + "apiKey": "API 密钥", + "model": "模型", + "customModel": "自定义...", + "customModelHint": "例如:meta/llama-3.3-70b-instruct", + "customModelLabel": "自定义模型名称", + "saveAndActivate": "保存并激活", + "removeConfiguration": "移除配置", + "apiKeyEmpty": "API 密钥不能为空", + "modelEmpty": "模型名称不能为空", + "configuredAndActivated": "已配置并激活", + "saveFailed": "保存失败", + "removeFailed": "移除失败", + "removeProvider": "移除提供商", + "removeProviderContent": "这将删除 API 密钥并停用该模型。", + "startingTerminal": "正在启动终端...", + "failedToStartTerminal": "启动终端失败", + "openClawOnboarding": "OpenClaw 初始配置", + "startingOnboarding": "正在启动配置向导...", + "failedToStartOnboarding": "启动配置向导失败", + "goToDashboard": "前往控制台", + "cliProxyManagement": "CLIProxy 管理中心", + "cliProxyNotRunning": "CLIProxy 服务未运行", + "openInBrowser": "在浏览器中打开", + "refresh": "刷新", + "reconnectProxy": "重新连接", + "installedBadge": "已安装" +} diff --git a/flutter_app/lib/models/ai_provider.dart b/flutter_app/lib/models/ai_provider.dart index d24f8a5..22f2ce9 100644 --- a/flutter_app/lib/models/ai_provider.dart +++ b/flutter_app/lib/models/ai_provider.dart @@ -26,7 +26,7 @@ class AiProvider { static const anthropic = AiProvider( id: 'anthropic', name: 'Anthropic', - description: 'Claude models — advanced reasoning and coding', + description: 'Claude models �?advanced reasoning and coding', icon: Icons.psychology, color: Color(0xFFD97706), baseUrl: 'https://api.anthropic.com/v1', @@ -133,6 +133,30 @@ class AiProvider { apiKeyHint: 'xai-...', ); + static const custom = AiProvider( + id: 'custom', + name: 'Custom / CLIProxy', + description: 'Any OpenAI-compatible API (e.g. CLIProxy on port 18790)', + icon: Icons.tune, + color: Color(0xFF8B5CF6), + baseUrl: 'http://127.0.0.1:18790/v1', + defaultModels: [ + 'claude-sonnet-4-20250514', + 'gemini-2.5-pro', + 'gpt-4o', + ], + apiKeyHint: 'your-api-key (or any string if not required)', + ); + /// All available AI providers. - static const all = [anthropic, openai, google, openrouter, nvidia, deepseek, xai]; + static const all = [ + anthropic, + openai, + google, + openrouter, + nvidia, + deepseek, + xai, + custom + ]; } diff --git a/flutter_app/lib/providers/node_provider.dart b/flutter_app/lib/providers/node_provider.dart index 2848636..6c240a0 100644 --- a/flutter_app/lib/providers/node_provider.dart +++ b/flutter_app/lib/providers/node_provider.dart @@ -63,7 +63,7 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver { text = 'Node reconnecting...'; break; case NodeStatus.error: - text = 'Node error — retrying'; + text = 'Node error ?retrying'; break; default: return; @@ -84,7 +84,7 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver { } } - /// App returned to foreground — force connection health check. + /// App returned to foreground ?force connection health check. /// Dart timers freeze while backgrounded, so the watchdog and ping /// timers won't have fired. We must check and reconnect manually. Future _onAppResumed() async { @@ -99,7 +99,7 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver { } catch (_) {} if (_state.isPaired && _nodeService.isConnectionStale) { - // WebSocket went stale while in background — force reconnect + // WebSocket went stale while in background ?force reconnect await _nodeService.disconnect(); await _nodeService.connect(); } else if (!_state.isPaired && !_state.isConnecting) { @@ -111,7 +111,7 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver { _startWatchdog(); } - /// App going to background — ensure the foreground service is running + /// App going to background ?ensure the foreground service is running /// so Android keeps our process alive. Future _onAppPaused() async { if (_state.isDisabled) return; @@ -254,10 +254,10 @@ class NodeProvider extends ChangeNotifier with WidgetsBindingObserver { } catch (_) {} if (!_state.isPaired && !_state.isConnecting) { - // Connection dropped — reconnect + // Connection dropped ?reconnect _nodeService.connect(); } else if (_state.isPaired && _nodeService.isConnectionStale) { - // Connection appears alive but no data received — force reconnect + // Connection appears alive but no data received ?force reconnect _nodeService.disconnect().then((_) => _nodeService.connect()); } }); diff --git a/flutter_app/lib/screens/cliproxy_install_screen.dart b/flutter_app/lib/screens/cliproxy_install_screen.dart new file mode 100644 index 0000000..a4e0449 --- /dev/null +++ b/flutter_app/lib/screens/cliproxy_install_screen.dart @@ -0,0 +1,238 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:xterm/xterm.dart'; +import 'package:flutter_pty/flutter_pty.dart'; +import '../l10n/app_strings.dart'; +import '../services/native_bridge.dart'; +import '../services/terminal_service.dart'; +import '../widgets/terminal_toolbar.dart'; + +class CliProxyInstallScreen extends StatefulWidget { + const CliProxyInstallScreen({super.key}); + + @override + State createState() => _CliProxyInstallScreenState(); +} + +class _CliProxyInstallScreenState extends State { + late final Terminal _terminal; + late final TerminalController _controller; + Pty? _pty; + bool _loading = true; + bool _finished = false; + String? _error; + final _ctrlNotifier = ValueNotifier(false); + final _altNotifier = ValueNotifier(false); + + static const _sentinel = 'CLIPROXY_INSTALL_COMPLETE'; + + static const _installCommand = 'set -e; ' + 'echo ">>> Installing 9Router (Node.js AI proxy)..."; ' + 'node --version; ' + 'npm --version; ' + 'echo ">>> Installing 9router globally..."; ' + 'npm install -g 9router; ' + 'echo ">>> 9Router installed"; ' + '9router --version 2>/dev/null || echo "9router ready"; ' + 'echo ">>> CLIPROXY_INSTALL_COMPLETE"'; + + static const _fontFallback = [ + 'monospace', + 'Noto Sans Mono', + 'Noto Sans Mono CJK SC', + 'sans-serif', + ]; + + @override + void initState() { + super.initState(); + _terminal = Terminal(maxLines: 10000); + _controller = TerminalController(); + NativeBridge.startTerminalService(); + WidgetsBinding.instance.addPostFrameCallback((_) => _startInstall()); + } + + Future _startInstall() async { + _pty?.kill(); + _pty = null; + try { + try { + await NativeBridge.setupDirs(); + } catch (_) {} + try { + await NativeBridge.writeResolv(); + } catch (_) {} + try { + final filesDir = await NativeBridge.getFilesDir(); + const rc = 'nameserver 8.8.8.8\nnameserver 8.8.4.4\n'; + final rf = File('$filesDir/config/resolv.conf'); + if (!rf.existsSync()) { + Directory('$filesDir/config').createSync(recursive: true); + rf.writeAsStringSync(rc); + } + final rr = File('$filesDir/rootfs/ubuntu/etc/resolv.conf'); + if (!rr.existsSync()) { + rr.parent.createSync(recursive: true); + rr.writeAsStringSync(rc); + } + } catch (_) {} + + final config = await TerminalService.getProotShellConfig(); + final args = TerminalService.buildProotArgs( + config, + columns: _terminal.viewWidth, + rows: _terminal.viewHeight, + ); + final cmdArgs = List.from(args) + ..removeLast() + ..removeLast() + ..addAll(['/bin/bash', '-lc', _installCommand]); + + _pty = Pty.start( + config['executable']!, + arguments: cmdArgs, + environment: TerminalService.buildHostEnv(config), + columns: _terminal.viewWidth, + rows: _terminal.viewHeight, + ); + + _pty!.output.cast>().listen((data) { + final text = utf8.decode(data, allowMalformed: true); + _terminal.write(text); + if (!_finished && text.contains(_sentinel)) { + if (mounted) setState(() => _finished = true); + } + }); + + _pty!.exitCode.then((code) { + _terminal.write('\r\n[Process exited with code $code]\r\n'); + if (mounted && !_finished) setState(() => _finished = true); + }); + + _terminal.onOutput = (data) { + if (_ctrlNotifier.value && data.length == 1) { + final code = data.toLowerCase().codeUnitAt(0); + if (code >= 97 && code <= 122) { + _pty?.write(Uint8List.fromList([code - 96])); + _ctrlNotifier.value = false; + return; + } + } + if (_altNotifier.value && data.isNotEmpty) { + _pty?.write(utf8.encode('\x1b$data')); + _altNotifier.value = false; + return; + } + _pty?.write(utf8.encode(data)); + }; + _terminal.onResize = (w, h, pw, ph) => _pty?.resize(h, w); + setState(() => _loading = false); + } catch (e) { + setState(() { + _loading = false; + _error = 'Failed: $e'; + }); + } + } + + @override + void dispose() { + _ctrlNotifier.dispose(); + _altNotifier.dispose(); + _controller.dispose(); + _pty?.kill(); + NativeBridge.stopTerminalService(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppStrings.cliProxyInstallTitle), + automaticallyImplyLeading: false, + ), + body: Column( + children: [ + if (_loading) + Expanded( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 16), + Text(AppStrings.cliProxyInstallStarting), + ], + ), + ), + ) + else if (_error != null) + Expanded( + child: Center( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, + size: 48, color: Theme.of(context).colorScheme.error), + const SizedBox(height: 16), + Text(_error!, + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).colorScheme.error)), + const SizedBox(height: 16), + FilledButton.icon( + onPressed: () => setState(() { + _loading = true; + _error = null; + _finished = false; + _startInstall(); + }), + icon: const Icon(Icons.refresh), + label: Text(AppStrings.retry), + ), + ], + ), + ), + ), + ) + else ...[ + Expanded( + child: TerminalView( + _terminal, + controller: _controller, + textStyle: const TerminalStyle( + fontSize: 11, + height: 1.0, + fontFamily: 'DejaVuSansMono', + fontFamilyFallback: _fontFallback, + ), + ), + ), + TerminalToolbar( + pty: _pty, + ctrlNotifier: _ctrlNotifier, + altNotifier: _altNotifier, + ), + ], + if (_finished) + Padding( + padding: const EdgeInsets.all(16), + child: SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: () => Navigator.of(context).pop(true), + icon: const Icon(Icons.check), + label: Text(AppStrings.cliProxyInstallDone), + ), + ), + ), + ], + ), + ); + } +} diff --git a/flutter_app/lib/screens/cliproxy_screen.dart b/flutter_app/lib/screens/cliproxy_screen.dart new file mode 100644 index 0000000..ed46871 --- /dev/null +++ b/flutter_app/lib/screens/cliproxy_screen.dart @@ -0,0 +1,494 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:xterm/xterm.dart' as xterm; +import 'package:flutter_pty/flutter_pty.dart' as flutter_pty; +import '../app.dart'; +import '../l10n/app_strings.dart'; +import '../services/native_bridge.dart'; +import '../services/terminal_service.dart'; +import '../utils/responsive.dart'; +import 'cliproxy_install_screen.dart'; + +class CliProxyScreen extends StatefulWidget { + const CliProxyScreen({super.key}); + + @override + State createState() => _CliProxyScreenState(); +} + +class _CliProxyScreenState extends State { + static const String _cliProxyUrl = 'http://127.0.0.1:20128/'; + static const int _cliProxyPort = 20128; + + late final WebViewController _controller; + bool _loading = true; + bool _hasError = false; + bool _isRunning = false; + bool _isStarting = false; + + @override + void initState() { + super.initState(); + _controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setNavigationDelegate( + NavigationDelegate( + onPageStarted: (_) => setState(() { + _loading = true; + _hasError = false; + }), + onPageFinished: (_) => setState(() { + _loading = false; + _isRunning = true; + }), + onWebResourceError: (error) { + if (error.isForMainFrame ?? true) { + setState(() { + _loading = false; + _hasError = true; + _isRunning = false; + }); + } + }, + ), + ) + ..loadRequest(Uri.parse(_cliProxyUrl)); + _checkRunning(); + } + + Future _checkRunning() async { + try { + final socket = await Socket.connect('127.0.0.1', _cliProxyPort, + timeout: const Duration(seconds: 2)); + socket.destroy(); + if (mounted) setState(() => _isRunning = true); + } catch (_) { + if (mounted) setState(() => _isRunning = false); + } + } + + Future _startCliProxy() async { + // 跳转到 OpenClaw 终端,自动输入启动命令 + // 用户在终端里看到 9router 启动后,返回此页面点重新连接 + if (!mounted) return; + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: Text(AppStrings.isChinese ? '启动 9Router' : 'Start 9Router'), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(AppStrings.isChinese + ? '请在终端中运行以下命令启动 9Router:' + : 'Run the following command in the terminal:'), + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.black87, + borderRadius: BorderRadius.circular(8), + ), + child: const SelectableText( + '9router --port 20128 &', + style: TextStyle( + fontFamily: 'monospace', + color: Colors.greenAccent, + fontSize: 13, + ), + ), + ), + const SizedBox(height: 12), + Text( + AppStrings.isChinese + ? '启动后选择 Hide to Tray,然后返回点重新连接。' + : 'Select "Hide to Tray", then come back and tap Reconnect.', + style: TextStyle(color: Colors.grey[600], fontSize: 12), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(ctx), + child: Text(AppStrings.cancel), + ), + FilledButton( + onPressed: () { + Navigator.pop(ctx); + // 跳转到终端并自动执行命令 + Navigator.of(context) + .push( + MaterialPageRoute( + builder: (_) => const _NineRouterTerminalScreen()), + ) + .then((_) { + Future.delayed(const Duration(seconds: 3), () { + _checkRunning().then((_) { + if (_isRunning && mounted) { + setState(() => _hasError = false); + _controller.reload(); + } + }); + }); + }); + }, + child: Text(AppStrings.isChinese ? '打开终端' : 'Open Terminal'), + ), + ], + ), + ); + } + + Future _stopCliProxy() async { + try { + await NativeBridge.runInProot( + 'pkill -f "9router" 2>/dev/null || true', + timeout: 10, + ); + await Future.delayed(const Duration(seconds: 1)); + setState(() { + _isRunning = false; + _hasError = true; + }); + } catch (_) {} + } + + Future _showCliProxyLog() async { + String log = ''; + try { + final result = await NativeBridge.runInProot( + 'cat /tmp/9router.log 2>/dev/null || echo "No log file found"', + timeout: 10, + ); + log = result; + } catch (e) { + log = 'Failed to read log: $e'; + } + if (!mounted) return; + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: + Text(AppStrings.isChinese ? '9Router 启动日志' : '9Router Startup Log'), + content: SizedBox( + width: double.maxFinite, + height: 300, + child: SingleChildScrollView( + child: SelectableText( + log.isEmpty ? (AppStrings.isChinese ? '暂无日志' : 'No logs') : log, + style: const TextStyle(fontFamily: 'monospace', fontSize: 11), + ), + ), + ), + actions: [ + FilledButton( + onPressed: () => Navigator.pop(ctx), + child: Text(AppStrings.done), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isTablet = Responsive.isTablet(context); + + return Scaffold( + appBar: AppBar( + title: Text(AppStrings.cliProxyManagement), + actions: [ + if (_isStarting) + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ), + ), + ) + else if (_isRunning) + IconButton( + icon: const Icon(Icons.stop_circle_outlined), + tooltip: AppStrings.cliProxyStop, + onPressed: _stopCliProxy, + ) + else + IconButton( + icon: const Icon(Icons.play_circle_outlined), + tooltip: AppStrings.cliProxyStart, + onPressed: _startCliProxy, + ), + Padding( + padding: const EdgeInsets.only(right: 4), + child: Center( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: (_isRunning + ? AppColors.statusGreen + : AppColors.statusGrey) + .withAlpha(25), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: (_isRunning + ? AppColors.statusGreen + : AppColors.statusGrey) + .withAlpha(60), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + _isRunning ? Icons.circle : Icons.circle_outlined, + size: 8, + color: _isRunning + ? AppColors.statusGreen + : AppColors.statusGrey, + ), + const SizedBox(width: 4), + Text( + _isRunning + ? AppStrings.cliProxyRunning + : AppStrings.cliProxyStopped, + style: theme.textTheme.labelSmall?.copyWith( + color: _isRunning + ? AppColors.statusGreen + : AppColors.statusGrey, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + IconButton( + icon: const Icon(Icons.refresh), + tooltip: AppStrings.cliProxyRefresh, + onPressed: () { + setState(() { + _loading = true; + _hasError = false; + }); + _controller.reload(); + _checkRunning(); + }, + ), + IconButton( + icon: const Icon(Icons.open_in_browser), + tooltip: AppStrings.openInBrowser, + onPressed: () => launchUrl(Uri.parse(_cliProxyUrl), + mode: LaunchMode.externalApplication), + ), + ], + ), + body: _hasError + ? _buildErrorView(context, isTablet) + : Stack( + children: [ + WebViewWidget(controller: _controller), + if (_loading) const Center(child: CircularProgressIndicator()), + ], + ), + ); + } + + Widget _buildErrorView(BuildContext context, bool isTablet) { + final theme = Theme.of(context); + return Responsive.constrain( + Center( + child: Padding( + padding: EdgeInsets.all(isTablet ? 48 : 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.cloud_off, + size: isTablet ? 80 : 64, + color: theme.colorScheme.onSurfaceVariant), + const SizedBox(height: 24), + Text(AppStrings.cliProxyNotRunning, + style: theme.textTheme.titleLarge + ?.copyWith(fontWeight: FontWeight.w600), + textAlign: TextAlign.center), + const SizedBox(height: 12), + Text(AppStrings.cliProxyGuide, + style: theme.textTheme.bodyMedium + ?.copyWith(color: theme.colorScheme.onSurfaceVariant), + textAlign: TextAlign.center), + const SizedBox(height: 32), + SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: _isStarting ? null : _startCliProxy, + icon: _isStarting + ? const SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator( + strokeWidth: 2, color: Colors.white)) + : const Icon(Icons.play_arrow), + label: Text(_isStarting + ? AppStrings.cliProxyStarting + : AppStrings.cliProxyStart), + ), + ), + const SizedBox(height: 12), + SizedBox( + width: double.infinity, + child: OutlinedButton.icon( + onPressed: () async { + final result = await Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => const CliProxyInstallScreen()), + ); + if (result == true) _startCliProxy(); + }, + icon: const Icon(Icons.download), + label: Text(AppStrings.cliProxyInstallBtn), + ), + ), + const SizedBox(height: 12), + TextButton.icon( + onPressed: () { + setState(() { + _loading = true; + _hasError = false; + }); + _controller.reload(); + _checkRunning(); + }, + icon: const Icon(Icons.refresh, size: 18), + label: Text(AppStrings.reconnect), + ), + const SizedBox(height: 8), + TextButton.icon( + onPressed: _showCliProxyLog, + icon: const Icon(Icons.article_outlined, size: 18), + label: + Text(AppStrings.isChinese ? '查看启动日志' : 'View startup log'), + ), + ], + ), + ), + ), + ); + } +} + +// 终端界面:在 proot 里前台运行 9router +class _NineRouterTerminalScreen extends StatefulWidget { + const _NineRouterTerminalScreen(); + + @override + State<_NineRouterTerminalScreen> createState() => + _NineRouterTerminalScreenState(); +} + +class _NineRouterTerminalScreenState extends State<_NineRouterTerminalScreen> { + static const _fontFallback = ['monospace', 'Noto Sans Mono', 'sans-serif']; + + late final xterm.Terminal _terminal; + late final xterm.TerminalController _controller; + flutter_pty.Pty? _pty; + bool _loading = true; + + @override + void initState() { + super.initState(); + _terminal = xterm.Terminal(maxLines: 5000); + _controller = xterm.TerminalController(); + NativeBridge.startTerminalService(); + WidgetsBinding.instance.addPostFrameCallback((_) => _start()); + } + + Future _start() async { + try { + try { + await NativeBridge.setupDirs(); + } catch (_) {} + try { + await NativeBridge.writeResolv(); + } catch (_) {} + final config = await TerminalService.getProotShellConfig(); + final args = TerminalService.buildProotArgs( + config, + columns: _terminal.viewWidth, + rows: _terminal.viewHeight, + ); + final cmdArgs = List.from(args) + ..removeLast() + ..removeLast() + ..addAll([ + '/bin/bash', + '-lc', + 'echo "Starting 9Router on port 20128..."; ' + 'nohup 9router --port 20128 > /tmp/9router.log 2>&1 & ' + 'sleep 2 && echo "9Router started" && cat /tmp/9router.log' + ]); + + _pty = flutter_pty.Pty.start( + config['executable']!, + arguments: cmdArgs, + environment: TerminalService.buildHostEnv(config), + columns: _terminal.viewWidth, + rows: _terminal.viewHeight, + ); + _pty!.output.cast>().listen((data) { + _terminal.write(utf8.decode(data, allowMalformed: true)); + }); + _pty!.exitCode.then((code) { + _terminal.write('\r\n[Process exited with code $code]\r\n'); + }); + _terminal.onOutput = (data) => _pty?.write(utf8.encode(data)); + _terminal.onResize = (w, h, pw, ph) => _pty?.resize(h, w); + setState(() => _loading = false); + } catch (e) { + setState(() => _loading = false); + _terminal.write('Error: $e\r\n'); + } + } + + @override + void dispose() { + _controller.dispose(); + _pty?.kill(); + NativeBridge.stopTerminalService(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppStrings.isChinese ? '9Router 运行终端' : '9Router Terminal'), + actions: [ + IconButton( + icon: const Icon(Icons.arrow_back), + tooltip: AppStrings.isChinese ? '返回管理界面' : 'Back', + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + body: _loading + ? const Center(child: CircularProgressIndicator()) + : xterm.TerminalView( + _terminal, + controller: _controller, + textStyle: const xterm.TerminalStyle( + fontSize: 11, + height: 1.0, + fontFamily: 'DejaVuSansMono', + fontFamilyFallback: _fontFallback, + ), + ), + ); + } +} diff --git a/flutter_app/lib/screens/configure_screen.dart b/flutter_app/lib/screens/configure_screen.dart index f695700..60fb8da 100644 --- a/flutter_app/lib/screens/configure_screen.dart +++ b/flutter_app/lib/screens/configure_screen.dart @@ -1,4 +1,4 @@ -import 'dart:convert'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -297,7 +297,7 @@ class _ConfigureScreenState extends State { body: Column( children: [ if (_loading) - const Expanded( + Expanded( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, diff --git a/flutter_app/lib/screens/dashboard_screen.dart b/flutter_app/lib/screens/dashboard_screen.dart index dc8d5c1..35d5787 100644 --- a/flutter_app/lib/screens/dashboard_screen.dart +++ b/flutter_app/lib/screens/dashboard_screen.dart @@ -1,9 +1,11 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../constants.dart'; +import '../l10n/app_strings.dart'; import '../providers/gateway_provider.dart'; import '../providers/node_provider.dart'; +import '../utils/responsive.dart'; import '../widgets/gateway_controls.dart'; import '../widgets/status_card.dart'; import 'node_screen.dart'; @@ -16,6 +18,8 @@ import 'packages_screen.dart'; import 'providers_screen.dart'; import 'settings_screen.dart'; import 'ssh_screen.dart'; +import 'nine_router_terminal_screen.dart'; +import 'nine_router_webview_screen.dart'; class DashboardScreen extends StatelessWidget { const DashboardScreen({super.key}); @@ -23,10 +27,11 @@ class DashboardScreen extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); + final isTablet = Responsive.isTablet(context); return Scaffold( appBar: AppBar( - title: const Text('OpenClaw'), + title: Text(AppStrings.appName), actions: [ IconButton( icon: const Icon(Icons.settings), @@ -36,181 +41,238 @@ class DashboardScreen extends StatelessWidget { ), ], ), - body: SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const GatewayControls(), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.only(left: 4, bottom: 8), - child: Text( - 'QUICK ACTIONS', - style: theme.textTheme.labelSmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - fontWeight: FontWeight.w600, - letterSpacing: 1.2, - ), - ), - ), - StatusCard( - title: 'Terminal', - subtitle: 'Open Ubuntu shell with OpenClaw', - icon: Icons.terminal, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const TerminalScreen()), - ), - ), - Consumer( - builder: (context, provider, _) { - final url = provider.state.dashboardUrl; - final token = url != null - ? RegExp(r'#token=([0-9a-f]+)').firstMatch(url)?.group(1) - : null; - final subtitle = provider.state.isRunning - ? (token != null - ? 'Token: ${token.substring(0, (token.length > 8 ? 8 : token.length))}...' - : 'Open OpenClaw dashboard in browser') - : 'Start gateway first'; - return StatusCard( - title: 'Web Dashboard', - subtitle: subtitle, - icon: Icons.dashboard, - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (token != null) - IconButton( - icon: const Icon(Icons.copy, size: 18), - tooltip: 'Copy dashboard URL', - onPressed: () { - Clipboard.setData(ClipboardData(text: url!)); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Dashboard URL copied')), - ); - }, - ), - const Icon(Icons.chevron_right), - ], + body: Responsive.constrain( + SingleChildScrollView( + padding: EdgeInsets.all(isTablet ? 24 : 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const GatewayControls(), + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.only(left: 4, bottom: 8), + child: Text( + AppStrings.quickActions, + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + fontWeight: FontWeight.w600, + letterSpacing: 1.2, ), - onTap: provider.state.isRunning - ? () => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => WebDashboardScreen( - url: url, - ), - ), - ) - : null, - ); - }, - ), - StatusCard( - title: 'Onboarding', - subtitle: 'Configure API keys and binding', - icon: Icons.vpn_key, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const OnboardingScreen()), - ), - ), - StatusCard( - title: 'Configure', - subtitle: 'Manage gateway settings', - icon: Icons.tune, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const ConfigureScreen()), - ), - ), - StatusCard( - title: 'AI Providers', - subtitle: 'Configure models and API keys', - icon: Icons.model_training, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const ProvidersScreen()), - ), - ), - StatusCard( - title: 'Packages', - subtitle: 'Install optional tools (Go, Homebrew, SSH)', - icon: Icons.extension, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const PackagesScreen()), - ), - ), - StatusCard( - title: 'SSH Access', - subtitle: 'Remote terminal access via SSH', - icon: Icons.terminal, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const SshScreen()), - ), - ), - StatusCard( - title: 'Logs', - subtitle: 'View gateway output and errors', - icon: Icons.article_outlined, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const LogsScreen()), - ), - ), - StatusCard( - title: 'Snapshot', - subtitle: 'Backup or restore your config', - icon: Icons.backup, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const SettingsScreen()), + ), ), - ), - Consumer( - builder: (context, nodeProvider, _) { - final nodeState = nodeProvider.state; - return StatusCard( - title: 'Node', - subtitle: nodeState.isPaired - ? 'Connected to gateway' - : nodeState.isDisabled - ? 'Device capabilities for AI' - : nodeState.statusText, - icon: Icons.devices, - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const NodeScreen()), - ), - ); - }, - ), - const SizedBox(height: 24), - Center( - child: Column( - children: [ - Text( - 'OpenClaw v${AppConstants.version}', - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, + if (isTablet) + _buildTabletGrid(context, theme) + else + _buildPhoneList(context, theme), + const SizedBox(height: 24), + Center( + child: Column( + children: [ + Text( + 'OpenClaw v${AppConstants.version}', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), ), - ), - const SizedBox(height: 2), - Text( - 'by ${AppConstants.authorName} | ${AppConstants.orgName}', - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, + const SizedBox(height: 2), + Text( + 'by ${AppConstants.authorName} | ${AppConstants.orgName}', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ), ), ); } + + // 手机:竖向列�? + Widget _buildPhoneList(BuildContext context, ThemeData theme) { + return Column( + children: _buildCards(context), + ); + } + + // 平板�?列网�? + Widget _buildTabletGrid(BuildContext context, ThemeData theme) { + final cards = _buildCards(context); + final rows = []; + for (int i = 0; i < cards.length; i += 2) { + rows.add( + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: cards[i]), + const SizedBox(width: 12), + Expanded( + child: i + 1 < cards.length ? cards[i + 1] : const SizedBox()), + ], + ), + ); + } + return Column(children: rows); + } + + List _buildCards(BuildContext context) { + return [ + StatusCard( + title: AppStrings.terminal, + subtitle: AppStrings.terminalSubtitle, + icon: Icons.terminal, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const TerminalScreen()), + ), + ), + Consumer( + builder: (context, provider, _) { + final url = provider.state.dashboardUrl; + final token = url != null + ? RegExp(r'#token=([0-9a-f]+)').firstMatch(url)?.group(1) + : null; + final subtitle = provider.state.isRunning + ? (token != null + ? 'Token: ${token.substring(0, (token.length > 8 ? 8 : token.length))}...' + : AppStrings.webDashboardSubtitle) + : AppStrings.startGatewayFirst; + return StatusCard( + title: AppStrings.webDashboard, + subtitle: subtitle, + icon: Icons.dashboard, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (token != null) + IconButton( + icon: const Icon(Icons.copy, size: 18), + tooltip: AppStrings.copyDashboardUrl, + onPressed: () { + Clipboard.setData(ClipboardData(text: url!)); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(AppStrings.dashboardUrlCopied)), + ); + }, + ), + const Icon(Icons.chevron_right), + ], + ), + onTap: provider.state.isRunning + ? () => Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => WebDashboardScreen(url: url), + ), + ) + : null, + ); + }, + ), + StatusCard( + title: AppStrings.isChinese ? '9Router 终端' : '9Router Terminal', + subtitle: AppStrings.isChinese + ? '启动免费 AI 账号代理服务' + : 'Start free AI account proxy', + icon: Icons.swap_horiz, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const NineRouterTerminalScreen()), + ), + ), + StatusCard( + title: AppStrings.isChinese ? '9Router 控制台' : '9Router Console', + subtitle: + AppStrings.isChinese ? '打开 Web 管理界面' : 'Open web management UI', + icon: Icons.dashboard_customize, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const NineRouterWebviewScreen()), + ), + ), + StatusCard( + title: AppStrings.onboarding, + subtitle: AppStrings.onboardingSubtitle, + icon: Icons.vpn_key, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const OnboardingScreen()), + ), + ), + StatusCard( + title: AppStrings.configure, + subtitle: AppStrings.configureSubtitle, + icon: Icons.tune, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const ConfigureScreen()), + ), + ), + StatusCard( + title: AppStrings.aiProviders, + subtitle: AppStrings.aiProvidersSubtitle, + icon: Icons.model_training, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const ProvidersScreen()), + ), + ), + StatusCard( + title: AppStrings.packages, + subtitle: AppStrings.packagesSubtitle, + icon: Icons.extension, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const PackagesScreen()), + ), + ), + StatusCard( + title: AppStrings.sshAccess, + subtitle: AppStrings.sshAccessSubtitle, + icon: Icons.terminal, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const SshScreen()), + ), + ), + StatusCard( + title: AppStrings.logs, + subtitle: AppStrings.logsSubtitle, + icon: Icons.article_outlined, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const LogsScreen()), + ), + ), + StatusCard( + title: AppStrings.snapshot, + subtitle: AppStrings.snapshotSubtitle, + icon: Icons.backup, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const SettingsScreen()), + ), + ), + Consumer( + builder: (context, nodeProvider, _) { + final nodeState = nodeProvider.state; + return StatusCard( + title: AppStrings.node, + subtitle: nodeState.isPaired + ? AppStrings.nodeConnected + : nodeState.isDisabled + ? AppStrings.nodeCapabilities + : nodeState.statusText, + icon: Icons.devices, + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const NodeScreen()), + ), + ); + }, + ), + ]; + } } diff --git a/flutter_app/lib/screens/logs_screen.dart b/flutter_app/lib/screens/logs_screen.dart index eca00e2..acf729a 100644 --- a/flutter_app/lib/screens/logs_screen.dart +++ b/flutter_app/lib/screens/logs_screen.dart @@ -1,9 +1,12 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../app.dart'; +import '../l10n/app_strings.dart'; import '../providers/gateway_provider.dart'; import '../services/screenshot_service.dart'; +import '../utils/log_parser.dart'; +import '../utils/responsive.dart'; class LogsScreen extends StatefulWidget { const LogsScreen({super.key}); @@ -17,6 +20,7 @@ class _LogsScreenState extends State { final _searchController = TextEditingController(); final _screenshotKey = GlobalKey(); bool _autoScroll = true; + bool _friendlyMode = true; // 友好模式 vs 原始模式 String _filter = ''; @override @@ -32,104 +36,215 @@ class _LogsScreenState extends State { return Scaffold( appBar: AppBar( - title: const Text('Gateway Logs'), + title: Text(AppStrings.gatewayLogs), actions: [ + // 切换友好/原始模式 + IconButton( + icon: Icon(_friendlyMode ? Icons.code : Icons.auto_awesome), + tooltip: _friendlyMode + ? (AppStrings.isChinese ? '切换到原始日志' : 'Raw logs') + : (AppStrings.isChinese ? '切换到友好模式' : 'Friendly mode'), + onPressed: () => setState(() => _friendlyMode = !_friendlyMode), + ), IconButton( icon: const Icon(Icons.camera_alt_outlined), - tooltip: 'Screenshot', + tooltip: AppStrings.screenshot, onPressed: _takeScreenshot, ), IconButton( icon: Icon( - _autoScroll ? Icons.vertical_align_bottom : Icons.vertical_align_top, + _autoScroll + ? Icons.vertical_align_bottom + : Icons.vertical_align_top, ), - tooltip: _autoScroll ? 'Auto-scroll on' : 'Auto-scroll off', + tooltip: _autoScroll + ? AppStrings.autoScrollOn + : AppStrings.autoScrollOff, onPressed: () => setState(() => _autoScroll = !_autoScroll), ), IconButton( icon: const Icon(Icons.copy), - tooltip: 'Copy all logs', + tooltip: AppStrings.copyAllLogs, onPressed: () => _copyLogs(context), ), ], ), - body: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8), - child: TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Filter logs...', - prefixIcon: const Icon(Icons.search), - isDense: true, - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, + body: Responsive.constrain( + Column( + children: [ + Padding( + padding: const EdgeInsets.all(8), + child: TextField( + controller: _searchController, + decoration: InputDecoration( + hintText: AppStrings.filterLogs, + prefixIcon: const Icon(Icons.search), + isDense: true, + contentPadding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + suffixIcon: _filter.isNotEmpty + ? IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + _searchController.clear(); + setState(() => _filter = ''); + }, + ) + : null, ), - suffixIcon: _filter.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - _searchController.clear(); - setState(() => _filter = ''); - }, - ) - : null, + onChanged: (value) => setState(() => _filter = value), ), - onChanged: (value) => setState(() => _filter = value), ), - ), - Expanded( - child: RepaintBoundary( - key: _screenshotKey, - child: Consumer( - builder: (context, provider, _) { - final logs = provider.state.logs; - final filtered = _filter.isEmpty - ? logs - : logs.where((l) => - l.toLowerCase().contains(_filter.toLowerCase())).toList(); - - if (filtered.isEmpty) { - return Center( - child: Text( - logs.isEmpty ? 'No logs yet. Start the gateway.' : 'No matching logs.', - style: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - ), - ), - ); - } - - WidgetsBinding.instance.addPostFrameCallback((_) { - if (_autoScroll && _scrollController.hasClients) { - _scrollController.jumpTo( - _scrollController.position.maxScrollExtent, - ); - } - }); - - return ListView.builder( - controller: _scrollController, - padding: const EdgeInsets.symmetric(horizontal: 8), - itemCount: filtered.length, - itemBuilder: (context, index) { - final line = filtered[index]; - return Text( - line, - style: TextStyle( - fontFamily: 'monospace', - fontSize: 12, - color: _logColor(line, theme), - ), + Expanded( + child: RepaintBoundary( + key: _screenshotKey, + child: Consumer( + builder: (context, provider, _) { + final logs = provider.state.logs; + final filtered = _filter.isEmpty + ? logs + : logs + .where((l) => + l.toLowerCase().contains(_filter.toLowerCase())) + .toList(); + + if (filtered.isEmpty) { + return Center( + child: Text( + logs.isEmpty + ? AppStrings.noLogsYet + : AppStrings.noMatchingLogs, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ); + } + + WidgetsBinding.instance.addPostFrameCallback((_) { + if (_autoScroll && _scrollController.hasClients) { + _scrollController.jumpTo( + _scrollController.position.maxScrollExtent, + ); + } + }); + + return ListView.builder( + controller: _scrollController, + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + itemCount: filtered.length, + itemBuilder: (context, index) { + final line = filtered[index]; + if (_friendlyMode) { + return _buildFriendlyLogItem(line, theme); + } + return _buildRawLogItem(line, theme); + }, ); }, - ); - }, + ), + ), ), + ], + ), + ), + ); + } + + // 友好模式:卡片样式 + Widget _buildFriendlyLogItem(String line, ThemeData theme) { + final parsed = LogParser.parse(line, theme); + final isDark = theme.brightness == Brightness.dark; + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Container( + decoration: BoxDecoration( + color: parsed.color.withAlpha(isDark ? 15 : 10), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: parsed.color.withAlpha(40)), + ), + child: InkWell( + borderRadius: BorderRadius.circular(8), + onTap: parsed.detail != null ? () => _showRawLog(line) : null, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(parsed.icon, size: 16, color: parsed.color), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + parsed.friendlyMessage, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.w500, + ), + ), + if (parsed.time.isNotEmpty) ...[ + const SizedBox(height: 2), + Text( + parsed.time, + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + fontSize: 10, + ), + ), + ], + ], + ), + ), + if (parsed.detail != null) + Icon(Icons.chevron_right, + size: 14, color: theme.colorScheme.onSurfaceVariant), + ], ), ), + ), + ), + ); + } + + // 原始模式:等宽字体文本 + Widget _buildRawLogItem(String line, ThemeData theme) { + return Text( + line, + style: TextStyle( + fontFamily: 'monospace', + fontSize: 11, + color: _logColor(line, theme), + ), + ); + } + + void _showRawLog(String line) { + showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: Text(AppStrings.isChinese ? '原始日志' : 'Raw Log'), + content: SingleChildScrollView( + child: SelectableText( + line, + style: const TextStyle(fontFamily: 'monospace', fontSize: 12), + ), + ), + actions: [ + TextButton( + onPressed: () { + Clipboard.setData(ClipboardData(text: line)); + Navigator.pop(ctx); + }, + child: Text(AppStrings.copy), + ), + FilledButton( + onPressed: () => Navigator.pop(ctx), + child: Text(AppStrings.done), + ), ], ), ); @@ -142,20 +257,17 @@ class _LogsScreenState extends State { if (line.contains('[WARN]') || line.contains('WARNING')) { return AppColors.statusAmber; } - if (line.contains('[INFO]')) { - return AppColors.mutedText; - } + if (line.contains('[INFO]')) return AppColors.mutedText; return theme.colorScheme.onSurface; } Future _takeScreenshot() async { - final path = await ScreenshotService.capture(_screenshotKey, prefix: 'logs'); + final path = + await ScreenshotService.capture(_screenshotKey, prefix: 'logs'); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(path != null - ? 'Screenshot saved: ${path.split('/').last}' - : 'Failed to capture screenshot'), + content: Text(path != null ? '截图已保存: ${path.split('/').last}' : '截图失败'), ), ); } @@ -165,7 +277,7 @@ class _LogsScreenState extends State { final text = provider.state.logs.join('\n'); Clipboard.setData(ClipboardData(text: text)); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Logs copied to clipboard')), + SnackBar(content: Text(AppStrings.copied)), ); } } diff --git a/flutter_app/lib/screens/nine_router_terminal_screen.dart b/flutter_app/lib/screens/nine_router_terminal_screen.dart new file mode 100644 index 0000000..46f0747 --- /dev/null +++ b/flutter_app/lib/screens/nine_router_terminal_screen.dart @@ -0,0 +1,221 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:xterm/xterm.dart'; +import 'package:flutter_pty/flutter_pty.dart'; +import '../l10n/app_strings.dart'; +import '../services/native_bridge.dart'; +import '../services/terminal_service.dart'; +import '../widgets/terminal_toolbar.dart'; + +/// 9Router 专属终端,使用独立的 NineRouterService 保活进程 +class NineRouterTerminalScreen extends StatefulWidget { + const NineRouterTerminalScreen({super.key}); + + @override + State createState() => + _NineRouterTerminalScreenState(); +} + +class _NineRouterTerminalScreenState extends State { + late final Terminal _terminal; + late final TerminalController _controller; + Pty? _pty; + bool _loading = true; + String? _error; + final _ctrlNotifier = ValueNotifier(false); + final _altNotifier = ValueNotifier(false); + + static const _fontFallback = [ + 'monospace', + 'Noto Sans Mono', + 'Noto Sans Mono CJK SC', + 'Noto Color Emoji', + 'sans-serif', + ]; + + // 自动执行的启动命令 + static const _autoCommand = + 'nohup 9router --port 20128 > /tmp/9router.log 2>&1 & echo "9Router starting..." && sleep 2 && curl -s http://127.0.0.1:20128/ > /dev/null && echo "9Router is running on port 20128!" || echo "Starting in background, check CLIProxy console."\n'; + + @override + void initState() { + super.initState(); + _terminal = Terminal(maxLines: 10000); + _controller = TerminalController(); + // 使用独立的 NineRouterService + NativeBridge.startNineRouterService(); + WidgetsBinding.instance.addPostFrameCallback((_) => _startPty()); + } + + Future _startPty() async { + _pty?.kill(); + _pty = null; + try { + try { + await NativeBridge.setupDirs(); + } catch (_) {} + try { + await NativeBridge.writeResolv(); + } catch (_) {} + try { + final filesDir = await NativeBridge.getFilesDir(); + const rc = 'nameserver 8.8.8.8\nnameserver 8.8.4.4\n'; + final rf = File('$filesDir/config/resolv.conf'); + if (!rf.existsSync()) { + Directory('$filesDir/config').createSync(recursive: true); + rf.writeAsStringSync(rc); + } + final rr = File('$filesDir/rootfs/ubuntu/etc/resolv.conf'); + if (!rr.existsSync()) { + rr.parent.createSync(recursive: true); + rr.writeAsStringSync(rc); + } + } catch (_) {} + + final config = await TerminalService.getProotShellConfig(); + final args = TerminalService.buildProotArgs( + config, + columns: _terminal.viewWidth, + rows: _terminal.viewHeight, + ); + + _pty = Pty.start( + config['executable']!, + arguments: args, + environment: TerminalService.buildHostEnv(config), + columns: _terminal.viewWidth, + rows: _terminal.viewHeight, + ); + + _pty!.output.cast>().listen((data) { + _terminal.write(utf8.decode(data, allowMalformed: true)); + }); + + _pty!.exitCode.then((code) { + _terminal.write('\r\n[Process exited with code $code]\r\n'); + }); + + _terminal.onOutput = (data) { + if (_ctrlNotifier.value && data.length == 1) { + final code = data.toLowerCase().codeUnitAt(0); + if (code >= 97 && code <= 122) { + _pty?.write(Uint8List.fromList([code - 96])); + _ctrlNotifier.value = false; + return; + } + } + if (_altNotifier.value && data.isNotEmpty) { + _pty?.write(utf8.encode('\x1b$data')); + _altNotifier.value = false; + return; + } + _pty?.write(utf8.encode(data)); + }; + + _terminal.onResize = (w, h, pw, ph) => _pty?.resize(h, w); + + setState(() => _loading = false); + + // 等 shell 就绪后自动执行启动命令 + await Future.delayed(const Duration(milliseconds: 1500)); + _pty?.write(utf8.encode(_autoCommand)); + } catch (e) { + setState(() { + _loading = false; + _error = 'Failed to start: $e'; + }); + } + } + + @override + void dispose() { + _ctrlNotifier.dispose(); + _altNotifier.dispose(); + _controller.dispose(); + _pty?.kill(); + // 不停止 NineRouterService,让 9router 继续在后台运行 + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppStrings.isChinese ? '9Router 终端' : '9Router Terminal'), + actions: [ + IconButton( + icon: const Icon(Icons.refresh), + tooltip: AppStrings.restart, + onPressed: () { + _pty?.kill(); + setState(() { + _loading = true; + _error = null; + }); + _startPty(); + }, + ), + ], + ), + body: _loading + ? const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircularProgressIndicator(), + SizedBox(height: 16), + Text('正在启动 9Router...'), + ], + )) + : _error != null + ? Center( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, + size: 48, color: Theme.of(context).colorScheme.error), + const SizedBox(height: 16), + Text(_error!, textAlign: TextAlign.center), + const SizedBox(height: 16), + FilledButton.icon( + onPressed: () { + setState(() { + _loading = true; + _error = null; + }); + _startPty(); + }, + icon: const Icon(Icons.refresh), + label: Text(AppStrings.retry), + ), + ], + ), + )) + : Column( + children: [ + Expanded( + child: TerminalView( + _terminal, + controller: _controller, + textStyle: const TerminalStyle( + fontSize: 11, + height: 1.0, + fontFamily: 'DejaVuSansMono', + fontFamilyFallback: _fontFallback, + ), + ), + ), + TerminalToolbar( + pty: _pty, + ctrlNotifier: _ctrlNotifier, + altNotifier: _altNotifier, + ), + ], + ), + ); + } +} diff --git a/flutter_app/lib/screens/nine_router_webview_screen.dart b/flutter_app/lib/screens/nine_router_webview_screen.dart new file mode 100644 index 0000000..4ca4ee3 --- /dev/null +++ b/flutter_app/lib/screens/nine_router_webview_screen.dart @@ -0,0 +1,125 @@ +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; +import 'package:url_launcher/url_launcher.dart'; +import '../l10n/app_strings.dart'; +import '../utils/responsive.dart'; + +class NineRouterWebviewScreen extends StatefulWidget { + const NineRouterWebviewScreen({super.key}); + + @override + State createState() => + _NineRouterWebviewScreenState(); +} + +class _NineRouterWebviewScreenState extends State { + static const String _url = 'http://127.0.0.1:20128/'; + + late final WebViewController _controller; + bool _loading = true; + bool _hasError = false; + + @override + void initState() { + super.initState(); + _controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setNavigationDelegate(NavigationDelegate( + onPageStarted: (_) => setState(() { + _loading = true; + _hasError = false; + }), + onPageFinished: (_) => setState(() => _loading = false), + onWebResourceError: (error) { + if (error.isForMainFrame ?? true) { + setState(() { + _loading = false; + _hasError = true; + }); + } + }, + )) + ..loadRequest(Uri.parse(_url)); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isTablet = Responsive.isTablet(context); + + return Scaffold( + appBar: AppBar( + title: Text(AppStrings.isChinese ? '9Router 控制台' : '9Router Console'), + actions: [ + IconButton( + icon: const Icon(Icons.refresh), + tooltip: AppStrings.isChinese ? '刷新' : 'Refresh', + onPressed: () { + setState(() { + _loading = true; + _hasError = false; + }); + _controller.reload(); + }, + ), + IconButton( + icon: const Icon(Icons.open_in_browser), + tooltip: AppStrings.openInBrowser, + onPressed: () => launchUrl(Uri.parse(_url), + mode: LaunchMode.externalApplication), + ), + ], + ), + body: _hasError + ? Responsive.constrain(Center( + child: Padding( + padding: EdgeInsets.all(isTablet ? 48 : 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.cloud_off, + size: isTablet ? 80 : 64, + color: theme.colorScheme.onSurfaceVariant), + const SizedBox(height: 24), + Text( + AppStrings.isChinese + ? '9Router 未运行' + : '9Router is not running', + style: theme.textTheme.titleLarge + ?.copyWith(fontWeight: FontWeight.w600), + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + Text( + AppStrings.isChinese + ? '请先在"9Router 终端"中启动服务,然后返回此页面。' + : 'Please start the service in "9Router Terminal" first.', + style: theme.textTheme.bodyMedium + ?.copyWith(color: theme.colorScheme.onSurfaceVariant), + textAlign: TextAlign.center, + ), + const SizedBox(height: 32), + FilledButton.icon( + onPressed: () { + setState(() { + _loading = true; + _hasError = false; + }); + _controller.reload(); + }, + icon: const Icon(Icons.refresh), + label: Text(AppStrings.reconnect), + ), + ], + ), + ), + )) + : Stack( + children: [ + WebViewWidget(controller: _controller), + if (_loading) const Center(child: CircularProgressIndicator()), + ], + ), + ); + } +} diff --git a/flutter_app/lib/screens/node_screen.dart b/flutter_app/lib/screens/node_screen.dart index f9b012d..133dde0 100644 --- a/flutter_app/lib/screens/node_screen.dart +++ b/flutter_app/lib/screens/node_screen.dart @@ -1,8 +1,10 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../app.dart'; +import '../l10n/app_strings.dart'; import '../providers/node_provider.dart'; import '../services/preferences_service.dart'; +import '../utils/responsive.dart'; import '../widgets/node_controls.dart'; class NodeScreen extends StatefulWidget { @@ -53,226 +55,183 @@ class _NodeScreenState extends State { final theme = Theme.of(context); return Scaffold( - appBar: AppBar(title: const Text('Node Configuration')), + appBar: AppBar(title: Text(AppStrings.nodeConfiguration)), body: _loading ? const Center(child: CircularProgressIndicator()) - : Consumer( - builder: (context, provider, _) { - final state = provider.state; - - return ListView( - padding: const EdgeInsets.all(16), - children: [ - const NodeControls(), - const SizedBox(height: 16), - - // Gateway Connection - _sectionHeader(theme, 'GATEWAY CONNECTION'), - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RadioListTile( - title: const Text('Local Gateway'), - subtitle: const Text('Auto-pair with gateway on this device'), - value: true, - groupValue: _isLocal, - onChanged: (value) { - setState(() => _isLocal = value!); - }, - ), - RadioListTile( - title: const Text('Remote Gateway'), - subtitle: const Text('Connect to a gateway on another device'), - value: false, - groupValue: _isLocal, - onChanged: (value) { - setState(() => _isLocal = value!); - }, - ), - if (!_isLocal) ...[ - const SizedBox(height: 12), - TextField( - controller: _hostController, - decoration: const InputDecoration( - labelText: 'Gateway Host', - hintText: '192.168.1.100', - ), - ), - const SizedBox(height: 12), - TextField( - controller: _portController, - decoration: const InputDecoration( - labelText: 'Gateway Port', - hintText: '18789', - ), - keyboardType: TextInputType.number, - ), - const SizedBox(height: 12), - TextField( - controller: _tokenController, - decoration: const InputDecoration( - labelText: 'Gateway Token', - hintText: 'Paste token from gateway dashboard URL', - helperText: 'Found in dashboard URL after #token=', - prefixIcon: Icon(Icons.key), - ), - obscureText: true, - ), - const SizedBox(height: 12), - FilledButton.icon( - onPressed: () { - final host = _hostController.text.trim(); - final port = int.tryParse(_portController.text.trim()) ?? 18789; - final token = _tokenController.text.trim(); - if (host.isNotEmpty) { - provider.connectRemote(host, port, - token: token.isNotEmpty ? token : null); - } - }, - icon: const Icon(Icons.link), - label: const Text('Connect'), - ), - ], - ], - ), - ), - ), - const SizedBox(height: 16), - - // Pairing Status - if (state.pairingCode != null) ...[ - _sectionHeader(theme, 'PAIRING'), + : Responsive.constrain( + Consumer( + builder: (context, provider, _) { + final state = provider.state; + return ListView( + padding: const EdgeInsets.all(16), + children: [ + const NodeControls(), + const SizedBox(height: 16), + _sectionHeader(theme, AppStrings.gatewayConnection), Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Icon(Icons.qr_code, size: 48), - const SizedBox(height: 8), - Text( - 'Approve this code on the gateway:', - style: theme.textTheme.bodyMedium, + RadioListTile( + title: Text(AppStrings.localGateway), + subtitle: Text(AppStrings.localGatewaySubtitle), + value: true, + groupValue: _isLocal, + onChanged: (v) => setState(() => _isLocal = v!), ), - const SizedBox(height: 8), - SelectableText( - state.pairingCode!, - style: theme.textTheme.headlineMedium?.copyWith( - fontFamily: 'monospace', - fontWeight: FontWeight.bold, - color: theme.colorScheme.primary, - ), + RadioListTile( + title: Text(AppStrings.remoteGateway), + subtitle: + Text(AppStrings.remoteGatewaySubtitle), + value: false, + groupValue: _isLocal, + onChanged: (v) => setState(() => _isLocal = v!), ), + if (!_isLocal) ...[ + const SizedBox(height: 12), + TextField( + controller: _hostController, + decoration: InputDecoration( + labelText: AppStrings.gatewayHost, + hintText: '192.168.1.100', + ), + ), + const SizedBox(height: 12), + TextField( + controller: _portController, + decoration: InputDecoration( + labelText: AppStrings.gatewayPort, + hintText: '18789', + ), + keyboardType: TextInputType.number, + ), + const SizedBox(height: 12), + TextField( + controller: _tokenController, + decoration: InputDecoration( + labelText: AppStrings.gatewayToken, + hintText: AppStrings.gatewayTokenHint, + helperText: AppStrings.gatewayTokenHelper, + prefixIcon: const Icon(Icons.key), + ), + obscureText: true, + ), + const SizedBox(height: 12), + FilledButton.icon( + onPressed: () { + final host = _hostController.text.trim(); + final port = int.tryParse( + _portController.text.trim()) ?? + 18789; + final token = _tokenController.text.trim(); + if (host.isNotEmpty) { + provider.connectRemote(host, port, + token: + token.isNotEmpty ? token : null); + } + }, + icon: const Icon(Icons.link), + label: Text(AppStrings.connect), + ), + ], ], ), ), ), const SizedBox(height: 16), - ], - - // Capabilities - _sectionHeader(theme, 'CAPABILITIES'), - _capabilityTile( - theme, - 'Camera', - 'Capture photos and video clips', - Icons.camera_alt, - ), - _capabilityTile( - theme, - 'Canvas', - 'Not available on mobile', - Icons.web, - available: false, - ), - _capabilityTile( - theme, - 'Location', - 'Get device GPS coordinates', - Icons.location_on, - ), - _capabilityTile( - theme, - 'Screen Recording', - 'Record device screen (requires consent each time)', - Icons.screen_share, - ), - _capabilityTile( - theme, - 'Flashlight', - 'Toggle device torch on/off', - Icons.flashlight_on, - ), - _capabilityTile( - theme, - 'Vibration', - 'Trigger haptic feedback and vibration patterns', - Icons.vibration, - ), - _capabilityTile( - theme, - 'Sensors', - 'Read accelerometer, gyroscope, magnetometer, barometer', - Icons.sensors, - ), - _capabilityTile( - theme, - 'Serial', - 'Bluetooth and USB serial communication', - Icons.usb, - ), - const SizedBox(height: 16), - - // Device Info - if (state.deviceId != null) ...[ - _sectionHeader(theme, 'DEVICE INFO'), - ListTile( - title: const Text('Device ID'), - subtitle: SelectableText( - state.deviceId!, - style: const TextStyle(fontFamily: 'monospace', fontSize: 12), - ), - leading: const Icon(Icons.fingerprint), - ), - ], - const SizedBox(height: 16), - - // Logs - _sectionHeader(theme, 'NODE LOGS'), - Card( - child: Container( - height: 200, - padding: const EdgeInsets.all(12), - child: state.logs.isEmpty - ? Center( - child: Text( - 'No logs yet', - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, + if (state.pairingCode != null) ...[ + _sectionHeader(theme, AppStrings.pairing), + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + const Icon(Icons.qr_code, size: 48), + const SizedBox(height: 8), + Text(AppStrings.pairingPrompt, + style: theme.textTheme.bodyMedium), + const SizedBox(height: 8), + SelectableText( + state.pairingCode!, + style: + theme.textTheme.headlineMedium?.copyWith( + fontFamily: 'monospace', + fontWeight: FontWeight.bold, + color: theme.colorScheme.primary, ), ), - ) - : ListView.builder( - reverse: true, - itemCount: state.logs.length, - itemBuilder: (context, index) { - final log = state.logs[state.logs.length - 1 - index]; - return Text( - log, - style: const TextStyle( - fontFamily: 'monospace', - fontSize: 11, + ], + ), + ), + ), + const SizedBox(height: 16), + ], + _sectionHeader(theme, AppStrings.capabilities), + _capabilityTile(theme, AppStrings.capCamera, + AppStrings.capCameraDesc, Icons.camera_alt), + _capabilityTile(theme, AppStrings.capCanvas, + AppStrings.capCanvasDesc, Icons.web, + available: false), + _capabilityTile(theme, AppStrings.capLocation, + AppStrings.capLocationDesc, Icons.location_on), + _capabilityTile(theme, AppStrings.capScreen, + AppStrings.capScreenDesc, Icons.screen_share), + _capabilityTile(theme, AppStrings.capFlash, + AppStrings.capFlashDesc, Icons.flashlight_on), + _capabilityTile(theme, AppStrings.capVibration, + AppStrings.capVibrationDesc, Icons.vibration), + _capabilityTile(theme, AppStrings.capSensors, + AppStrings.capSensorsDesc, Icons.sensors), + _capabilityTile(theme, AppStrings.capSerial, + AppStrings.capSerialDesc, Icons.usb), + const SizedBox(height: 16), + if (state.deviceId != null) ...[ + _sectionHeader(theme, AppStrings.deviceInfo), + ListTile( + title: Text(AppStrings.deviceId), + subtitle: SelectableText( + state.deviceId!, + style: const TextStyle( + fontFamily: 'monospace', fontSize: 12), + ), + leading: const Icon(Icons.fingerprint), + ), + ], + const SizedBox(height: 16), + _sectionHeader(theme, AppStrings.nodeLogs), + Card( + child: Container( + height: 200, + padding: const EdgeInsets.all(12), + child: state.logs.isEmpty + ? Center( + child: Text( + AppStrings.noLogsYetNode, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, ), - ); - }, - ), + ), + ) + : ListView.builder( + reverse: true, + itemCount: state.logs.length, + itemBuilder: (context, index) { + final log = state + .logs[state.logs.length - 1 - index]; + return Text(log, + style: const TextStyle( + fontFamily: 'monospace', + fontSize: 11)); + }, + ), + ), ), - ), - ], - ); - }, + ], + ); + }, + ), ), ); } @@ -300,16 +259,9 @@ class _NodeScreenState extends State { title: Text(title), subtitle: Text(subtitle), trailing: available - ? const Icon( - Icons.check_circle, - color: AppColors.statusGreen, - size: 20, - ) - : const Icon( - Icons.block, - color: AppColors.statusAmber, - size: 20, - ), + ? const Icon(Icons.check_circle, + color: AppColors.statusGreen, size: 20) + : const Icon(Icons.block, color: AppColors.statusAmber, size: 20), ), ); } diff --git a/flutter_app/lib/screens/onboarding_screen.dart b/flutter_app/lib/screens/onboarding_screen.dart index b2e409e..685cd98 100644 --- a/flutter_app/lib/screens/onboarding_screen.dart +++ b/flutter_app/lib/screens/onboarding_screen.dart @@ -1,4 +1,4 @@ -import 'dart:convert'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -6,6 +6,7 @@ import 'package:xterm/xterm.dart'; import 'package:flutter_pty/flutter_pty.dart'; import 'package:url_launcher/url_launcher.dart'; import '../constants.dart'; +import '../l10n/app_strings.dart'; import '../services/native_bridge.dart'; import '../services/screenshot_service.dart'; import '../services/terminal_service.dart'; @@ -69,7 +70,7 @@ class _OnboardingScreenState extends State { // Defer PTY start until after the first frame so TerminalView has been // laid out and _terminal.viewWidth/viewHeight reflect real screen // dimensions instead of the 80×24 default. This is critical for QR - // codes — the shell must know the actual column count to avoid wrapping. + // codes �?the shell must know the actual column count to avoid wrapping. WidgetsBinding.instance.addPostFrameCallback((_) { _startOnboarding(); }); @@ -415,9 +416,9 @@ class _OnboardingScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('OpenClaw Onboarding'), + title: Text(AppStrings.openClawOnboarding), leading: widget.isFirstRun - ? null // no back button during first-run + ? null : IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => Navigator.of(context).pop(), @@ -426,22 +427,22 @@ class _OnboardingScreenState extends State { actions: [ IconButton( icon: const Icon(Icons.camera_alt_outlined), - tooltip: 'Screenshot', + tooltip: AppStrings.screenshot, onPressed: _takeScreenshot, ), IconButton( icon: const Icon(Icons.copy), - tooltip: 'Copy', + tooltip: AppStrings.copy, onPressed: _copySelection, ), IconButton( icon: const Icon(Icons.open_in_browser), - tooltip: 'Open URL', + tooltip: AppStrings.openUrl, onPressed: _openSelection, ), IconButton( icon: const Icon(Icons.paste), - tooltip: 'Paste', + tooltip: AppStrings.paste, onPressed: _paste, ), ], @@ -449,14 +450,14 @@ class _OnboardingScreenState extends State { body: Column( children: [ if (_loading) - const Expanded( + Expanded( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), SizedBox(height: 16), - Text('Starting onboarding...'), + Text(AppStrings.startingOnboarding), ], ), ), @@ -534,8 +535,8 @@ class _OnboardingScreenState extends State { ? Icons.arrow_forward : Icons.check), label: Text(widget.isFirstRun - ? 'Go to Dashboard' - : 'Done'), + ? AppStrings.goToDashboard + : AppStrings.done), ), ), ), diff --git a/flutter_app/lib/screens/package_install_screen.dart b/flutter_app/lib/screens/package_install_screen.dart index 9cb543d..1edbfe9 100644 --- a/flutter_app/lib/screens/package_install_screen.dart +++ b/flutter_app/lib/screens/package_install_screen.dart @@ -1,4 +1,4 @@ -import 'dart:convert'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -210,7 +210,7 @@ class _PackageInstallScreenState extends State { body: Column( children: [ if (_loading) - const Expanded( + Expanded( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, diff --git a/flutter_app/lib/screens/packages_screen.dart b/flutter_app/lib/screens/packages_screen.dart index 9324309..3d97ebb 100644 --- a/flutter_app/lib/screens/packages_screen.dart +++ b/flutter_app/lib/screens/packages_screen.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import '../app.dart'; import '../models/optional_package.dart'; import '../services/package_service.dart'; @@ -82,7 +82,7 @@ class _PackagesScreenState extends State { return Scaffold( appBar: AppBar(title: const Text('Optional Packages')), body: _loading - ? const Center(child: CircularProgressIndicator()) + ? Center(child: CircularProgressIndicator()) : ListView( padding: const EdgeInsets.all(16), children: [ diff --git a/flutter_app/lib/screens/provider_detail_screen.dart b/flutter_app/lib/screens/provider_detail_screen.dart index 8601b88..09633cd 100644 --- a/flutter_app/lib/screens/provider_detail_screen.dart +++ b/flutter_app/lib/screens/provider_detail_screen.dart @@ -1,9 +1,10 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import '../app.dart'; +import '../l10n/app_strings.dart'; import '../models/ai_provider.dart'; import '../services/provider_config_service.dart'; +import '../utils/responsive.dart'; -/// Form screen to configure API key and model for a single AI provider. class ProviderDetailScreen extends StatefulWidget { final AiProvider provider; final String? existingApiKey; @@ -25,29 +26,38 @@ class _ProviderDetailScreenState extends State { late final TextEditingController _apiKeyController; late final TextEditingController _customModelController; + late final TextEditingController _baseUrlController; late String _selectedModel; bool _isCustomModel = false; bool _obscureKey = true; bool _saving = false; bool _removing = false; - bool get _isConfigured => widget.existingApiKey != null && widget.existingApiKey!.isNotEmpty; + bool get _isCustomProvider => widget.provider.id == 'custom'; + + bool get _isConfigured => + widget.existingApiKey != null && widget.existingApiKey!.isNotEmpty; - /// Returns the effective model name to save. String get _effectiveModel => _isCustomModel ? _customModelController.text.trim() : _selectedModel; + String get _effectiveBaseUrl => _isCustomProvider + ? _baseUrlController.text.trim() + : widget.provider.baseUrl; + @override void initState() { super.initState(); - _apiKeyController = TextEditingController(text: widget.existingApiKey ?? ''); + _apiKeyController = + TextEditingController(text: widget.existingApiKey ?? ''); _customModelController = TextEditingController(); + _baseUrlController = TextEditingController(text: widget.provider.baseUrl); - final existing = widget.existingModel ?? widget.provider.defaultModels.first; + final existing = + widget.existingModel ?? widget.provider.defaultModels.first; if (widget.provider.defaultModels.contains(existing)) { _selectedModel = existing; } else { - // Existing model is not in the predefined list — treat as custom _selectedModel = _customModelSentinel; _isCustomModel = true; _customModelController.text = existing; @@ -56,6 +66,7 @@ class _ProviderDetailScreenState extends State { @override void dispose() { + _baseUrlController.dispose(); _apiKeyController.dispose(); _customModelController.dispose(); super.dispose(); @@ -65,14 +76,14 @@ class _ProviderDetailScreenState extends State { final apiKey = _apiKeyController.text.trim(); if (apiKey.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('API key cannot be empty')), + SnackBar(content: Text(AppStrings.apiKeyEmpty)), ); return; } final model = _effectiveModel; if (model.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Model name cannot be empty')), + SnackBar(content: Text(AppStrings.modelEmpty)), ); return; } @@ -83,17 +94,20 @@ class _ProviderDetailScreenState extends State { provider: widget.provider, apiKey: apiKey, model: model, + baseUrl: _effectiveBaseUrl, ); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('${widget.provider.name} configured and activated')), + SnackBar( + content: Text( + '${widget.provider.name} ${AppStrings.configuredAndActivated}')), ); Navigator.of(context).pop(true); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Failed to save: $e')), + SnackBar(content: Text('${AppStrings.saveFailed}: $e')), ); } } finally { @@ -105,16 +119,16 @@ class _ProviderDetailScreenState extends State { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( - title: Text('Remove ${widget.provider.name}?'), - content: const Text('This will delete the API key and deactivate the model.'), + title: Text('${AppStrings.removeProvider} ${widget.provider.name}?'), + content: Text(AppStrings.removeProviderContent), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), - child: const Text('Cancel'), + child: Text(AppStrings.cancel), ), FilledButton( onPressed: () => Navigator.pop(ctx, true), - child: const Text('Remove'), + child: Text(AppStrings.remove), ), ], ), @@ -124,17 +138,19 @@ class _ProviderDetailScreenState extends State { setState(() => _removing = true); try { - await ProviderConfigService.removeProviderConfig(provider: widget.provider); + await ProviderConfigService.removeProviderConfig( + provider: widget.provider); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('${widget.provider.name} removed')), + SnackBar( + content: Text('${widget.provider.name} ${AppStrings.remove}')), ); Navigator.of(context).pop(true); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Failed to remove: $e')), + SnackBar(content: Text('${AppStrings.removeFailed}: $e')), ); } } finally { @@ -150,134 +166,150 @@ class _ProviderDetailScreenState extends State { return Scaffold( appBar: AppBar(title: Text(widget.provider.name)), - body: ListView( - padding: const EdgeInsets.all(16), - children: [ - // Provider header - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: iconBg, - borderRadius: BorderRadius.circular(12), + body: Responsive.constrain( + ListView( + padding: const EdgeInsets.all(16), + children: [ + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: iconBg, + borderRadius: BorderRadius.circular(12), + ), + child: Icon(widget.provider.icon, + color: widget.provider.color), ), - child: Icon(widget.provider.icon, color: widget.provider.color), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.provider.name, - style: theme.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.provider.name, + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + ), ), - ), - const SizedBox(height: 4), - Text( - widget.provider.description, - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, + const SizedBox(height: 4), + Text( + widget.provider.description, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ), ), - ), - const SizedBox(height: 24), - - // API Key - Text( - 'API Key', - style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), - ), - const SizedBox(height: 8), - TextField( - controller: _apiKeyController, - obscureText: _obscureKey, - decoration: InputDecoration( - hintText: widget.provider.apiKeyHint, - suffixIcon: IconButton( - icon: Icon(_obscureKey ? Icons.visibility_off : Icons.visibility), - onPressed: () => setState(() => _obscureKey = !_obscureKey), - ), + const SizedBox(height: 24), + // Base URL - 仅 custom 提供商可编辑,其他只读显示 + Text( + 'Base URL', + style: theme.textTheme.titleSmall + ?.copyWith(fontWeight: FontWeight.w600), ), - ), - const SizedBox(height: 24), - - // Model selection - Text( - 'Model', - style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), - ), - const SizedBox(height: 8), - DropdownButtonFormField( - value: _selectedModel, - isExpanded: true, - decoration: const InputDecoration(), - items: [ - ...widget.provider.defaultModels - .map((m) => DropdownMenuItem(value: m, child: Text(m))), - const DropdownMenuItem( - value: _customModelSentinel, - child: Text('Custom...'), + const SizedBox(height: 8), + TextField( + controller: _baseUrlController, + readOnly: !_isCustomProvider, + decoration: InputDecoration( + hintText: 'http://127.0.0.1:18790/v1', + helperText: _isCustomProvider ? AppStrings.baseUrlHelper : null, ), - ], - onChanged: (value) { - if (value != null) { - setState(() { - _selectedModel = value; - _isCustomModel = value == _customModelSentinel; - }); - } - }, - ), - if (_isCustomModel) ...[ - const SizedBox(height: 12), + ), + const SizedBox(height: 24), + Text( + AppStrings.apiKey, + style: theme.textTheme.titleSmall + ?.copyWith(fontWeight: FontWeight.w600), + ), + const SizedBox(height: 8), TextField( - controller: _customModelController, - decoration: const InputDecoration( - hintText: 'e.g. meta/llama-3.3-70b-instruct', - labelText: 'Custom model name', + controller: _apiKeyController, + obscureText: _obscureKey, + decoration: InputDecoration( + hintText: widget.provider.apiKeyHint, + suffixIcon: IconButton( + icon: Icon( + _obscureKey ? Icons.visibility_off : Icons.visibility), + onPressed: () => setState(() => _obscureKey = !_obscureKey), + ), ), ), - ], - const SizedBox(height: 32), - - // Actions - FilledButton( - onPressed: _saving ? null : _save, - child: _saving - ? const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white), - ) - : const Text('Save & Activate'), - ), - if (_isConfigured) ...[ - const SizedBox(height: 12), - OutlinedButton( - onPressed: _removing ? null : _remove, - child: _removing + const SizedBox(height: 24), + Text( + AppStrings.model, + style: theme.textTheme.titleSmall + ?.copyWith(fontWeight: FontWeight.w600), + ), + const SizedBox(height: 8), + DropdownButtonFormField( + value: _selectedModel, + isExpanded: true, + decoration: const InputDecoration(), + items: [ + ...widget.provider.defaultModels + .map((m) => DropdownMenuItem(value: m, child: Text(m))), + DropdownMenuItem( + value: _customModelSentinel, + child: Text(AppStrings.customModel), + ), + ], + onChanged: (value) { + if (value != null) { + setState(() { + _selectedModel = value; + _isCustomModel = value == _customModelSentinel; + }); + } + }, + ), + if (_isCustomModel) ...[ + const SizedBox(height: 12), + TextField( + controller: _customModelController, + decoration: InputDecoration( + hintText: AppStrings.customModelHint, + labelText: AppStrings.customModelLabel, + ), + ), + ], + const SizedBox(height: 32), + FilledButton( + onPressed: _saving ? null : _save, + child: _saving ? const SizedBox( height: 20, width: 20, - child: CircularProgressIndicator(strokeWidth: 2), + child: CircularProgressIndicator( + strokeWidth: 2, color: Colors.white), ) - : const Text('Remove Configuration'), + : Text(AppStrings.saveAndActivate), ), + if (_isConfigured) ...[ + const SizedBox(height: 12), + OutlinedButton( + onPressed: _removing ? null : _remove, + child: _removing + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : Text(AppStrings.removeConfiguration), + ), + ], ], - ], + ), ), ); } diff --git a/flutter_app/lib/screens/providers_screen.dart b/flutter_app/lib/screens/providers_screen.dart index 3bbb535..baa8f82 100644 --- a/flutter_app/lib/screens/providers_screen.dart +++ b/flutter_app/lib/screens/providers_screen.dart @@ -1,7 +1,9 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import '../app.dart'; +import '../l10n/app_strings.dart'; import '../models/ai_provider.dart'; import '../services/provider_config_service.dart'; +import '../utils/responsive.dart'; import 'provider_detail_screen.dart'; /// Lists all AI providers with their configuration status. @@ -53,13 +55,12 @@ class _ProvidersScreenState extends State { String _statusLabel(AiProvider provider) { final isConfigured = _providers.containsKey(provider.id); if (!isConfigured) return ''; - // Check if the active model belongs to this provider if (_activeModel != null) { final isActive = provider.defaultModels.any((m) => _activeModel!.contains(m)) || _activeModel!.contains(provider.id); - if (isActive) return 'Active'; + if (isActive) return AppStrings.active; } - return 'Configured'; + return AppStrings.configured; } @override @@ -68,68 +69,69 @@ class _ProvidersScreenState extends State { final isDark = theme.brightness == Brightness.dark; return Scaffold( - appBar: AppBar(title: const Text('AI Providers')), + appBar: AppBar(title: Text(AppStrings.aiProviders)), body: _loading - ? const Center(child: CircularProgressIndicator()) - : ListView( - padding: const EdgeInsets.all(16), - children: [ - // Active model card - if (_activeModel != null && _activeModel!.isNotEmpty) ...[ - Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.statusGreen.withAlpha(25), - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - Icons.check_circle, - color: AppColors.statusGreen, + ? Center(child: CircularProgressIndicator()) + : Responsive.constrain( + ListView( + padding: const EdgeInsets.all(16), + children: [ + if (_activeModel != null && _activeModel!.isNotEmpty) ...[ + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: AppColors.statusGreen.withAlpha(25), + borderRadius: BorderRadius.circular(12), + ), + child: const Icon( + Icons.check_circle, + color: AppColors.statusGreen, + ), ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Active Model', - style: theme.textTheme.labelSmall?.copyWith( - color: AppColors.statusGreen, - fontWeight: FontWeight.w600, + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppStrings.activeModel, + style: theme.textTheme.labelSmall?.copyWith( + color: AppColors.statusGreen, + fontWeight: FontWeight.w600, + ), ), - ), - const SizedBox(height: 2), - Text( - _activeModel!, - style: theme.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, + const SizedBox(height: 2), + Text( + _activeModel!, + style: theme.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w600, + ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ), ), + const SizedBox(height: 16), + ], + Text( + AppStrings.selectProvider, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), ), const SizedBox(height: 16), + for (final provider in AiProvider.all) + _buildProviderCard(theme, provider, isDark), ], - Text( - 'Select a provider to configure its API key and model.', - style: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(height: 16), - for (final provider in AiProvider.all) - _buildProviderCard(theme, provider, isDark), - ], + ), ), ); } @@ -177,7 +179,7 @@ class _ProvidersScreenState extends State { vertical: 2, ), decoration: BoxDecoration( - color: (status == 'Active' + color: (status == AppStrings.active ? AppColors.statusGreen : AppColors.statusAmber) .withAlpha(25), @@ -186,7 +188,7 @@ class _ProvidersScreenState extends State { child: Text( status, style: theme.textTheme.labelSmall?.copyWith( - color: status == 'Active' + color: status == AppStrings.active ? AppColors.statusGreen : AppColors.statusAmber, fontWeight: FontWeight.w600, diff --git a/flutter_app/lib/screens/settings_screen.dart b/flutter_app/lib/screens/settings_screen.dart index 3aad664..dffeb49 100644 --- a/flutter_app/lib/screens/settings_screen.dart +++ b/flutter_app/lib/screens/settings_screen.dart @@ -1,4 +1,4 @@ -import 'dart:convert'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; @@ -6,10 +6,12 @@ import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import '../app.dart'; import '../constants.dart'; +import '../l10n/app_strings.dart'; import '../providers/node_provider.dart'; import '../services/native_bridge.dart'; import '../services/preferences_service.dart'; import '../services/update_service.dart'; +import '../utils/responsive.dart'; import 'node_screen.dart'; import 'setup_wizard_screen.dart'; @@ -85,253 +87,206 @@ class _SettingsScreenState extends State { final theme = Theme.of(context); return Scaffold( - appBar: AppBar(title: const Text('Settings')), + appBar: AppBar(title: Text(AppStrings.settings)), body: _loading - ? const Center(child: CircularProgressIndicator()) - : ListView( - children: [ - _sectionHeader(theme, 'GENERAL'), - SwitchListTile( - title: const Text('Auto-start gateway'), - subtitle: const Text('Start the gateway when the app opens'), - value: _autoStart, - onChanged: (value) { - setState(() => _autoStart = value); - _prefs.autoStartGateway = value; - }, - ), - ListTile( - title: const Text('Battery Optimization'), - subtitle: Text(_batteryOptimized - ? 'Optimized (may kill background sessions)' - : 'Unrestricted (recommended)'), - leading: const Icon(Icons.battery_alert), - trailing: _batteryOptimized - ? const Icon(Icons.warning, color: AppColors.statusAmber) - : const Icon(Icons.check_circle, color: AppColors.statusGreen), - onTap: () async { - await NativeBridge.requestBatteryOptimization(); - // Refresh status after returning from settings - final optimized = await NativeBridge.isBatteryOptimized(); - setState(() => _batteryOptimized = optimized); - }, - ), - ListTile( - title: const Text('Setup Storage'), - subtitle: Text(_storageGranted - ? 'Granted — proot can access /sdcard. Revoke if not needed.' - : 'Allow access to shared storage'), - leading: const Icon(Icons.sd_storage), - trailing: _storageGranted - ? const Icon(Icons.warning_amber, color: AppColors.statusAmber) - : const Icon(Icons.warning, color: AppColors.statusAmber), - onTap: () async { - await NativeBridge.requestStoragePermission(); - // Refresh after returning from permission screen - final granted = await NativeBridge.hasStoragePermission(); - setState(() => _storageGranted = granted); - }, - ), - const Divider(), - _sectionHeader(theme, 'NODE'), - SwitchListTile( - title: const Text('Enable Node'), - subtitle: const Text('Provide device capabilities to the gateway'), - value: _nodeEnabled, - onChanged: (value) { - setState(() => _nodeEnabled = value); - _prefs.nodeEnabled = value; - final nodeProvider = context.read(); - if (value) { - nodeProvider.enable(); - } else { - nodeProvider.disable(); - } - }, - ), - ListTile( - title: const Text('Node Configuration'), - subtitle: const Text('Connection, pairing, and capabilities'), - leading: const Icon(Icons.devices), - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const NodeScreen()), + ? Center(child: CircularProgressIndicator()) + : Responsive.constrain( + ListView( + children: [ + _sectionHeader(theme, AppStrings.general.toUpperCase()), + SwitchListTile( + title: Text(AppStrings.autoStartGateway), + subtitle: Text(AppStrings.autoStartSubtitle), + value: _autoStart, + onChanged: (value) { + setState(() => _autoStart = value); + _prefs.autoStartGateway = value; + }, ), - ), - const Divider(), - _sectionHeader(theme, 'SYSTEM INFO'), - ListTile( - title: const Text('Architecture'), - subtitle: Text(_arch), - leading: const Icon(Icons.memory), - ), - ListTile( - title: const Text('PRoot path'), - subtitle: Text(_prootPath), - leading: const Icon(Icons.folder), - ), - ListTile( - title: const Text('Rootfs'), - subtitle: Text(_status['rootfsExists'] == true - ? 'Installed' - : 'Not installed'), - leading: const Icon(Icons.storage), - ), - ListTile( - title: const Text('Node.js'), - subtitle: Text(_status['nodeInstalled'] == true - ? 'Installed' - : 'Not installed'), - leading: const Icon(Icons.code), - ), - ListTile( - title: const Text('OpenClaw'), - subtitle: Text(_status['openclawInstalled'] == true - ? 'Installed' - : 'Not installed'), - leading: const Icon(Icons.cloud), - ), - ListTile( - title: const Text('Go (Golang)'), - subtitle: Text(_goInstalled - ? 'Installed' - : 'Not installed'), - leading: const Icon(Icons.integration_instructions), - ), - ListTile( - title: const Text('Homebrew'), - subtitle: Text(_brewInstalled - ? 'Installed' - : 'Not installed'), - leading: const Icon(Icons.science), - ), - ListTile( - title: const Text('OpenSSH'), - subtitle: Text(_sshInstalled - ? 'Installed' - : 'Not installed'), - leading: const Icon(Icons.vpn_key), - ), - const Divider(), - _sectionHeader(theme, 'MAINTENANCE'), - ListTile( - title: const Text('Export Snapshot'), - subtitle: const Text('Backup config to Downloads'), - leading: const Icon(Icons.upload_file), - trailing: const Icon(Icons.chevron_right), - onTap: _exportSnapshot, - ), - ListTile( - title: const Text('Import Snapshot'), - subtitle: const Text('Restore config from backup'), - leading: const Icon(Icons.download), - trailing: const Icon(Icons.chevron_right), - onTap: _importSnapshot, - ), - ListTile( - title: const Text('Re-run setup'), - subtitle: const Text('Reinstall or repair the environment'), - leading: const Icon(Icons.build), - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (_) => const SetupWizardScreen(), + ListTile( + title: Text(AppStrings.batteryOptimization), + subtitle: Text(_batteryOptimized + ? AppStrings.batteryOptimized + : AppStrings.batteryUnrestricted), + leading: const Icon(Icons.battery_alert), + trailing: _batteryOptimized + ? const Icon(Icons.warning, color: AppColors.statusAmber) + : const Icon(Icons.check_circle, color: AppColors.statusGreen), + onTap: () async { + await NativeBridge.requestBatteryOptimization(); + final optimized = await NativeBridge.isBatteryOptimized(); + setState(() => _batteryOptimized = optimized); + }, + ), + ListTile( + title: Text(AppStrings.setupStorage), + subtitle: Text(_storageGranted + ? AppStrings.storageGranted + : AppStrings.storageNotGranted), + leading: const Icon(Icons.sd_storage), + trailing: _storageGranted + ? const Icon(Icons.warning_amber, color: AppColors.statusAmber) + : const Icon(Icons.warning, color: AppColors.statusAmber), + onTap: () async { + await NativeBridge.requestStoragePermission(); + final granted = await NativeBridge.hasStoragePermission(); + setState(() => _storageGranted = granted); + }, + ), + const Divider(), + _sectionHeader(theme, AppStrings.nodeSection.toUpperCase()), + SwitchListTile( + title: Text(AppStrings.enableNodeTitle), + subtitle: Text(AppStrings.enableNodeSubtitle), + value: _nodeEnabled, + onChanged: (value) { + setState(() => _nodeEnabled = value); + _prefs.nodeEnabled = value; + final nodeProvider = context.read(); + if (value) { + nodeProvider.enable(); + } else { + nodeProvider.disable(); + } + }, + ), + ListTile( + title: Text(AppStrings.nodeConfiguration), + subtitle: Text(AppStrings.nodeConfigSubtitle), + leading: const Icon(Icons.devices), + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const NodeScreen()), ), ), - ), - const Divider(), - _sectionHeader(theme, 'ABOUT'), - const ListTile( - title: Text('OpenClaw'), - subtitle: Text( - 'AI Gateway for Android\nVersion ${AppConstants.version}', + const Divider(), + _sectionHeader(theme, AppStrings.systemInfo.toUpperCase()), + ListTile( + title: Text(AppStrings.architecture), + subtitle: Text(_arch), + leading: const Icon(Icons.memory), ), - leading: Icon(Icons.info_outline), - isThreeLine: true, - ), - ListTile( - title: const Text('Check for Updates'), - subtitle: const Text('Check GitHub for a newer release'), - leading: _checkingUpdate - ? const SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator(strokeWidth: 2), - ) - : const Icon(Icons.system_update), - onTap: _checkingUpdate ? null : _checkForUpdates, - ), - const ListTile( - title: Text('Developer'), - subtitle: Text(AppConstants.authorName), - leading: Icon(Icons.person), - ), - ListTile( - title: const Text('GitHub'), - subtitle: const Text('mithun50/openclaw-termux'), - leading: const Icon(Icons.code), - trailing: const Icon(Icons.open_in_new, size: 18), - onTap: () => launchUrl( - Uri.parse(AppConstants.githubUrl), - mode: LaunchMode.externalApplication, + ListTile( + title: Text(AppStrings.prootPath), + subtitle: Text(_prootPath), + leading: const Icon(Icons.folder), ), - ), - ListTile( - title: const Text('Contact'), - subtitle: const Text(AppConstants.authorEmail), - leading: const Icon(Icons.email), - trailing: const Icon(Icons.open_in_new, size: 18), - onTap: () => launchUrl( - Uri.parse('mailto:${AppConstants.authorEmail}'), + ListTile( + title: Text(AppStrings.rootfs), + subtitle: Text(_status['rootfsExists'] == true + ? AppStrings.installed + : AppStrings.notInstalled), + leading: const Icon(Icons.storage), ), - ), - const ListTile( - title: Text('License'), - subtitle: Text(AppConstants.license), - leading: Icon(Icons.description), - ), - const Divider(), - _sectionHeader(theme, AppConstants.orgName.toUpperCase()), - ListTile( - title: const Text('Instagram'), - subtitle: const Text('@nexgenxplorer_nxg'), - leading: const Icon(Icons.camera_alt), - trailing: const Icon(Icons.open_in_new, size: 18), - onTap: () => launchUrl( - Uri.parse(AppConstants.instagramUrl), - mode: LaunchMode.externalApplication, + ListTile( + title: const Text('Node.js'), + subtitle: Text(_status['nodeInstalled'] == true + ? AppStrings.installed + : AppStrings.notInstalled), + leading: const Icon(Icons.code), ), - ), - ListTile( - title: const Text('YouTube'), - subtitle: const Text('@nexgenxplorer'), - leading: const Icon(Icons.play_circle_fill), - trailing: const Icon(Icons.open_in_new, size: 18), - onTap: () => launchUrl( - Uri.parse(AppConstants.youtubeUrl), - mode: LaunchMode.externalApplication, + ListTile( + title: const Text('OpenClaw'), + subtitle: Text(_status['openclawInstalled'] == true + ? AppStrings.installed + : AppStrings.notInstalled), + leading: const Icon(Icons.cloud), ), - ), - ListTile( - title: const Text('Play Store'), - subtitle: const Text('NextGenX Apps'), - leading: const Icon(Icons.shop), - trailing: const Icon(Icons.open_in_new, size: 18), - onTap: () => launchUrl( - Uri.parse(AppConstants.playStoreUrl), - mode: LaunchMode.externalApplication, + ListTile( + title: const Text('Go (Golang)'), + subtitle: Text(_goInstalled ? AppStrings.installed : AppStrings.notInstalled), + leading: const Icon(Icons.integration_instructions), + ), + ListTile( + title: const Text('Homebrew'), + subtitle: Text(_brewInstalled ? AppStrings.installed : AppStrings.notInstalled), + leading: const Icon(Icons.science), + ), + ListTile( + title: const Text('OpenSSH'), + subtitle: Text(_sshInstalled ? AppStrings.installed : AppStrings.notInstalled), + leading: const Icon(Icons.vpn_key), + ), + const Divider(), + _sectionHeader(theme, AppStrings.maintenance.toUpperCase()), + ListTile( + title: Text(AppStrings.exportSnapshot), + subtitle: Text(AppStrings.exportSnapshotSubtitle), + leading: const Icon(Icons.upload_file), + trailing: const Icon(Icons.chevron_right), + onTap: _exportSnapshot, + ), + ListTile( + title: Text(AppStrings.importSnapshot), + subtitle: Text(AppStrings.importSnapshotSubtitle), + leading: const Icon(Icons.download), + trailing: const Icon(Icons.chevron_right), + onTap: _importSnapshot, ), - ), - ListTile( - title: const Text('Email'), - subtitle: const Text(AppConstants.orgEmail), - leading: const Icon(Icons.email_outlined), - trailing: const Icon(Icons.open_in_new, size: 18), - onTap: () => launchUrl( - Uri.parse('mailto:${AppConstants.orgEmail}'), + ListTile( + title: Text(AppStrings.rerunSetup), + subtitle: Text(AppStrings.rerunSetupSubtitle), + leading: const Icon(Icons.build), + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (_) => const SetupWizardScreen(), + ), + ), + ), + const Divider(), + _sectionHeader(theme, AppStrings.about.toUpperCase()), + const ListTile( + title: Text('OpenClaw'), + subtitle: Text( + 'AI Gateway for Android\nVersion ${AppConstants.version}', + ), + leading: Icon(Icons.info_outline), + isThreeLine: true, ), - ), - ], + ListTile( + title: Text(AppStrings.checkForUpdates), + subtitle: Text(AppStrings.checkUpdatesSubtitle), + leading: _checkingUpdate + ? const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Icon(Icons.system_update), + onTap: _checkingUpdate ? null : _checkForUpdates, + ), + ListTile( + title: Text(AppStrings.developer), + subtitle: const Text(AppConstants.authorName), + leading: const Icon(Icons.person), + ), + ListTile( + title: Text(AppStrings.github), + subtitle: const Text('mithun50/openclaw-termux'), + leading: const Icon(Icons.code), + trailing: const Icon(Icons.open_in_new, size: 18), + onTap: () => launchUrl( + Uri.parse(AppConstants.githubUrl), + mode: LaunchMode.externalApplication, + ), + ), + ListTile( + title: Text(AppStrings.contact), + subtitle: const Text(AppConstants.authorEmail), + leading: const Icon(Icons.email), + trailing: const Icon(Icons.open_in_new, size: 18), + onTap: () => launchUrl( + Uri.parse('mailto:${AppConstants.authorEmail}'), + ), + ), + ListTile( + title: Text(AppStrings.license), + subtitle: const Text(AppConstants.license), + leading: const Icon(Icons.description), + ), + ], + ), ), ); } @@ -373,12 +328,12 @@ class _SettingsScreenState extends State { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Snapshot saved to $path')), + SnackBar(content: Text('${AppStrings.snapshotSaved}: $path')), ); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Export failed: $e')), + SnackBar(content: Text('${AppStrings.exportFailed}: $e')), ); } } @@ -391,7 +346,7 @@ class _SettingsScreenState extends State { if (!await file.exists()) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('No snapshot found at $path')), + SnackBar(content: Text('${AppStrings.noSnapshotFound}: $path')), ); return; } @@ -433,12 +388,12 @@ class _SettingsScreenState extends State { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Snapshot restored successfully. Restart the gateway to apply.')), + SnackBar(content: Text(AppStrings.snapshotRestored)), ); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Import failed: $e')), + SnackBar(content: Text('${AppStrings.importFailed}: $e')), ); } } @@ -452,16 +407,15 @@ class _SettingsScreenState extends State { showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('Update Available'), + title: Text(AppStrings.updateAvailable), content: Text( - 'A new version is available.\n\n' - 'Current: ${AppConstants.version}\n' - 'Latest: ${result.latest}', + '${AppStrings.currentVersion}: ${AppConstants.version}\n' + '${AppStrings.latestVersion}: ${result.latest}', ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), - child: const Text('Later'), + child: Text(AppStrings.later), ), FilledButton( onPressed: () { @@ -471,20 +425,20 @@ class _SettingsScreenState extends State { mode: LaunchMode.externalApplication, ); }, - child: const Text('Download'), + child: Text(AppStrings.download), ), ], ), ); } else { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text("You're on the latest version")), + SnackBar(content: Text(AppStrings.alreadyLatest)), ); } } catch (_) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Could not check for updates')), + SnackBar(content: Text(AppStrings.checkUpdateFailed)), ); } finally { if (mounted) setState(() => _checkingUpdate = false); diff --git a/flutter_app/lib/screens/setup_wizard_screen.dart b/flutter_app/lib/screens/setup_wizard_screen.dart index dc18c5d..a79ed76 100644 --- a/flutter_app/lib/screens/setup_wizard_screen.dart +++ b/flutter_app/lib/screens/setup_wizard_screen.dart @@ -1,11 +1,13 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../app.dart'; import '../constants.dart'; +import '../l10n/app_strings.dart'; import '../models/setup_state.dart'; import '../models/optional_package.dart'; import '../providers/setup_provider.dart'; import '../services/package_service.dart'; +import '../utils/responsive.dart'; import '../widgets/progress_step.dart'; import 'onboarding_screen.dart'; import 'package_install_screen.dart'; @@ -46,114 +48,116 @@ class _SetupWizardScreenState extends State { builder: (context, provider, _) { final state = provider.state; - // Load package statuses once setup completes if (state.isComplete && _pkgStatuses.isEmpty) { _refreshPkgStatuses(); } return Padding( padding: const EdgeInsets.all(24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 32), - Image.asset( - 'assets/ic_launcher.png', - width: 64, - height: 64, - ), - const SizedBox(height: 16), - Text( - 'Setup OpenClaw', - style: theme.textTheme.headlineSmall?.copyWith( - fontWeight: FontWeight.bold, + child: Responsive.constrain( + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 32), + Image.asset('assets/ic_launcher.png', + width: 64, height: 64), + const SizedBox(height: 16), + Text( + AppStrings.setupOpenClaw, + style: theme.textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.bold, + ), ), - ), - const SizedBox(height: 8), - Text( - _started - ? 'Setting up the environment. This may take several minutes.' - : 'This will download Ubuntu, Node.js, and OpenClaw into a self-contained environment.', - style: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.onSurfaceVariant, + const SizedBox(height: 8), + Text( + _started + ? AppStrings.setupRunning + : AppStrings.setupDescription, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), ), - ), - const SizedBox(height: 32), - Expanded( - child: _buildSteps(state, theme, isDark), - ), - if (state.hasError) ...[ - ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 160), - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: theme.colorScheme.errorContainer, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(Icons.error_outline, color: theme.colorScheme.error), - const SizedBox(width: 8), - Expanded( - child: SingleChildScrollView( - child: Text( - state.error ?? 'Unknown error', - style: TextStyle(color: theme.colorScheme.onErrorContainer), + const SizedBox(height: 32), + Expanded(child: _buildSteps(state, theme, isDark)), + if (state.hasError) ...[ + ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 160), + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: theme.colorScheme.errorContainer, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.error_outline, + color: theme.colorScheme.error), + const SizedBox(width: 8), + Expanded( + child: SingleChildScrollView( + child: Text( + AppStrings.translateError( + state.error ?? 'Unknown error'), + style: TextStyle( + color: + theme.colorScheme.onErrorContainer), + ), ), ), - ), - ], + ], + ), ), ), - ), - const SizedBox(height: 16), - ], - if (state.isComplete) - SizedBox( - width: double.infinity, - child: FilledButton.icon( - onPressed: () => _goToOnboarding(context), - icon: const Icon(Icons.arrow_forward), - label: const Text('Configure API Keys'), + const SizedBox(height: 16), + ], + if (state.isComplete) + SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: () => _goToOnboarding(context), + icon: const Icon(Icons.arrow_forward), + label: Text(AppStrings.configureApiKeys), + ), + ) + else if (!_started || state.hasError) + SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: provider.isRunning + ? null + : () { + setState(() => _started = true); + provider.runSetup(); + }, + icon: const Icon(Icons.download), + label: Text(_started + ? AppStrings.retrySetup + : AppStrings.beginSetup), + ), ), - ) - else if (!_started || state.hasError) - SizedBox( - width: double.infinity, - child: FilledButton.icon( - onPressed: provider.isRunning - ? null - : () { - setState(() => _started = true); - provider.runSetup(); - }, - icon: const Icon(Icons.download), - label: Text(_started ? 'Retry Setup' : 'Begin Setup'), + if (!_started) ...[ + const SizedBox(height: 8), + Center( + child: Text( + AppStrings.storageRequired, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), ), - ), - if (!_started) ...[ - const SizedBox(height: 8), + ], + const SizedBox(height: 16), Center( child: Text( - 'Requires ~500MB of storage and an internet connection', + 'by ${AppConstants.authorName} | ${AppConstants.orgName}', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ), ], - const SizedBox(height: 16), - Center( - child: Text( - 'by ${AppConstants.authorName} | ${AppConstants.orgName}', - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - ), - ), - ), - ], + ), ), ); }, @@ -164,11 +168,11 @@ class _SetupWizardScreenState extends State { Widget _buildSteps(SetupState state, ThemeData theme, bool isDark) { final steps = [ - (1, 'Download Ubuntu rootfs', SetupStep.downloadingRootfs), - (2, 'Extract rootfs', SetupStep.extractingRootfs), - (3, 'Install Node.js', SetupStep.installingNode), - (4, 'Install OpenClaw', SetupStep.installingOpenClaw), - (5, 'Configure Bionic Bypass', SetupStep.configuringBypass), + (1, AppStrings.downloadRootfs, SetupStep.downloadingRootfs), + (2, AppStrings.extractRootfs, SetupStep.extractingRootfs), + (3, AppStrings.installNode, SetupStep.installingNode), + (4, AppStrings.installOpenClaw, SetupStep.installingOpenClaw), + (5, AppStrings.configureBionicBypass, SetupStep.configuringBypass), ]; return ListView( @@ -183,16 +187,16 @@ class _SetupWizardScreenState extends State { progress: state.step == step ? state.progress : null, ), if (state.isComplete) ...[ - const ProgressStep( + ProgressStep( stepNumber: 6, - label: 'Setup complete!', + label: AppStrings.setupComplete, isComplete: true, ), const SizedBox(height: 24), Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( - 'OPTIONAL PACKAGES', + AppStrings.optionalPackages, style: theme.textTheme.labelSmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, fontWeight: FontWeight.w600, @@ -208,7 +212,8 @@ class _SetupWizardScreenState extends State { ); } - Widget _buildPackageTile(ThemeData theme, OptionalPackage package, bool isDark) { + Widget _buildPackageTile( + ThemeData theme, OptionalPackage package, bool isDark) { final installed = _pkgStatuses[package.id] ?? false; final iconBg = isDark ? AppColors.darkSurfaceAlt : const Color(0xFFF3F4F6); @@ -222,7 +227,8 @@ class _SetupWizardScreenState extends State { color: iconBg, borderRadius: BorderRadius.circular(10), ), - child: Icon(package.icon, color: theme.colorScheme.onSurfaceVariant, size: 22), + child: Icon(package.icon, + color: theme.colorScheme.onSurfaceVariant, size: 22), ), title: Row( children: [ @@ -231,17 +237,18 @@ class _SetupWizardScreenState extends State { if (installed) ...[ const SizedBox(width: 8), Container( - padding: - const EdgeInsets.symmetric(horizontal: 6, vertical: 1), + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1), decoration: BoxDecoration( color: AppColors.statusGreen.withAlpha(25), borderRadius: BorderRadius.circular(8), ), - child: Text('Installed', - style: theme.textTheme.labelSmall?.copyWith( - color: AppColors.statusGreen, - fontWeight: FontWeight.w600, - )), + child: Text( + AppStrings.installed, + style: theme.textTheme.labelSmall?.copyWith( + color: AppColors.statusGreen, + fontWeight: FontWeight.w600, + ), + ), ), ], ], @@ -251,7 +258,7 @@ class _SetupWizardScreenState extends State { ? const Icon(Icons.check_circle, color: AppColors.statusGreen) : OutlinedButton( onPressed: () => _installPackage(package), - child: const Text('Install'), + child: Text(AppStrings.install), ), ), ); diff --git a/flutter_app/lib/screens/splash_screen.dart b/flutter_app/lib/screens/splash_screen.dart index c6b5387..5639e84 100644 --- a/flutter_app/lib/screens/splash_screen.dart +++ b/flutter_app/lib/screens/splash_screen.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import '../constants.dart'; +import '../l10n/app_strings.dart'; import '../services/native_bridge.dart'; import '../services/preferences_service.dart'; import 'setup_wizard_screen.dart'; @@ -18,7 +19,7 @@ class SplashScreen extends StatefulWidget { class _SplashScreenState extends State with SingleTickerProviderStateMixin { - String _status = 'Loading...'; + String _status = AppStrings.loading; late final AnimationController _fadeController; late final Animation _fadeAnimation; @@ -47,7 +48,7 @@ class _SplashScreenState extends State await Future.delayed(const Duration(milliseconds: 500)); try { - setState(() => _status = 'Checking setup status...'); + setState(() => _status = AppStrings.checkingSetup); // Ensure directories and resolv.conf exist on every app open. // Android may clear the files directory during update or reinstall (#40). @@ -126,17 +127,17 @@ class _SplashScreenState extends State final openclawOk = status['openclawInstalled'] == true; final bypassOk = status['bypassInstalled'] == true; - // Core rootfs must exist — can't repair without it + // Core rootfs must exist ?can't repair without it if (rootfsOk && bashOk) { // Regenerate bionic bypass if missing if (!bypassOk) { - setState(() => _status = 'Repairing bionic bypass...'); + setState(() => _status = AppStrings.repairingBypass); await NativeBridge.installBionicBypass(); } // Reinstall node if binary is missing (#97) if (!nodeOk) { - setState(() => _status = 'Reinstalling Node.js...'); + setState(() => _status = AppStrings.reinstallingNode); try { final arch = await NativeBridge.getArch(); final nodeTarUrl = AppConstants.getNodeTarballUrl(arch); @@ -150,7 +151,7 @@ class _SplashScreenState extends State // Reinstall openclaw if package.json is missing (#97) if (!openclawOk && nodeOk) { - setState(() => _status = 'Reinstalling OpenClaw...'); + setState(() => _status = AppStrings.reinstallingOpenClaw); try { const wrapper = '/root/.openclaw/node-wrapper.js'; const nodeRun = 'node $wrapper'; @@ -213,7 +214,7 @@ class _SplashScreenState extends State ), const SizedBox(height: 8), Text( - 'AI Gateway for Android', + AppStrings.aiGatewayForAndroid, style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), diff --git a/flutter_app/lib/screens/ssh_screen.dart b/flutter_app/lib/screens/ssh_screen.dart index d14698d..ce95815 100644 --- a/flutter_app/lib/screens/ssh_screen.dart +++ b/flutter_app/lib/screens/ssh_screen.dart @@ -1,10 +1,10 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../app.dart'; import '../services/ssh_service.dart'; import 'packages_screen.dart'; -/// SSH server management screen — start/stop sshd, set password, show connection info. +/// SSH server management screen �?start/stop sshd, set password, show connection info. class SshScreen extends StatefulWidget { const SshScreen({super.key}); @@ -127,7 +127,7 @@ class _SshScreenState extends State { return Scaffold( appBar: AppBar(title: const Text('SSH Access')), body: _loading - ? const Center(child: CircularProgressIndicator()) + ? Center(child: CircularProgressIndicator()) : _installed ? _buildInstalledView(theme, isDark) : _buildNotInstalledView(theme), diff --git a/flutter_app/lib/screens/terminal_screen.dart b/flutter_app/lib/screens/terminal_screen.dart index 25bdeb9..5ca89b0 100644 --- a/flutter_app/lib/screens/terminal_screen.dart +++ b/flutter_app/lib/screens/terminal_screen.dart @@ -1,10 +1,11 @@ -import 'dart:convert'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:xterm/xterm.dart'; import 'package:flutter_pty/flutter_pty.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../l10n/app_strings.dart'; import '../services/native_bridge.dart'; import '../services/screenshot_service.dart'; import '../services/terminal_service.dart'; @@ -107,14 +108,14 @@ class _TerminalScreenState extends State { if (_ctrlNotifier.value && data.length == 1) { final code = data.toLowerCase().codeUnitAt(0); if (code >= 97 && code <= 122) { - // Ctrl+a-z → bytes 1-26 + // Ctrl+a-z �?bytes 1-26 _pty?.write(Uint8List.fromList([code - 96])); _ctrlNotifier.value = false; return; } } if (_altNotifier.value && data.isNotEmpty) { - // Alt+key → ESC + key + // Alt+key �?ESC + key _pty?.write(utf8.encode('\x1b$data')); _altNotifier.value = false; return; @@ -195,10 +196,10 @@ class _TerminalScreenState extends State { if (url != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: const Text('Copied to clipboard'), + content: Text(AppStrings.copied), duration: const Duration(seconds: 3), action: SnackBarAction( - label: 'Open', + label: '打开', onPressed: () { final uri = Uri.tryParse(url); if (uri != null) { @@ -210,9 +211,9 @@ class _TerminalScreenState extends State { ); } else { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Copied to clipboard'), - duration: Duration(seconds: 1), + SnackBar( + content: Text(AppStrings.copied), + duration: const Duration(seconds: 1), ), ); } @@ -231,9 +232,9 @@ class _TerminalScreenState extends State { } } ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('No URL found in selection'), - duration: Duration(seconds: 1), + SnackBar( + content: Text(AppStrings.noUrlFound), + duration: const Duration(seconds: 1), ), ); } @@ -251,8 +252,8 @@ class _TerminalScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(path != null - ? 'Screenshot saved: ${path.split('/').last}' - : 'Failed to capture screenshot'), + ? '截图已保�? ${path.split('/').last}' + : '截图失败'), ), ); } @@ -302,24 +303,24 @@ class _TerminalScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), - child: const Text('Cancel'), + child: Text(AppStrings.cancel), ), TextButton( onPressed: () { Clipboard.setData(ClipboardData(text: url)); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Link copied'), - duration: Duration(seconds: 1), + SnackBar( + content: Text(AppStrings.linkCopied), + duration: const Duration(seconds: 1), ), ); Navigator.pop(ctx, false); }, - child: const Text('Copy'), + child: Text(AppStrings.copy), ), FilledButton( onPressed: () => Navigator.pop(ctx, true), - child: const Text('Open'), + child: const Text('打开'), ), ], ), @@ -334,31 +335,31 @@ class _TerminalScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Terminal'), + title: Text(AppStrings.terminal), actions: [ IconButton( icon: const Icon(Icons.camera_alt_outlined), - tooltip: 'Screenshot', + tooltip: AppStrings.screenshot, onPressed: _takeScreenshot, ), IconButton( icon: const Icon(Icons.copy), - tooltip: 'Copy', + tooltip: AppStrings.copy, onPressed: _copySelection, ), IconButton( icon: const Icon(Icons.open_in_browser), - tooltip: 'Open URL', + tooltip: AppStrings.openUrl, onPressed: _openSelection, ), IconButton( icon: const Icon(Icons.paste), - tooltip: 'Paste', + tooltip: AppStrings.paste, onPressed: _paste, ), IconButton( icon: const Icon(Icons.refresh), - tooltip: 'Restart', + tooltip: AppStrings.restart, onPressed: () { _pty?.kill(); setState(() { @@ -376,13 +377,13 @@ class _TerminalScreenState extends State { Widget _buildBody() { if (_loading) { - return const Center( + return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), SizedBox(height: 16), - Text('Starting terminal...'), + Text(AppStrings.startingTerminal), ], ), ); @@ -416,7 +417,7 @@ class _TerminalScreenState extends State { _startPty(); }, icon: const Icon(Icons.refresh), - label: const Text('Retry'), + label: Text(AppStrings.retry), ), ], ), diff --git a/flutter_app/lib/services/bootstrap_service.dart b/flutter_app/lib/services/bootstrap_service.dart index 9399cbb..b934bfe 100644 --- a/flutter_app/lib/services/bootstrap_service.dart +++ b/flutter_app/lib/services/bootstrap_service.dart @@ -139,7 +139,7 @@ class BootstrapService { )); // Blanket recursive chmod on all bin/lib directories. // Java tar extraction loses execute bits; dpkg needs tar, xz, - // gzip, rm, mv, etc. — easier to fix everything than enumerate. + // gzip, rm, mv, etc. ?easier to fix everything than enumerate. await NativeBridge.runInProot( 'chmod -R 755 /usr/bin /usr/sbin /bin /sbin ' '/usr/local/bin /usr/local/sbin 2>/dev/null; ' @@ -153,7 +153,7 @@ class BootstrapService { // --- Install base packages via apt-get (like Termux proot-distro) --- // Now that our proot matches Termux exactly (env -i, clean host env, // proper flags), dpkg works normally. No need for Java-side deb - // extraction — let dpkg+tar handle it inside proot like Termux does. + // extraction ?let dpkg+tar handle it inside proot like Termux does. _updateSetupNotification('Updating package lists...', progress: 48); onProgress(const SetupState( step: SetupStep.installingNode, @@ -173,7 +173,7 @@ class BootstrapService { // python3, make, g++: node-gyp needs these to compile native addons // (npm's bundled node-gyp runs as a JS module, not a spawned process, // so proot-compat.js spawn mock can't intercept it) - // dpkg extracts via tar inside proot — permissions are correct. + // dpkg extracts via tar inside proot ?permissions are correct. // Post-install scripts (update-ca-certificates) run automatically. // Pre-configure tzdata to avoid interactive continent/timezone prompt // (tzdata is a dependency of python3 and ignores DEBIAN_FRONTEND on @@ -188,7 +188,7 @@ class BootstrapService { ); // Git config (.gitconfig) is written by installBionicBypass() on the - // Java side — directly to $rootfsDir/root/.gitconfig — rewrites + // Java side ?directly to $rootfsDir/root/.gitconfig ?rewrites // SSH→HTTPS for npm git deps (no SSH keys in proot). // --- Install Node.js via binary tarball --- @@ -259,7 +259,7 @@ class BootstrapService { progress: 0.0, message: 'Installing OpenClaw (this may take a few minutes)...', )); - // Install openclaw — fork/exec works now with our Termux-matching proot. + // Install openclaw ?fork/exec works now with our Termux-matching proot. await NativeBridge.runInProot( '$nodeRun $npmCli install -g openclaw', timeout: 1800, @@ -273,7 +273,7 @@ class BootstrapService { )); // npm global install creates symlinks for bin entries, but symlinks // can fail silently in proot. Create shell wrappers from Java side - // (reads package.json directly from rootfs filesystem — no escaping). + // (reads package.json directly from rootfs filesystem ?no escaping). await NativeBridge.createBinWrappers('openclaw'); _updateSetupNotification('Verifying OpenClaw...', progress: 96); diff --git a/flutter_app/lib/services/capabilities/flash_capability.dart b/flutter_app/lib/services/capabilities/flash_capability.dart index 217f0b4..6f66dc6 100644 --- a/flutter_app/lib/services/capabilities/flash_capability.dart +++ b/flutter_app/lib/services/capabilities/flash_capability.dart @@ -34,7 +34,7 @@ class FlashCapability extends CapabilityHandler { if (_controller!.value.isInitialized && !_controller!.value.hasError) { return _controller!; } - // Controller is stale/errored — dispose and recreate + // Controller is stale/errored ?dispose and recreate try { _controller!.dispose(); } catch (_) {} _controller = null; } diff --git a/flutter_app/lib/services/gateway_service.dart b/flutter_app/lib/services/gateway_service.dart index a51097f..d97c1fe 100644 --- a/flutter_app/lib/services/gateway_service.dart +++ b/flutter_app/lib/services/gateway_service.dart @@ -196,7 +196,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); } } - /// Repair openclaw.json on disk — fixes corrupted model entries and ensures + /// Repair openclaw.json on disk ?fixes corrupted model entries and ensures /// gateway.mode=local is set. Called on init() before any gateway start (#88). Future _repairConfigFile() async { try { @@ -210,7 +210,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); try { config = Map.from(jsonDecode(content) as Map); } catch (_) { - return; // Unparseable — _writeNodeAllowConfig will recreate it + return; // Unparseable ?_writeNodeAllowConfig will recreate it } bool modified = false; @@ -223,7 +223,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); modified = true; } - // Fix model entries: strings → objects (#83, #88) + // Fix model entries: strings ?objects (#83, #88) final models = config['models'] as Map?; if (models != null) { final providers = models['providers'] as Map?; @@ -272,7 +272,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); } /// Read the actual gateway auth token from openclaw.json config file (#74, #82). - /// This is the source of truth — more reliable than regex-scraping stdout. + /// This is the source of truth ?more reliable than regex-scraping stdout. Future _readTokenFromConfig() async { try { final raw = await NativeBridge.readRootfsFile('root/.openclaw/openclaw.json'); @@ -308,7 +308,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); )); try { - // Ensure directories exist — Android may have cleared them (#40). + // Ensure directories exist ?Android may have cleared them (#40). // Non-fatal: the GatewayService foreground service also creates them. try { await NativeBridge.setupDirs(); } catch (_) {} try { await NativeBridge.writeResolv(); } catch (_) {} @@ -373,7 +373,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); void _startHealthCheck() { _cancelAllTimers(); - // Delay the first health check by 30s — Node.js inside proot needs time to start. + // Delay the first health check by 30s ?Node.js inside proot needs time to start. // Use a Timer (not Future.delayed) so it can be cancelled on stop(). _initialDelayTimer = Timer(const Duration(seconds: 30), () { _initialDelayTimer = null; @@ -393,7 +393,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); .timeout(const Duration(seconds: 3)); if (response.statusCode < 500 && _state.status != GatewayStatus.running) { - // Read the actual token from openclaw.json — source of truth (#74, #82). + // Read the actual token from openclaw.json ?source of truth (#74, #82). // This ensures the displayed token always matches the gateway's config, // even if the stdout regex didn't capture it. String? configUrl = _state.dashboardUrl; diff --git a/flutter_app/lib/services/native_bridge.dart b/flutter_app/lib/services/native_bridge.dart index 70b0cbe..e9cf76c 100644 --- a/flutter_app/lib/services/native_bridge.dart +++ b/flutter_app/lib/services/native_bridge.dart @@ -35,7 +35,8 @@ class NativeBridge { } static Future runInProot(String command, {int timeout = 900}) async { - return await _channel.invokeMethod('runInProot', {'command': command, 'timeout': timeout}); + return await _channel + .invokeMethod('runInProot', {'command': command, 'timeout': timeout}); } static Future startGateway() async { @@ -67,11 +68,13 @@ class NativeBridge { } static Future extractNodeTarball(String tarPath) async { - return await _channel.invokeMethod('extractNodeTarball', {'tarPath': tarPath}); + return await _channel + .invokeMethod('extractNodeTarball', {'tarPath': tarPath}); } static Future createBinWrappers(String packageName) async { - return await _channel.invokeMethod('createBinWrappers', {'packageName': packageName}); + return await _channel + .invokeMethod('createBinWrappers', {'packageName': packageName}); } static Future startTerminalService() async { @@ -86,6 +89,18 @@ class NativeBridge { return await _channel.invokeMethod('isTerminalServiceRunning'); } + static Future startNineRouterService() async { + return await _channel.invokeMethod('startNineRouterService'); + } + + static Future stopNineRouterService() async { + return await _channel.invokeMethod('stopNineRouterService'); + } + + static Future isNineRouterServiceRunning() async { + return await _channel.invokeMethod('isNineRouterServiceRunning'); + } + static Future startNodeService() async { return await _channel.invokeMethod('startNodeService'); } @@ -99,7 +114,8 @@ class NativeBridge { } static Future updateNodeNotification(String text) async { - return await _channel.invokeMethod('updateNodeNotification', {'text': text}); + return await _channel + .invokeMethod('updateNodeNotification', {'text': text}); } static Future requestBatteryOptimization() async { @@ -114,24 +130,31 @@ class NativeBridge { return await _channel.invokeMethod('startSetupService'); } - static Future updateSetupNotification(String text, {int progress = -1}) async { - return await _channel.invokeMethod('updateSetupNotification', {'text': text, 'progress': progress}); + static Future updateSetupNotification(String text, + {int progress = -1}) async { + return await _channel.invokeMethod( + 'updateSetupNotification', {'text': text, 'progress': progress}); } static Future stopSetupService() async { return await _channel.invokeMethod('stopSetupService'); } - static Future showUrlNotification(String url, {String title = 'URL Detected'}) async { - return await _channel.invokeMethod('showUrlNotification', {'url': url, 'title': title}); + static Future showUrlNotification(String url, + {String title = 'URL Detected'}) async { + return await _channel + .invokeMethod('showUrlNotification', {'url': url, 'title': title}); } static Stream get gatewayLogStream { - return _eventChannel.receiveBroadcastStream().map((event) => event.toString()); + return _eventChannel + .receiveBroadcastStream() + .map((event) => event.toString()); } static Future requestScreenCapture(int durationMs) async { - return await _channel.invokeMethod('requestScreenCapture', {'durationMs': durationMs}); + return await _channel + .invokeMethod('requestScreenCapture', {'durationMs': durationMs}); } static Future stopScreenCapture() async { @@ -155,7 +178,8 @@ class NativeBridge { } static Future writeRootfsFile(String path, String content) async { - return await _channel.invokeMethod('writeRootfsFile', {'path': path, 'content': content}); + return await _channel + .invokeMethod('writeRootfsFile', {'path': path, 'content': content}); } // SSH Service @@ -185,6 +209,7 @@ class NativeBridge { } static Future setRootPassword(String password) async { - return await _channel.invokeMethod('setRootPassword', {'password': password}); + return await _channel + .invokeMethod('setRootPassword', {'password': password}); } } diff --git a/flutter_app/lib/services/node_service.dart b/flutter_app/lib/services/node_service.dart index 95c9256..465784c 100644 --- a/flutter_app/lib/services/node_service.dart +++ b/flutter_app/lib/services/node_service.dart @@ -263,7 +263,7 @@ class NodeService { )); _log('[NODE] Paired and connected'); - // Send capabilities advertisement — include both 'capabilities' (legacy) + // Send capabilities advertisement ?include both 'capabilities' (legacy) // and 'commands' (matching the connect frame format) so the gateway can // discover node commands regardless of which field it checks (#56). final capabilities = _capabilityHandlers.keys.toList(); diff --git a/flutter_app/lib/services/package_service.dart b/flutter_app/lib/services/package_service.dart index 50bd5e5..906e023 100644 --- a/flutter_app/lib/services/package_service.dart +++ b/flutter_app/lib/services/package_service.dart @@ -21,7 +21,7 @@ class PackageService { } /// Check installation status for all optional packages. - /// Returns a map of package id → installed boolean. + /// Returns a map of package id ?installed boolean. static Future> checkAllStatuses() async { final rootfs = await _getRootfsDir(); final statuses = {}; diff --git a/flutter_app/lib/services/provider_config_service.dart b/flutter_app/lib/services/provider_config_service.dart index 41f1cfc..8f090cd 100644 --- a/flutter_app/lib/services/provider_config_service.dart +++ b/flutter_app/lib/services/provider_config_service.dart @@ -39,7 +39,8 @@ class ProviderConfigService { final providers = {}; final modelsSection = config['models'] as Map?; if (modelsSection != null) { - final providerEntries = modelsSection['providers'] as Map?; + final providerEntries = + modelsSection['providers'] as Map?; if (providerEntries != null) { for (final entry in providerEntries.entries) { providers[entry.key] = entry.value; @@ -60,10 +61,12 @@ class ProviderConfigService { required AiProvider provider, required String apiKey, required String model, + String? baseUrl, }) async { + final effectiveBaseUrl = baseUrl ?? provider.baseUrl; final providerIdJson = jsonEncode(provider.id); final apiKeyJson = jsonEncode(apiKey); - final baseUrlJson = jsonEncode(provider.baseUrl); + final baseUrlJson = jsonEncode(effectiveBaseUrl); final modelJson = jsonEncode(model); // Build the provider object with the model as an object containing `id`, @@ -100,7 +103,7 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); await _saveConfigDirect( providerId: provider.id, apiKey: apiKey, - baseUrl: provider.baseUrl, + baseUrl: effectiveBaseUrl, model: model, ); } @@ -123,20 +126,28 @@ fs.writeFileSync(p, JSON.stringify(c, null, 2)); // Start fresh } - // Merge provider entry — models must be objects with `id`, not bare strings (#83, #88). + // Merge provider entry �?models must be objects with `id`, not bare strings (#83, #88). config['models'] ??= {}; - (config['models'] as Map)['providers'] ??= {}; - ((config['models'] as Map)['providers'] as Map)[providerId] = { + (config['models'] as Map)['providers'] ??= + {}; + ((config['models'] as Map)['providers'] + as Map)[providerId] = { 'apiKey': apiKey, 'baseUrl': baseUrl, - 'models': [{'id': model}], + 'models': [ + {'id': model} + ], }; // Set active model config['agents'] ??= {}; - (config['agents'] as Map)['defaults'] ??= {}; - ((config['agents'] as Map)['defaults'] as Map)['model'] ??= {}; - (((config['agents'] as Map)['defaults'] as Map)['model'] as Map)['primary'] = model; + (config['agents'] as Map)['defaults'] ??= + {}; + ((config['agents'] as Map)['defaults'] + as Map)['model'] ??= {}; + (((config['agents'] as Map)['defaults'] + as Map)['model'] + as Map)['primary'] = model; // Ensure gateway.mode is set (#93, #90) config['gateway'] ??= {}; diff --git a/flutter_app/lib/services/terminal_service.dart b/flutter_app/lib/services/terminal_service.dart index a757957..b4f29b8 100644 --- a/flutter_app/lib/services/terminal_service.dart +++ b/flutter_app/lib/services/terminal_service.dart @@ -13,10 +13,10 @@ class TerminalService { '#1 SMP PREEMPT_DYNAMIC Fri, 10 Oct 2025 00:00:00 +0000'; /// Get paths and host-side proot environment variables. - /// Host env should ONLY contain proot-specific vars — guest env is + /// Host env should ONLY contain proot-specific vars ?guest env is /// set via `env -i` inside the command, matching proot-distro. /// - /// Also ensures directories and resolv.conf exist — Android may clear + /// Also ensures directories and resolv.conf exist ?Android may clear /// them during an app update (#40). Every screen that uses proot calls /// this method, so it's the single place to guarantee the files exist. static Future> getProotShellConfig() async { @@ -64,7 +64,7 @@ class TerminalService { 'libDir': libDir, 'nativeLibDir': nativeLibDir, 'storageGranted': storageGranted.toString(), - // Host-side proot env — ONLY proot-specific vars. + // Host-side proot env ?ONLY proot-specific vars. // Do NOT set PROOT_NO_SECCOMP (proot-distro doesn't set it). // Do NOT set HOME/TERM/LANG here (those go in guest env via env -i). 'PROOT_TMP_DIR': tmpDir, @@ -76,7 +76,7 @@ class TerminalService { /// Build proot arguments matching ProcessManager.kt's gateway mode /// (proot-distro command_login). Uses `env -i` for a clean guest - /// environment — prevents Android JVM vars from leaking into proot. + /// environment ?prevents Android JVM vars from leaking into proot. static List buildProotArgs(Map config, {int columns = 80, int rows = 24}) { final procFakes = '${config['configDir']}/proc_fakes'; @@ -161,7 +161,7 @@ class TerminalService { } /// Host-side environment map for Pty.start(). - /// Only proot-specific vars — no guest vars (those are in env -i). + /// Only proot-specific vars ?no guest vars (those are in env -i). static Map buildHostEnv(Map config) { return { 'PROOT_TMP_DIR': config['PROOT_TMP_DIR']!, diff --git a/flutter_app/lib/utils/log_parser.dart b/flutter_app/lib/utils/log_parser.dart new file mode 100644 index 0000000..71fd5b8 --- /dev/null +++ b/flutter_app/lib/utils/log_parser.dart @@ -0,0 +1,227 @@ +import 'package:flutter/material.dart'; +import '../app.dart'; +import '../l10n/app_strings.dart'; + +enum LogLevel { info, warn, error, success, debug, system } + +class ParsedLog { + final LogLevel level; + final String time; + final String rawMessage; + final String friendlyMessage; // 中文友好说明 + final String? detail; // 可选的技术细节 + final IconData icon; + final Color color; + + const ParsedLog({ + required this.level, + required this.time, + required this.rawMessage, + required this.friendlyMessage, + this.detail, + required this.icon, + required this.color, + }); +} + +class LogParser { + static ParsedLog parse(String raw, ThemeData theme) { + final time = _extractTime(raw); + final msg = _stripTime(raw).trim(); + + // 错误级别 + if (_isError(msg)) { + return ParsedLog( + level: LogLevel.error, + time: time, + rawMessage: raw, + friendlyMessage: _translateError(msg), + detail: msg, + icon: Icons.error_outline, + color: theme.colorScheme.error, + ); + } + + // 警告级别 + if (_isWarn(msg)) { + return ParsedLog( + level: LogLevel.warn, + time: time, + rawMessage: raw, + friendlyMessage: _translateWarn(msg), + detail: msg, + icon: Icons.warning_amber_outlined, + color: AppColors.statusAmber, + ); + } + + // 成功/健康 + if (_isSuccess(msg)) { + return ParsedLog( + level: LogLevel.success, + time: time, + rawMessage: raw, + friendlyMessage: _translateSuccess(msg), + icon: Icons.check_circle_outline, + color: AppColors.statusGreen, + ); + } + + // 系统/启动 + if (_isSystem(msg)) { + return ParsedLog( + level: LogLevel.system, + time: time, + rawMessage: raw, + friendlyMessage: _translateSystem(msg), + icon: Icons.settings_outlined, + color: AppColors.mutedText, + ); + } + + // 普通信息 + return ParsedLog( + level: LogLevel.info, + time: time, + rawMessage: raw, + friendlyMessage: _translateInfo(msg), + icon: Icons.info_outline, + color: AppColors.mutedText, + ); + } + + static String _extractTime(String raw) { + // ISO 时间格式: 2024-01-01T12:00:00.000Z + final iso = RegExp(r'\d{4}-\d{2}-\d{2}T(\d{2}:\d{2}:\d{2})'); + final m = iso.firstMatch(raw); + if (m != null) return m.group(1)!; + // HH:MM:SS 格式 + final hms = RegExp(r'(\d{2}:\d{2}:\d{2})'); + final m2 = hms.firstMatch(raw); + if (m2 != null) return m2.group(1)!; + return ''; + } + + static String _stripTime(String raw) { + return raw + .replaceAll( + RegExp(r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z?\s*'), '') + .replaceAll(RegExp(r'\[\w+\]\s*'), '') + .trim(); + } + + static bool _isError(String msg) => + msg.contains('[ERR]') || + msg.contains('ERROR') || + msg.contains('error') || + msg.contains('failed') || + msg.contains('Failed') || + msg.contains('exception') || + msg.contains('ECONNREFUSED') || + msg.contains('ENOENT'); + + static bool _isWarn(String msg) => + msg.contains('[WARN]') || + msg.contains('WARNING') || + msg.contains('warn') || + msg.contains('deprecated'); + + static bool _isSuccess(String msg) => + msg.contains('healthy') || + msg.contains('ready') || + msg.contains('started') || + msg.contains('connected') || + msg.contains('complete') || + msg.contains('success') || + msg.contains('Gateway is healthy') || + msg.contains('Running'); + + static bool _isSystem(String msg) => + msg.contains('Starting') || + msg.contains('Stopping') || + msg.contains('Auto-start') || + msg.contains('reconnect') || + msg.contains('detected') || + msg.contains('process'); + + static String _translateError(String msg) { + if (!AppStrings.isChinese) return msg; + if (msg.contains('ECONNREFUSED') || msg.contains('Connection refused')) { + return '连接被拒绝:网关服务未响应,请检查是否已启动'; + } + if (msg.contains('ENOENT') || msg.contains('No such file')) { + return '文件不存在:安装可能不完整,建议重新安装'; + } + if (msg.contains('timeout') || msg.contains('Timeout')) { + return '连接超时:网络或服务响应过慢'; + } + if (msg.contains('Failed to start')) { + return '启动失败:请检查环境是否正确安装'; + } + if (msg.contains('permission') || msg.contains('Permission')) { + return '权限不足:请检查应用权限设置'; + } + if (msg.contains('port') || msg.contains('Port')) { + return '端口错误:18789 端口可能被占用'; + } + if (msg.contains('memory') || msg.contains('Memory')) { + return '内存不足:请关闭其他应用后重试'; + } + return '发生错误:$msg'; + } + + static String _translateWarn(String msg) { + if (!AppStrings.isChinese) return msg; + if (msg.contains('deprecated')) return '功能已过时,建议更新版本'; + if (msg.contains('retry') || msg.contains('Retry')) return '正在重试连接...'; + if (msg.contains('slow') || msg.contains('Slow')) return '响应较慢,请耐心等待'; + if (msg.contains('not running')) return '网关进程未运行'; + return '警告:$msg'; + } + + static String _translateSuccess(String msg) { + if (!AppStrings.isChinese) return msg; + if (msg.contains('healthy') || msg.contains('Gateway is healthy')) { + return '✓ 网关运行正常,服务健康'; + } + if (msg.contains('started') || msg.contains('Starting gateway')) { + return '网关正在启动中...'; + } + if (msg.contains('connected') || msg.contains('reconnecting')) { + return '已连接到网关服务'; + } + if (msg.contains('complete') || msg.contains('success')) { + return '操作成功完成'; + } + if (msg.contains('Running') || msg.contains('ready')) { + return '服务已就绪,可以开始使用'; + } + return msg; + } + + static String _translateSystem(String msg) { + if (!AppStrings.isChinese) return msg; + if (msg.contains('Auto-starting')) return '自动启动网关...'; + if (msg.contains('Starting gateway')) return '正在启动网关服务...'; + if (msg.contains('Stopping') || msg.contains('stopped')) return '网关已停止'; + if (msg.contains('detected') || msg.contains('reconnecting')) { + return '检测到网关进程,正在重新连接...'; + } + if (msg.contains('waiting')) return '等待网关启动,请稍候...'; + if (msg.contains('process not running')) return '网关进程已退出'; + return msg; + } + + static String _translateInfo(String msg) { + if (!AppStrings.isChinese) return msg; + if (msg.contains('token') || msg.contains('Token')) { + return '获取到访问令牌,控制台已就绪'; + } + if (msg.contains('Dashboard')) return '控制台地址已更新'; + if (msg.contains('health') || msg.contains('Health')) + return '正在检查服务健康状态...'; + if (msg.contains('log') || msg.contains('Log')) return '日志记录中'; + if (msg.isEmpty) return '系统消息'; + return msg; + } +} diff --git a/flutter_app/lib/utils/responsive.dart b/flutter_app/lib/utils/responsive.dart new file mode 100644 index 0000000..ca6508f --- /dev/null +++ b/flutter_app/lib/utils/responsive.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class Responsive { + static const double tabletBreakpoint = 600.0; + static const double maxContentWidth = 720.0; + + static bool isTablet(BuildContext context) => + MediaQuery.of(context).size.width >= tabletBreakpoint; + + /// 平板上限制内容最大宽度并居中,手机上全宽 + static Widget constrain(Widget child) { + return Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: maxContentWidth), + child: child, + ), + ); + } +} diff --git a/flutter_app/lib/widgets/gateway_controls.dart b/flutter_app/lib/widgets/gateway_controls.dart index 52c524b..c260cba 100644 --- a/flutter_app/lib/widgets/gateway_controls.dart +++ b/flutter_app/lib/widgets/gateway_controls.dart @@ -1,8 +1,9 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../app.dart'; import '../constants.dart'; +import '../l10n/app_strings.dart'; import '../models/gateway_state.dart'; import '../providers/gateway_provider.dart'; import '../screens/logs_screen.dart'; @@ -29,7 +30,7 @@ class GatewayControls extends StatelessWidget { children: [ Expanded( child: Text( - 'Gateway', + AppStrings.gateway, style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w600, ), @@ -66,21 +67,22 @@ class GatewayControls extends StatelessWidget { ), IconButton( icon: const Icon(Icons.copy, size: 18), - tooltip: 'Copy URL', + tooltip: AppStrings.copyUrl, onPressed: () { - final url = state.dashboardUrl ?? AppConstants.gatewayUrl; + final url = + state.dashboardUrl ?? AppConstants.gatewayUrl; Clipboard.setData(ClipboardData(text: url)); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('URL copied to clipboard'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(AppStrings.urlCopied), + duration: const Duration(seconds: 2), ), ); }, ), IconButton( icon: const Icon(Icons.open_in_new, size: 18), - tooltip: 'Open dashboard', + tooltip: AppStrings.openDashboard, onPressed: () { Navigator.of(context).push( MaterialPageRoute( @@ -108,20 +110,21 @@ class GatewayControls extends StatelessWidget { FilledButton.icon( onPressed: () => provider.start(), icon: const Icon(Icons.play_arrow), - label: const Text('Start Gateway'), + label: Text(AppStrings.startGateway), ), - if (state.isRunning || state.status == GatewayStatus.starting) + if (state.isRunning || + state.status == GatewayStatus.starting) OutlinedButton.icon( onPressed: () => provider.stop(), icon: const Icon(Icons.stop), - label: const Text('Stop Gateway'), + label: Text(AppStrings.stopGateway), ), OutlinedButton.icon( onPressed: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const LogsScreen()), ), icon: const Icon(Icons.article_outlined), - label: const Text('View Logs'), + label: Text(AppStrings.viewLogs), ), ], ), @@ -141,19 +144,19 @@ class GatewayControls extends StatelessWidget { switch (status) { case GatewayStatus.running: color = AppColors.statusGreen; - label = 'Running'; + label = AppStrings.gatewayRunning; icon = Icons.check_circle_outline; case GatewayStatus.starting: color = AppColors.statusAmber; - label = 'Starting'; + label = AppStrings.gatewayStarting; icon = Icons.hourglass_top; case GatewayStatus.error: color = AppColors.statusRed; - label = 'Error'; + label = AppStrings.gatewayError; icon = Icons.error_outline; case GatewayStatus.stopped: color = AppColors.statusGrey; - label = 'Stopped'; + label = AppStrings.gatewayStopped; icon = Icons.circle_outlined; } diff --git a/flutter_app/lib/widgets/node_controls.dart b/flutter_app/lib/widgets/node_controls.dart index 4a2b719..ea6d6f2 100644 --- a/flutter_app/lib/widgets/node_controls.dart +++ b/flutter_app/lib/widgets/node_controls.dart @@ -1,6 +1,7 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../app.dart'; +import '../l10n/app_strings.dart'; import '../models/node_state.dart'; import '../providers/node_provider.dart'; import '../screens/node_screen.dart'; @@ -26,7 +27,7 @@ class NodeControls extends StatelessWidget { children: [ Expanded( child: Text( - 'Node', + AppStrings.node, style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w600, ), @@ -78,20 +79,20 @@ class NodeControls extends StatelessWidget { FilledButton.icon( onPressed: () => provider.enable(), icon: const Icon(Icons.power_settings_new), - label: const Text('Enable Node'), + label: Text(AppStrings.enableNode), ), if (!state.isDisabled) ...[ OutlinedButton.icon( onPressed: () => provider.disable(), icon: const Icon(Icons.stop), - label: const Text('Disable Node'), + label: Text(AppStrings.disableNode), ), if (state.status == NodeStatus.error || state.status == NodeStatus.disconnected) OutlinedButton.icon( onPressed: () => provider.reconnect(), icon: const Icon(Icons.refresh), - label: const Text('Reconnect'), + label: Text(AppStrings.reconnect), ), ], OutlinedButton.icon( @@ -99,7 +100,7 @@ class NodeControls extends StatelessWidget { MaterialPageRoute(builder: (_) => const NodeScreen()), ), icon: const Icon(Icons.settings), - label: const Text('Configure'), + label: Text(AppStrings.nodeConfigure), ), ], ), @@ -119,25 +120,25 @@ class NodeControls extends StatelessWidget { switch (status) { case NodeStatus.paired: color = AppColors.statusGreen; - label = 'Paired'; + label = AppStrings.nodePaired; icon = Icons.check_circle_outline; case NodeStatus.connecting: case NodeStatus.challenging: case NodeStatus.pairing: color = AppColors.statusAmber; - label = 'Connecting'; + label = AppStrings.nodeConnecting; icon = Icons.hourglass_top; case NodeStatus.error: color = AppColors.statusRed; - label = 'Error'; + label = AppStrings.gatewayError; icon = Icons.error_outline; case NodeStatus.disabled: color = AppColors.statusGrey; - label = 'Disabled'; + label = AppStrings.nodeDisabled; icon = Icons.circle_outlined; case NodeStatus.disconnected: color = AppColors.statusGrey; - label = 'Disconnected'; + label = AppStrings.nodeDisconnected; icon = Icons.link_off; } diff --git a/flutter_app/lib/widgets/progress_step.dart b/flutter_app/lib/widgets/progress_step.dart index adc6593..5962742 100644 --- a/flutter_app/lib/widgets/progress_step.dart +++ b/flutter_app/lib/widgets/progress_step.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import '../app.dart'; class ProgressStep extends StatelessWidget { @@ -9,7 +9,7 @@ class ProgressStep extends StatelessWidget { final bool hasError; final double? progress; - const ProgressStep({ + ProgressStep({ super.key, required this.stepNumber, required this.label, diff --git a/flutter_app/lib/widgets/terminal_toolbar.dart b/flutter_app/lib/widgets/terminal_toolbar.dart index 8675cef..e56714d 100644 --- a/flutter_app/lib/widgets/terminal_toolbar.dart +++ b/flutter_app/lib/widgets/terminal_toolbar.dart @@ -54,7 +54,7 @@ class _TerminalToolbarState extends State { if (_ctrlActive) { widget.ctrlNotifier.value = false; - // Ctrl+a-z → bytes 1-26 + // Ctrl+a-z ?bytes 1-26 if (data.length == 1) { final code = data.toLowerCase().codeUnitAt(0); if (code >= 97 && code <= 122) { diff --git a/flutter_app/pubspec.lock b/flutter_app/pubspec.lock new file mode 100644 index 0000000..e5561f9 --- /dev/null +++ b/flutter_app/pubspec.lock @@ -0,0 +1,954 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + bluez: + dependency: transitive + description: + name: bluez + sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545" + url: "https://pub.dev" + source: hosted + version: "0.8.3" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + camera: + dependency: "direct main" + description: + name: camera + sha256: "4142a19a38e388d3bab444227636610ba88982e36dff4552d5191a86f65dc437" + url: "https://pub.dev" + source: hosted + version: "0.11.4" + camera_android_camerax: + dependency: transitive + description: + name: camera_android_camerax + sha256: "8516fe308bc341a5067fb1a48edff0ddfa57c0d3cdcc9dbe7ceca3ba119e2577" + url: "https://pub.dev" + source: hosted + version: "0.6.30" + camera_avfoundation: + dependency: transitive + description: + name: camera_avfoundation + sha256: "11b4aee2f5e5e038982e152b4a342c749b414aa27857899d20f4323e94cb5f0b" + url: "https://pub.dev" + source: hosted + version: "0.9.23+2" + camera_platform_interface: + dependency: transitive + description: + name: camera_platform_interface + sha256: "98cfc9357e04bad617671b4c1f78a597f25f08003089dd94050709ae54effc63" + url: "https://pub.dev" + source: hosted + version: "2.12.0" + camera_web: + dependency: transitive + description: + name: camera_web + sha256: "57f49a635c8bf249d07fb95eb693d7e4dda6796dedb3777f9127fb54847beba7" + url: "https://pub.dev" + source: hosted + version: "0.3.5+3" + characters: + dependency: transitive + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" + url: "https://pub.dev" + source: hosted + version: "0.3.5+2" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + cryptography: + dependency: "direct main" + description: + name: cryptography + sha256: "3eda3029d34ec9095a27a198ac9785630fe525c0eb6a49f3d575272f8e792ef0" + url: "https://pub.dev" + source: hosted + version: "2.9.0" + dbus: + dependency: transitive + description: + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" + source: hosted + version: "0.7.12" + dio: + dependency: "direct main" + description: + name: dio + sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c + url: "https://pub.dev" + source: hosted + version: "5.9.2" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + equatable: + dependency: transitive + description: + name: equatable + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" + url: "https://pub.dev" + source: hosted + version: "2.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blue_plus: + dependency: "direct main" + description: + name: flutter_blue_plus + sha256: "69a8c87c11fc792e8cf0f997d275484fbdb5143ac9f0ac4d424429700cb4e0ed" + url: "https://pub.dev" + source: hosted + version: "1.36.8" + flutter_blue_plus_android: + dependency: transitive + description: + name: flutter_blue_plus_android + sha256: "6f7fe7e69659c30af164a53730707edc16aa4d959e4c208f547b893d940f853d" + url: "https://pub.dev" + source: hosted + version: "7.0.4" + flutter_blue_plus_darwin: + dependency: transitive + description: + name: flutter_blue_plus_darwin + sha256: "682982862c1d964f4d54a3fb5fccc9e59a066422b93b7e22079aeecd9c0d38f8" + url: "https://pub.dev" + source: hosted + version: "7.0.3" + flutter_blue_plus_linux: + dependency: transitive + description: + name: flutter_blue_plus_linux + sha256: "56b0c45edd0a2eec8f85bd97a26ac3cd09447e10d0094fed55587bf0592e3347" + url: "https://pub.dev" + source: hosted + version: "7.0.3" + flutter_blue_plus_platform_interface: + dependency: transitive + description: + name: flutter_blue_plus_platform_interface + sha256: "84fbd180c50a40c92482f273a92069960805ce324e3673ad29c41d2faaa7c5c2" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + flutter_blue_plus_web: + dependency: transitive + description: + name: flutter_blue_plus_web + sha256: a1aceee753d171d24c0e0cdadb37895b5e9124862721f25f60bb758e20b72c99 + url: "https://pub.dev" + source: hosted + version: "7.0.2" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0" + url: "https://pub.dev" + source: hosted + version: "2.0.34" + flutter_pty: + dependency: "direct main" + description: + name: flutter_pty + sha256: c2f3b3160b519ac820fa3f6ef175361f2dfc52c557465643589542e9f229ad66 + url: "https://pub.dev" + source: hosted + version: "0.4.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "149876cc5207a0f5daf4fdd3bfcf0a0f27258b3fe95108fa084f527ad0568f1b" + url: "https://pub.dev" + source: hosted + version: "12.0.0" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d + url: "https://pub.dev" + source: hosted + version: "4.6.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 + url: "https://pub.dev" + source: hosted + version: "2.3.13" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" + url: "https://pub.dev" + source: hosted + version: "4.2.6" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 + url: "https://pub.dev" + source: hosted + version: "4.1.3" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" + url: "https://pub.dev" + source: hosted + version: "0.2.5" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055 + url: "https://pub.dev" + source: hosted + version: "6.3.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + http: + dependency: "direct main" + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: transitive + description: + name: lints + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" + source: hosted + version: "5.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + url: "https://pub.dev" + source: hosted + version: "0.12.19" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" + url: "https://pub.dev" + source: hosted + version: "0.17.6" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + url: "https://pub.dev" + source: hosted + version: "9.3.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "149441ca6e4f38193b2e004c0ca6376a3d11f51fa5a77552d8bd4d2b0c0912ba" + url: "https://pub.dev" + source: hosted + version: "2.2.23" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" + url: "https://pub.dev" + source: hosted + version: "11.4.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc + url: "https://pub.dev" + source: hosted + version: "12.1.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + url: "https://pub.dev" + source: hosted + version: "7.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf + url: "https://pub.dev" + source: hosted + version: "2.5.5" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 + url: "https://pub.dev" + source: hosted + version: "2.4.23" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + url: "https://pub.dev" + source: hosted + version: "0.7.10" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "3bb000251e55d4a209aa0e2e563309dc9bb2befea2295fd0cec1f51760aac572" + url: "https://pub.dev" + source: hosted + version: "6.3.29" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + url: "https://pub.dev" + source: hosted + version: "3.2.5" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f + url: "https://pub.dev" + source: hosted + version: "2.4.2" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + usb_serial: + dependency: "direct main" + description: + name: usb_serial + sha256: a605a600e34e7f28d4e80851ca3999ef747e42e406138887b8a88b8c382a8b07 + url: "https://pub.dev" + source: hosted + version: "0.5.2" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: "direct main" + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: a3da219916aba44947d3a5478b1927876a09781174b5a2b67fa5be0555154bf9 + url: "https://pub.dev" + source: hosted + version: "4.13.1" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: "0f7fcd2c86bf36bdcf94881f7941ce0cbc4f8d104b9fdcd5fcbef90e2199db76" + url: "https://pub.dev" + source: hosted + version: "4.10.15" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: "1221c1b12f5278791042f2ec2841743784cf25c5a644e23d6680e5d718824f04" + url: "https://pub.dev" + source: hosted + version: "2.15.1" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: d7219cfabc6f5fc2032e0fa980ec36d71f308a35a823395af1abc34d9a2ede83 + url: "https://pub.dev" + source: hosted + version: "3.24.2" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" + xterm: + dependency: "direct main" + description: + name: xterm + sha256: "168dfedca77cba33fdb6f52e2cd001e9fde216e398e89335c19b524bb22da3a2" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" + zmodem: + dependency: transitive + description: + name: zmodem + sha256: "3b7e5b29f3a7d8aee472029b05165a68438eff2f3f7766edf13daba1e297adbf" + url: "https://pub.dev" + source: hosted + version: "0.0.6" +sdks: + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" diff --git a/scripts/fetch-proot-windows.ps1 b/scripts/fetch-proot-windows.ps1 new file mode 100644 index 0000000..dcb28d9 --- /dev/null +++ b/scripts/fetch-proot-windows.ps1 @@ -0,0 +1,98 @@ +# 从 Termux 仓库下载 proot 和 libtalloc,解压放到 jniLibs +# 在 Windows PowerShell 中运行 + +$TERMUX_REPO = "https://packages.termux.dev/apt/termux-main" +$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path +$JNILIBS_DIR = "$SCRIPT_DIR\..\flutter_app\android\app\jniLibs" +$TMP_DIR = "$env:TEMP\proot-fetch-$(Get-Random)" +New-Item -ItemType Directory -Force -Path $TMP_DIR | Out-Null + +$env:HTTPS_PROXY = "http://127.0.0.1:7897" +$env:HTTP_PROXY = "http://127.0.0.1:7897" + +function Get-TermuxPkgUrl($arch, $pkgName) { + $indexUrl = "$TERMUX_REPO/dists/stable/main/binary-$arch/Packages" + $index = (Invoke-WebRequest -Uri $indexUrl -UseBasicParsing -Proxy "http://127.0.0.1:7897").Content + $lines = $index -split "`n" + $inPkg = $false + foreach ($line in $lines) { + if ($line -match "^Package: $pkgName$") { $inPkg = $true } + if ($inPkg -and $line -match "^Filename: (.+)") { + return "$TERMUX_REPO/$($Matches[1].Trim())" + } + if ($inPkg -and $line -eq "") { $inPkg = $false } + } + return $null +} + +function Extract-Deb($debPath, $outDir) { + New-Item -ItemType Directory -Force -Path $outDir | Out-Null + # .deb 是 ar 格式,用 7-Zip 或手动解析 + # 尝试用 7-Zip + $7z = "C:\Program Files\7-Zip\7z.exe" + if (Test-Path $7z) { + & $7z e $debPath -o"$outDir" "data.tar*" -y | Out-Null + $dataTar = Get-ChildItem $outDir -Filter "data.tar*" | Select-Object -First 1 + if ($dataTar) { + & $7z x $dataTar.FullName -o"$outDir\data" -y | Out-Null + } + } else { + Write-Host " Please install 7-Zip: https://www.7-zip.org/" -ForegroundColor Red + exit 1 + } +} + +$abis = @( + @{ jni = "arm64-v8a"; deb = "aarch64"; find = "aarch64" }, + @{ jni = "armeabi-v7a"; deb = "arm"; find = "arm" }, + @{ jni = "x86_64"; deb = "x86_64"; find = "x86_64" } +) + +foreach ($abi in $abis) { + $jniAbi = $abi.jni + $debArch = $abi.deb + $outDir = "$JNILIBS_DIR\$jniAbi" + New-Item -ItemType Directory -Force -Path $outDir | Out-Null + + Write-Host "[$jniAbi] Fetching proot..." -ForegroundColor Cyan + $prootUrl = Get-TermuxPkgUrl $debArch "proot" + if (-not $prootUrl) { Write-Host " proot package not found" -ForegroundColor Red; continue } + + $prootDeb = "$TMP_DIR\proot-$debArch.deb" + Invoke-WebRequest -Uri $prootUrl -OutFile $prootDeb -UseBasicParsing -Proxy "http://127.0.0.1:7897" + Extract-Deb $prootDeb "$TMP_DIR\proot-$debArch" + + Write-Host "[$jniAbi] Fetching libtalloc..." -ForegroundColor Cyan + $tallocUrl = Get-TermuxPkgUrl $debArch "libtalloc" + if (-not $tallocUrl) { Write-Host " libtalloc package not found" -ForegroundColor Red; continue } + + $tallocDeb = "$TMP_DIR\talloc-$debArch.deb" + Invoke-WebRequest -Uri $tallocUrl -OutFile $tallocDeb -UseBasicParsing -Proxy "http://127.0.0.1:7897" + Extract-Deb $tallocDeb "$TMP_DIR\talloc-$debArch" + + # 复制 proot 二进制 + $prootBin = Get-ChildItem "$TMP_DIR\proot-$debArch\data" -Recurse -Filter "proot" | Where-Object { -not $_.PSIsContainer } | Select-Object -First 1 + if ($prootBin) { + Copy-Item $prootBin.FullName "$outDir\libproot.so" -Force + Write-Host " libproot.so OK ($([math]::Round($prootBin.Length/1KB))KB)" + } + + # 复制 loader + $loader = Get-ChildItem "$TMP_DIR\proot-$debArch\data" -Recurse -Filter "loader" | Where-Object { -not $_.PSIsContainer } | Select-Object -First 1 + if ($loader) { + Copy-Item $loader.FullName "$outDir\libprootloader.so" -Force + Write-Host " libprootloader.so OK" + } + + # 复制 libtalloc + $talloc = Get-ChildItem "$TMP_DIR\talloc-$debArch\data" -Recurse | Where-Object { $_.Name -like "libtalloc.so*" -and -not $_.PSIsContainer } | Select-Object -First 1 + if ($talloc) { + Copy-Item $talloc.FullName "$outDir\libtalloc.so" -Force + Write-Host " libtalloc.so OK" + } + + Write-Host "[$jniAbi] Done" -ForegroundColor Green +} + +Remove-Item -Recurse -Force $TMP_DIR -ErrorAction SilentlyContinue +Write-Host "`nAll done! Now rebuild the APK." -ForegroundColor Green diff --git "a/\346\225\264\345\220\210\346\226\271\346\241\210.md" "b/\346\225\264\345\220\210\346\226\271\346\241\210.md" new file mode 100644 index 0000000..9db0482 --- /dev/null +++ "b/\346\225\264\345\220\210\346\226\271\346\241\210.md" @@ -0,0 +1,32 @@ +现在全局都清楚了,整合方案非常明确。 + +这个 UI 是 React + TypeScript 的 Web 应用,构建后是一个单文件 HTML。 + +关键信息: + +CLIProxyAPI 从 v6.0.19 起已经内置这个 UI,访问 http://localhost:端口/management.html 就能用 +UI 已经支持中文、响应式移动端布局 +支持 OAuth 登录、多账号管理、配额监控、日志查看等所有功能 +所以整合到 openclaw-termux 的方案非常简单,不需要重写任何东西: + + +proot Ubuntu 里同时运行: + ├── CLIProxyAPI(Go 二进制,监听 18790) + │ └── 内置 /management.html(Web UI) + └── OpenClaw(Node.js,监听 18789) + └── 配置 API base URL → 127.0.0.1:18790 + +Flutter App 加两个入口: + ├── 现有的 Web Dashboard(OpenClaw,18789) + └── 新增 CLIProxy 管理(WebView → 18790/management.html) + + + +分步骤完成: + +添加 flutter_localizations + intl 依赖 +创建中文翻译文件 +配置 app.dart 支持中文【方案改成了用 PlatformDispatcher.instance.locale.languageCode 在运行时读取系统语言,AppStrings 里每个字符串都是 getter,手机系统设置中文就返回中文,设置英文(或其他语言)就返回英文。不需要 ARB 代码生成,也不需要 flutter gen-l10n 命令,flutter build apk 直接就能跑。】 +平板响应式布局(dashboard_screen.dart + 全局 ConstrainedBox) +新增 CLIProxyAPI 管理页面(WebView) +Dashboard 加入口 \ No newline at end of file diff --git "a/\347\273\210\347\253\257\346\227\245\345\277\227.md" "b/\347\273\210\347\253\257\346\227\245\345\277\227.md" new file mode 100644 index 0000000..e69de29