From 479250c2076a520b471c3477cdd94fb91b512ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lollipopkit=F0=9F=8F=B3=EF=B8=8F=E2=80=8D=E2=9A=A7?= =?UTF-8?q?=EF=B8=8F?= <10864310+lollipopkit@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:44:54 +0800 Subject: [PATCH] init --- android/app/src/main/AndroidManifest.xml | 24 ++- .../tech/lolli/toolbox/ForegroundService.kt | 59 ++++++ .../tech/lolli/toolbox/KeepAliveService.kt | 18 -- .../kotlin/tech/lolli/toolbox/MainActivity.kt | 8 +- lib/view/page/ssh/page.dart | 93 ++++------ lib/view/page/ssh/tab.dart | 8 +- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 172 +++++++++++++----- pubspec.yaml | 3 +- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 13 files changed, 259 insertions(+), 137 deletions(-) create mode 100644 android/app/src/main/kotlin/tech/lolli/toolbox/ForegroundService.kt delete mode 100644 android/app/src/main/kotlin/tech/lolli/toolbox/KeepAliveService.kt diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index feea319e..509e98e1 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -29,12 +29,12 @@ while the Flutter UI initializes. After that, this theme continues to determine the Window background behind the Flutter UI. --> + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" + /> - - + + - - + + - + \ No newline at end of file diff --git a/android/app/src/main/kotlin/tech/lolli/toolbox/ForegroundService.kt b/android/app/src/main/kotlin/tech/lolli/toolbox/ForegroundService.kt new file mode 100644 index 00000000..74a50257 --- /dev/null +++ b/android/app/src/main/kotlin/tech/lolli/toolbox/ForegroundService.kt @@ -0,0 +1,59 @@ +package tech.lolli.toolbox + +import android.app.* +import android.content.Intent +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat + +class MyForegroundService : Service() { + + private val CHANNEL_ID = "ForegroundServiceChannel" + + override fun onCreate() { + super.onCreate() + createNotificationChannel() + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + val notification = createNotification() + startForeground(1, notification) + + // Exec your code here + + return START_STICKY + } + + override fun onBind(intent: Intent): IBinder? { + return null + } + + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val serviceChannel = NotificationChannel( + CHANNEL_ID, + CHANNEL_ID, + NotificationManager.IMPORTANCE_DEFAULT + ) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(serviceChannel) + } + } + + private fun createNotification(): Notification { + val notificationIntent = Intent(this, MainActivity::class.java) + val pendingIntent = PendingIntent.getActivity( + this, + 0, + notificationIntent, + PendingIntent.FLAG_IMMUTABLE + ) + + return NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("App is running") + .setContentText("Click to open the app") + .setSmallIcon(R.drawable.ic_notification) + .setContentIntent(pendingIntent) + .build() + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/tech/lolli/toolbox/KeepAliveService.kt b/android/app/src/main/kotlin/tech/lolli/toolbox/KeepAliveService.kt deleted file mode 100644 index 75c1518d..00000000 --- a/android/app/src/main/kotlin/tech/lolli/toolbox/KeepAliveService.kt +++ /dev/null @@ -1,18 +0,0 @@ -package tech.lolli.toolbox - -import android.app.Service -import android.content.Intent - -import android.os.IBinder -import org.jetbrains.annotations.Nullable - -class KeepAliveService : Service() { - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - return START_STICKY - } - - @Nullable - override fun onBind(intent: Intent?): IBinder? { - return null - } -} \ No newline at end of file diff --git a/android/app/src/main/kotlin/tech/lolli/toolbox/MainActivity.kt b/android/app/src/main/kotlin/tech/lolli/toolbox/MainActivity.kt index 4cac19c2..e3d2d13f 100644 --- a/android/app/src/main/kotlin/tech/lolli/toolbox/MainActivity.kt +++ b/android/app/src/main/kotlin/tech/lolli/toolbox/MainActivity.kt @@ -18,8 +18,12 @@ class MainActivity: FlutterFragmentActivity() { result.success(null) } "startService" -> { - val intent = Intent(this@MainActivity, KeepAliveService::class.java) - startService(intent) + val serviceIntent = Intent(this, ForegroundService::class.java) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(serviceIntent) + } else { + startService(serviceIntent) + } } else -> { result.notImplemented() diff --git a/lib/view/page/ssh/page.dart b/lib/view/page/ssh/page.dart index 9cf25aab..88b18e25 100644 --- a/lib/view/page/ssh/page.dart +++ b/lib/view/page/ssh/page.dart @@ -5,7 +5,6 @@ import 'package:dartssh2/dartssh2.dart'; import 'package:fl_lib/fl_lib.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:provider/provider.dart'; import 'package:server_box/core/extension/context/locale.dart'; import 'package:server_box/core/utils/ssh_auth.dart'; @@ -85,6 +84,7 @@ class SSHPageState extends State _terminalController.dispose(); _discontinuityTimer?.cancel(); if (!Stores.setting.generalWakeLock.fetch()) WakelockPlus.disable(); + _setupDiscontinuityTimer(); } @override @@ -95,7 +95,7 @@ class SSHPageState extends State 2 => true, _ => context.isDark, }; - _media = MediaQuery.of(context); + _media = context.media; _terminalTheme = _isDark ? TerminalThemes.dark : TerminalThemes.light; _terminalTheme = _terminalTheme.copyWith(selectionCursor: UIs.primaryColor); @@ -415,8 +415,6 @@ class SSHPageState extends State _listen(session.stdout); _listen(session.stderr); - _initService(); - for (final snippet in SnippetProvider.snippets.value) { if (snippet.autoRunOn?.contains(widget.spi.id) == true) { snippet.runInTerm(_terminal, widget.spi); @@ -451,64 +449,43 @@ class SSHPageState extends State .listen(_terminal.write); } - // void _setupDiscontinuityTimer() { - // _discontinuityTimer = Timer.periodic( - // const Duration(seconds: 5), - // (_) async { - // var throwTimeout = true; - // Future.delayed(const Duration(seconds: 3), () { - // if (throwTimeout) { - // _catchTimeout(); - // } - // }); - // await _client?.ping(); - // throwTimeout = false; - // }, - // ); - // } + void _setupDiscontinuityTimer() { + _discontinuityTimer = Timer.periodic( + const Duration(seconds: 5), + (_) async { + var throwTimeout = true; + Future.delayed(const Duration(seconds: 3), () { + if (throwTimeout) { + _catchTimeout(); + } + }); + await _client?.ping(); + throwTimeout = false; + }, + ); + } - // void _catchTimeout() { - // _discontinuityTimer?.cancel(); - // if (!mounted) return; - // _writeLn('\n\nConnection lost\r\n'); - // context.showRoundDialog( - // title: Text(l10n.attention), - // child: Text('${l10n.disconnected}\n${l10n.goBackQ}'), - // barrierDismiss: false, - // actions: [ - // TextButton( - // onPressed: () { - // if (mounted) { - // context.pop(); - // if (widget.pop) { - // context.pop(); - // } - // } - // }, - // child: Text(l10n.ok), - // ), - // ], - // ); - // } + void _catchTimeout() { + _discontinuityTimer?.cancel(); + if (!mounted) return; + _writeLn('\n\nConnection lost\r\n'); + context.showRoundDialog( + title: libL10n.attention, + child: Text('${l10n.disconnected}\n${l10n.goBackQ}'), + barrierDismiss: false, + actions: Btn.ok( + onTap: () { + if (mounted) { + context.pop(); + } + }, + ).toList, + ); + } @override bool get wantKeepAlive => true; - Future _initService() async { - if (!isAndroid) return; - - await FlutterBackgroundService().configure( - androidConfiguration: AndroidConfiguration( - onStart: _onStart, - autoStart: true, - isForegroundMode: true, - initialNotificationTitle: 'SSH', - initialNotificationContent: l10n.bgRun, - ), - iosConfiguration: IosConfiguration(), - ); - } - void _initStoredCfg() { final fontFamilly = Stores.setting.fontPath.fetch().getFileName(); final textSize = Stores.setting.termFontSize.fetch(); @@ -546,5 +523,3 @@ class SSHPageState extends State if (Stores.setting.sshWakeLock.fetch()) WakelockPlus.enable(); } } - -Future _onStart(ServiceInstance service) async {} diff --git a/lib/view/page/ssh/tab.dart b/lib/view/page/ssh/tab.dart index 928b5c3b..be1f3fd6 100644 --- a/lib/view/page/ssh/tab.dart +++ b/lib/view/page/ssh/tab.dart @@ -107,18 +107,18 @@ class _SSHTabPageState extends State final idxs = _tabMap.keys .map((e) => reg.firstMatch(e)) .map((e) => e?.group(1)) - .where((e) => e != null); + .whereType(); if (idxs.isEmpty) { return _tabMap.keys.contains(spi.name) ? '${spi.name}(1)' : spi.name; } - final biggest = idxs.reduce((a, b) => a!.length > b!.length ? a : b); - final biggestInt = int.tryParse(biggest ?? '0'); + final biggest = idxs.reduce((a, b) => a.length > b.length ? a : b); + final biggestInt = int.tryParse(biggest); if (biggestInt != null && biggestInt > 0) { return '${spi.name}(${biggestInt + 1})'; } return spi.name; }(); - final key = GlobalKey(); + final key = Key(name); _tabMap[name] = ( page: SSHPage( // Keep it, or the Flutter will works unexpectedly diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 965f5cf6..412a5437 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -15,6 +16,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) dynamic_color_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); + g_autoptr(FlPluginRegistrar) gtk_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); + gtk_plugin_register_with_registrar(gtk_registrar); g_autoptr(FlPluginRegistrar) screen_retriever_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index dacf00d7..eb9e8cbb 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST dynamic_color + gtk screen_retriever url_launcher_linux window_manager diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 7a6a1957..24b84125 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import app_links import dynamic_color import icloud_storage import local_auth_darwin @@ -18,6 +19,7 @@ import wakelock_plus import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) IcloudStoragePlugin.register(with: registry.registrar(forPlugin: "IcloudStoragePlugin")) FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 05927ae5..3fdacd29 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -30,6 +30,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + app_links: + dependency: transitive + description: + name: app_links + sha256: "50437e5916e6f56c1ca53e967cbfd6d53b3451465b41eef05ba1533bf1e1c5ea" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" archive: dependency: transitive description: @@ -438,8 +470,8 @@ packages: dependency: "direct main" description: path: "." - ref: "v1.0.145" - resolved-ref: "9f37be2b15c9d87887d704599f8fcc17263b8335" + ref: "v1.0.147" + resolved-ref: "3c65bab2820ce96922612fbe1d81473e6acb0bd7" url: "https://github.com/lppcg/fl_lib" source: git version: "0.0.1" @@ -448,38 +480,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_background_service: - dependency: "direct main" - description: - name: flutter_background_service - sha256: "8807ed792227be05329478870b92f2df62c7af96f49763f6d62ad39d2eac6ee6" - url: "https://pub.dev" - source: hosted - version: "5.0.7" - flutter_background_service_android: - dependency: transitive - description: - name: flutter_background_service_android - sha256: fe06c4bd719b8ce8512d5724a229526155c1f54f734524b8e43f8212e98384a8 - url: "https://pub.dev" - source: hosted - version: "6.2.4" - flutter_background_service_ios: - dependency: transitive - description: - name: flutter_background_service_ios - sha256: "45c8aca1e8850e5c45822152b06d5806aba9470517dcd2c291fce8ef99a44d60" - url: "https://pub.dev" - source: hosted - version: "5.0.2" - flutter_background_service_platform_interface: - dependency: transitive - description: - name: flutter_background_service_platform_interface - sha256: "91dd3391c213e37094fbc3fb7f34319b99ea9df76036a5c054d6371be843b0ae" - url: "https://pub.dev" - source: hosted - version: "5.1.1" flutter_displaymode: dependency: "direct main" description: @@ -575,6 +575,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + functions_client: + dependency: transitive + description: + name: functions_client + sha256: e63f49cd3b41727f47b3bde284a11a4ac62839e0604f64077d4257487510e484 + url: "https://pub.dev" + source: hosted + version: "2.3.2" glob: dependency: transitive description: @@ -583,6 +591,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + gotrue: + dependency: transitive + description: + name: gotrue + sha256: "8703db795511f69194fe77125a0c838bbb6befc2f95717b6e40331784a8bdecb" + url: "https://pub.dev" + source: hosted + version: "2.8.4" graphs: dependency: transitive description: @@ -591,6 +607,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" highlight: dependency: "direct main" description: @@ -727,6 +751,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.8.0" + jwt_decode: + dependency: transitive + description: + name: jwt_decode + sha256: d2e9f68c052b2225130977429d30f187aa1981d789c76ad104a32243cfdebfbb + url: "https://pub.dev" + source: hosted + version: "0.3.1" leak_tracker: dependency: transitive description: @@ -1008,14 +1040,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - pocketbase: - dependency: transitive - description: - name: pocketbase - sha256: "1d2958a3a7cb1e0050f425f179bd6557441fafcf740a79d5b8b80d6954149790" - url: "https://pub.dev" - source: hosted - version: "0.18.1" pointycastle: dependency: transitive description: @@ -1032,6 +1056,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + postgrest: + dependency: transitive + description: + name: postgrest + sha256: c4197238601c7c3103b03a4bb77f2050b17d0064bf8b968309421abdebbb7f0e + url: "https://pub.dev" + source: hosted + version: "2.1.4" pretty_qr_code: dependency: transitive description: @@ -1088,6 +1120,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + realtime_client: + dependency: transitive + description: + name: realtime_client + sha256: d897a65ee3b1b5ddc1cf606f0b83792262d38fd5679c2df7e38da29c977513da + url: "https://pub.dev" + source: hosted + version: "2.2.1" + retry: + dependency: transitive + description: + name: retry + sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" screen_retriever: dependency: transitive description: @@ -1237,6 +1293,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.1" + storage_client: + dependency: transitive + description: + name: storage_client + sha256: "28c147c805304dbc2b762becd1fc26ee0cb621ace3732b9ae61ef979aab8b367" + url: "https://pub.dev" + source: hosted + version: "2.0.3" stream_channel: dependency: transitive description: @@ -1261,6 +1325,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + supabase: + dependency: transitive + description: + name: supabase + sha256: "4ed1cf3298f39865c05b2d8557f92eb131a9b9af70e32e218672a0afce01a6bc" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + supabase_flutter: + dependency: transitive + description: + name: supabase_flutter + sha256: ff6ba3048fd47d831fdc0027d3efb99346d99b95becfcb406562454bd9b229c5 + url: "https://pub.dev" + source: hosted + version: "2.6.0" term_glyph: dependency: transitive description: @@ -1584,6 +1664,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + yet_another_json_isolate: + dependency: transitive + description: + name: yet_another_json_isolate + sha256: "47ed3900e6b0e4dfe378811a4402e85b7fc126a7daa94f840fef65ea9c8e46f4" + url: "https://pub.dev" + source: hosted + version: "2.0.2" zmodem: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b2b86944..238c9867 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,7 +22,6 @@ dependencies: dynamic_color: ^1.6.6 xml: ^6.4.2 # for parsing nvidia-smi flutter_displaymode: ^0.6.0 - flutter_background_service: ^5.0.5 fl_chart: ^0.67.0 wakelock_plus: ^1.2.4 wake_on_lan: ^4.1.1+3 @@ -60,7 +59,7 @@ dependencies: fl_lib: git: url: https://github.com/lppcg/fl_lib - ref: v1.0.145 + ref: v1.0.147 dependency_overrides: # dartssh2: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index b29d6496..1adfc297 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -14,6 +15,8 @@ #include void RegisterPlugins(flutter::PluginRegistry* registry) { + AppLinksPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AppLinksPluginCApi")); DynamicColorPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); LocalAuthPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 16e54273..89509209 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + app_links dynamic_color local_auth_windows screen_retriever