mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
fix: catch crash of fg service (#669)
This commit is contained in:
@@ -5,10 +5,24 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class ForegroundService : Service() {
|
||||
private val chanId = "ForegroundServiceChannel"
|
||||
|
||||
private fun logError(message: String, error: Throwable? = null) {
|
||||
Log.e("ForegroundService", message, error)
|
||||
try {
|
||||
val logFile = File(getExternalFilesDir(null), "server_box.log")
|
||||
val timestamp = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(Date())
|
||||
val logMessage = "$timestamp [ForegroundService] ERROR: $message\n${error?.stackTraceToString() ?: ""}\n"
|
||||
logFile.appendText(logMessage)
|
||||
} catch (e: Exception) {
|
||||
Log.e("ForegroundService", "Failed to write log", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Log.d("ForegroundService", "Service onCreate")
|
||||
@@ -16,6 +30,17 @@ class ForegroundService : Service() {
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
||||
androidx.core.content.ContextCompat.checkSelfPermission(
|
||||
this, android.Manifest.permission.POST_NOTIFICATIONS
|
||||
) != android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
Log.w("ForegroundService", "Notification permission denied. Stopping service.")
|
||||
stopForegroundService()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
if (intent == null) {
|
||||
Log.w("ForegroundService", "onStartCommand called with null intent")
|
||||
stopForegroundService()
|
||||
@@ -25,17 +50,33 @@ class ForegroundService : Service() {
|
||||
val action = intent.action
|
||||
Log.d("ForegroundService", "onStartCommand action=$action")
|
||||
|
||||
// Create notification before starting foreground
|
||||
val notification = createNotification()
|
||||
|
||||
// Use try-catch for startForeground
|
||||
try {
|
||||
startForeground(1, notification)
|
||||
} catch (e: Exception) {
|
||||
logError("Failed to start foreground", e)
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
return when (action) {
|
||||
"ACTION_STOP_FOREGROUND" -> {
|
||||
stopForegroundService()
|
||||
START_NOT_STICKY
|
||||
}
|
||||
else -> {
|
||||
val notification = createNotification()
|
||||
startForeground(1, notification)
|
||||
START_STICKY
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
logError("Error in onStartCommand", e)
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
@@ -61,6 +102,7 @@ class ForegroundService : Service() {
|
||||
}
|
||||
|
||||
private fun createNotification(): Notification {
|
||||
try {
|
||||
val notificationIntent = Intent(this, MainActivity::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
@@ -92,13 +134,21 @@ class ForegroundService : Service() {
|
||||
.setContentIntent(pendingIntent)
|
||||
.addAction(android.R.drawable.ic_delete, "Stop", deletePendingIntent)
|
||||
.build()
|
||||
} catch (e: Exception) {
|
||||
logError("Error creating notification", e)
|
||||
// Return a basic notification as fallback
|
||||
return Notification.Builder(this)
|
||||
.setContentTitle("Server Box")
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopForegroundService() {
|
||||
try {
|
||||
stopForeground(true)
|
||||
} catch (e: Exception) {
|
||||
Log.e("ForegroundService", "Error stopping foreground: ${e.message}")
|
||||
logError("Error stopping foreground", e)
|
||||
}
|
||||
stopSelf()
|
||||
Log.d("ForegroundService", "ForegroundService stopped")
|
||||
|
||||
@@ -25,6 +25,7 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
result.success(null)
|
||||
}
|
||||
"startService" -> {
|
||||
try {
|
||||
reqPerm()
|
||||
val serviceIntent = Intent(this@MainActivity, ForegroundService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
@@ -32,6 +33,12 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
} else {
|
||||
startService(serviceIntent)
|
||||
}
|
||||
result.success(null)
|
||||
} catch (e: Exception) {
|
||||
// Log error but don't crash
|
||||
android.util.Log.e("MainActivity", "Failed to start service: ${e.message}")
|
||||
result.error("SERVICE_ERROR", e.message, null)
|
||||
}
|
||||
}
|
||||
"stopService" -> {
|
||||
val serviceIntent = Intent(this@MainActivity, ForegroundService::class.java)
|
||||
@@ -54,13 +61,20 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
|
||||
private fun reqPerm() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
|
||||
|
||||
// Check if we already have the permission to avoid unnecessary prompts
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
try {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
||||
123,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
// Log error but don't crash
|
||||
android.util.Log.e("MainActivity", "Failed to request permissions: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ class HomeWidget : AppWidgetProvider() {
|
||||
views.setViewVisibility(R.id.error_message, View.VISIBLE)
|
||||
views.setTextViewText(R.id.error_message, "Please configure the widget URL.")
|
||||
views.setViewVisibility(R.id.widget_content, View.GONE)
|
||||
views.setFloat(R.id.widget_name, "setAlpha", 1f)
|
||||
views.setFloat(R.id.error_message, "setAlpha", 1f)
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
return
|
||||
} else {
|
||||
@@ -100,6 +102,12 @@ class HomeWidget : AppWidgetProvider() {
|
||||
views.setTextViewText(R.id.widget_net, net)
|
||||
val timeStr = android.text.format.DateFormat.format("HH:mm", java.util.Date()).toString()
|
||||
views.setTextViewText(R.id.widget_time, timeStr)
|
||||
views.setFloat(R.id.widget_name, "setAlpha", 1f)
|
||||
views.setFloat(R.id.widget_cpu_label, "setAlpha", 1f)
|
||||
views.setFloat(R.id.widget_mem_label, "setAlpha", 1f)
|
||||
views.setFloat(R.id.widget_disk_label, "setAlpha", 1f)
|
||||
views.setFloat(R.id.widget_net_label, "setAlpha", 1f)
|
||||
views.setFloat(R.id.widget_time, "setAlpha", 1f)
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
}
|
||||
} else {
|
||||
@@ -113,6 +121,8 @@ class HomeWidget : AppWidgetProvider() {
|
||||
views.setViewVisibility(R.id.error_message, View.VISIBLE)
|
||||
views.setTextViewText(R.id.error_message, "Failed to retrieve data.")
|
||||
views.setViewVisibility(R.id.widget_content, View.GONE)
|
||||
views.setFloat(R.id.widget_name, "setAlpha", 1f)
|
||||
views.setFloat(R.id.error_message, "setAlpha", 1f)
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
android:textSize="23sp"
|
||||
android:textStyle="bold"
|
||||
android:maxLines="1"
|
||||
android:alpha="0"
|
||||
android:animateLayoutChanges="true"
|
||||
tools:text="Server Name" />
|
||||
|
||||
<!-- Wrap the content in a LinearLayout for easy visibility management -->
|
||||
@@ -32,7 +34,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="13dp">
|
||||
android:paddingTop="13dp"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_cpu_label"
|
||||
@@ -155,6 +158,8 @@
|
||||
android:textColor="@color/widgetSummaryText"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
android:alpha="0"
|
||||
android:animateLayoutChanges="true"
|
||||
tools:text="Error message" />
|
||||
|
||||
<TextView
|
||||
@@ -165,6 +170,8 @@
|
||||
android:maxLines="2"
|
||||
android:textColor="@color/widgetSummaryText"
|
||||
android:textSize="11sp"
|
||||
android:alpha="0"
|
||||
android:animateLayoutChanges="true"
|
||||
tools:text="UpdateTime" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -6,6 +6,13 @@ PODS:
|
||||
- file_picker (0.0.1):
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- flutter_inappwebview_ios (0.0.1):
|
||||
- Flutter
|
||||
- flutter_inappwebview_ios/Core (= 0.0.1)
|
||||
- OrderedSet (~> 6.0.3)
|
||||
- flutter_inappwebview_ios/Core (0.0.1):
|
||||
- Flutter
|
||||
- OrderedSet (~> 6.0.3)
|
||||
- flutter_native_splash (2.4.3):
|
||||
- Flutter
|
||||
- icloud_storage (0.0.1):
|
||||
@@ -13,6 +20,7 @@ PODS:
|
||||
- local_auth_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- OrderedSet (6.0.3)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
@@ -31,15 +39,13 @@ PODS:
|
||||
- Flutter
|
||||
- watch_connectivity (0.0.1):
|
||||
- Flutter
|
||||
- webview_flutter_wkwebview (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- icloud_storage (from `.symlinks/plugins/icloud_storage/ios`)
|
||||
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
|
||||
@@ -51,7 +57,10 @@ DEPENDENCIES:
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
- watch_connectivity (from `.symlinks/plugins/watch_connectivity/ios`)
|
||||
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- OrderedSet
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
app_links:
|
||||
@@ -62,6 +71,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_inappwebview_ios:
|
||||
:path: ".symlinks/plugins/flutter_inappwebview_ios/ios"
|
||||
flutter_native_splash:
|
||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||
icloud_storage:
|
||||
@@ -84,17 +95,17 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
watch_connectivity:
|
||||
:path: ".symlinks/plugins/watch_connectivity/ios"
|
||||
webview_flutter_wkwebview:
|
||||
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0
|
||||
camera_avfoundation: dd002b0330f4981e1bbcb46ae9b62829237459a4
|
||||
file_picker: c79185e70b9b45728cde2a8d8da454e0cb43f287
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
|
||||
flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a
|
||||
icloud_storage: d9ac7a33ced81df08ba7ea1bf3099cc0ee58f60a
|
||||
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
|
||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
plain_notification_token: b36467dc91939a7b6754267c701bbaca14996ee1
|
||||
@@ -103,7 +114,6 @@ SPEC CHECKSUMS:
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||
watch_connectivity: 715eb484685e05846eab74795348a44bb2809b82
|
||||
webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
|
||||
|
||||
PODFILE CHECKSUM: ec6ef69056f066e8b21a3391082f23b5ad2d37f8
|
||||
|
||||
|
||||
@@ -672,7 +672,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -682,7 +682,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -808,7 +808,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -818,7 +818,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -836,7 +836,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -846,7 +846,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -867,7 +867,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -880,7 +880,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||
@@ -906,7 +906,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -919,7 +919,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -942,7 +942,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -955,7 +955,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -978,7 +978,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -990,7 +990,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||
@@ -1019,7 +1019,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1031,7 +1031,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||
PRODUCT_NAME = ServerBox;
|
||||
@@ -1057,7 +1057,7 @@
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1069,7 +1069,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
|
||||
PRODUCT_NAME = ServerBox;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:server_box/data/res/misc.dart';
|
||||
import 'package:server_box/data/res/store.dart';
|
||||
|
||||
abstract final class MethodChans {
|
||||
static const _channel = MethodChannel('${Miscs.pkgName}/main_chan');
|
||||
@@ -8,14 +9,14 @@ abstract final class MethodChans {
|
||||
_channel.invokeMethod('sendToBackground');
|
||||
}
|
||||
|
||||
/// TODO: try fix the fn, then uncomment it and [stopService]
|
||||
/// Issues #639
|
||||
static void startService() {
|
||||
// _channel.invokeMethod('startService');
|
||||
if (Stores.setting.fgService.fetch() != true) return;
|
||||
_channel.invokeMethod('startService');
|
||||
}
|
||||
|
||||
static void stopService() {
|
||||
// _channel.invokeMethod('stopService');
|
||||
if (Stores.setting.fgService.fetch() != true) return;
|
||||
_channel.invokeMethod('stopService');
|
||||
}
|
||||
|
||||
static void updateHomeWidget() async {
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
abstract class BuildData {
|
||||
static const String name = "ServerBox";
|
||||
static const int build = 1117;
|
||||
static const int build = 1124;
|
||||
static const int script = 59;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,9 @@ class SettingStore extends HiveStore {
|
||||
/// Set it empty to use local editor GUI.
|
||||
late final sftpEditor = propertyDefault('sftpEditor', '');
|
||||
|
||||
/// Run foreground service on Android, if the SSH terminal is running
|
||||
late final fgService = propertyDefault('fgService', false);
|
||||
|
||||
// Never show these settings for users
|
||||
//
|
||||
// ------BEGIN------
|
||||
|
||||
@@ -434,6 +434,18 @@ abstract class AppLocalizations {
|
||||
/// **'If you downloaded this app from F-Droid, it is recommended to turn off this option.'**
|
||||
String get fdroidReleaseTip;
|
||||
|
||||
/// No description provided for @fgService.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Foreground Service'**
|
||||
String get fgService;
|
||||
|
||||
/// No description provided for @fgServiceTip.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'After enabling, some device models may crash. Disabling it may cause some models to be unable to maintain SSH connections in the background. Please allow ServerBox notification permissions, background running, and self-wake-up in system settings.'**
|
||||
String get fgServiceTip;
|
||||
|
||||
/// No description provided for @fileTooLarge.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Wenn Sie diese App von F-Droid heruntergeladen haben, wird empfohlen, diese Option zu deaktivieren.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Vordergrund-Dienst';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Nach dem Einschalten kann es bei einigen Gerätemodellen zu Abstürzen kommen. Das Ausschalten kann bei einigen Modellen dazu führen, dass SSH-Verbindungen im Hintergrund nicht aufrechterhalten werden können. Bitte erlauben Sie ServerBox in den Systemeinstellungen Benachrichtigungsrechte, Hintergrundausführung und Selbstaktivierung.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'Datei \'$file\' ist zu groß $size, max $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'If you downloaded this app from F-Droid, it is recommended to turn off this option.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Foreground Service';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'After enabling, some device models may crash. Disabling it may cause some models to be unable to maintain SSH connections in the background. Please allow ServerBox notification permissions, background running, and self-wake-up in system settings.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'File \'$file\' too large $size, max $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Si descargaste esta aplicación desde F-Droid, se recomienda desactivar esta opción.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Servicio en primer plano';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Después de activarlo, algunos modelos de dispositivos pueden bloquearse. Desactivarlo puede hacer que algunos modelos no puedan mantener las conexiones SSH en segundo plano. Por favor, permita los permisos de notificación de ServerBox, la ejecución en segundo plano y el auto-despertar en la configuración del sistema.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'El archivo \'$file\' es demasiado grande \'$size\', supera el $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Si vous avez téléchargé cette application depuis F-Droid, il est recommandé de désactiver cette option.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Service de premier plan';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Après l\'activation, certains modèles d\'appareils peuvent planter. La désactivation peut empêcher certains modèles de maintenir les connexions SSH en arrière-plan. Veuillez autoriser les permissions de notification ServerBox, l\'exécution en arrière-plan et l\'auto-réveil dans les paramètres système.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'Fichier \'$file\' trop volumineux $size, max $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Jika Anda mengunduh aplikasi ini dari F-Droid, disarankan untuk mematikan opsi ini.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Layanan Latar Depan';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Setelah diaktifkan, beberapa model perangkat mungkin crash. Menonaktifkannya dapat menyebabkan beberapa model tidak dapat mempertahankan koneksi SSH di latar belakang. Harap izinkan perizinan notifikasi ServerBox, menjalankan di latar belakang, dan bangun mandiri di pengaturan sistem.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'File \'$file\' terlalu besar $size, max $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'このアプリをF-Droidからダウンロードした場合、このオプションをオフにすることをお勧めします。';
|
||||
|
||||
@override
|
||||
String get fgService => 'フォアグラウンドサービス';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => '有効にすると、一部の機種でクラッシュする可能性があります。無効にすると、一部の機種でバックグラウンドでのSSH接続を維持できなくなる可能性があります。システム設定でServerBoxの通知権限、バックグラウンド実行、自己起動を許可してください。';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'ファイル \'$file\' は大きすぎます \'$size\'、$sizeMax を超えています';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Als u deze app van F-Droid heeft gedownload, wordt aanbevolen deze optie uit te schakelen.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Voorgrondservice';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Na het inschakelen kunnen sommige apparaatmodellen crashen. Uitschakelen kan ertoe leiden dat sommige modellen SSH-verbindingen niet op de achtergrond kunnen behouden. Sta ServerBox notificatierechten, achtergronduitvoering en zelf-ontwaken toe in systeeminstellingen.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'Bestand \'$file\' te groot $size, max $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Se você baixou este aplicativo do F-Droid, é recomendado desativar esta opção.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Serviço em primeiro plano';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Após ativar, alguns modelos de dispositivos podem travar. Desativar pode fazer com que alguns modelos não consigam manter conexões SSH em segundo plano. Por favor, permita as permissões de notificação do ServerBox, execução em segundo plano e auto-despertar nas configurações do sistema.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'Arquivo \'$file\' muito grande \'$size\', excedendo $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Если вы скачали это приложение с F-Droid, рекомендуется отключить эту опцию.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Сервис переднего плана';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'После включения некоторые модели устройств могут вылетать. Отключение может привести к тому, что некоторые модели не смогут поддерживать SSH-соединения в фоновом режиме. Пожалуйста, разрешите ServerBox права на уведомления, фоновую работу и самопробуждение в системных настройках.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'Файл \'$file\' слишком большой \'$size\', превышает $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Bu uygulamayı F-Droid\'den indirdiyseniz, bu seçeneği kapatmanız önerilir.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Ön plan hizmeti';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Etkinleştirdikten sonra, bazı cihaz modellerinde çökme olabilir. Devre dışı bırakmak, bazı modellerin SSH bağlantılarını arka planda sürdürememesine neden olabilir. Lütfen sistem ayarlarında ServerBox bildirim izinlerine, arka planda çalışmaya ve kendiliğinden uyanmaya izin verin.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return '\'$file\' dosyası çok büyük $size, maksimum $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => 'Якщо ви завантажили цей застосунок з F-Droid, рекомендується відключити цю опцію.';
|
||||
|
||||
@override
|
||||
String get fgService => 'Служба переднього плану';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => 'Після увімкнення деякі моделі пристроїв можуть вилітати. Вимкнення може призвести до того, що деякі моделі не зможуть підтримувати SSH-з\'єднання у фоновому режимі. Будь ласка, дозвольте ServerBox права на сповіщення, фонову роботу та самопробудження в системних налаштуваннях.';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return 'Файл \'$file\' занадто великий ($size), макс $sizeMax';
|
||||
|
||||
@@ -173,6 +173,12 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
@override
|
||||
String get fdroidReleaseTip => '如果你是从 F-Droid 下载的本应用,推荐关闭此选项';
|
||||
|
||||
@override
|
||||
String get fgService => '前台服务';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => '开启后,可能会导致部分机型闪退。关闭可能导致部分机型无法后台保持 SSH 连接。请在系统设置内允许 ServerBox 通知权限、后台运行、自我唤醒。';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return '文件 \'$file\' 过大 \'$size\',超过了 $sizeMax';
|
||||
@@ -869,6 +875,12 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
|
||||
@override
|
||||
String get fdroidReleaseTip => '如果你是從 F-Droid 下載的本應用,推薦關閉此選項';
|
||||
|
||||
@override
|
||||
String get fgService => '前台服務';
|
||||
|
||||
@override
|
||||
String get fgServiceTip => '開啟後,可能會導致部分機型閃退。關閉可能導致部分機型無法後台保持 SSH 連接。請在系統設置內允許 ServerBox 通知權限、後台運行、自我喚醒。';
|
||||
|
||||
@override
|
||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
||||
return '文件 \'$file\' 過大 \'$size\',超過了 $sizeMax';
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Extra args",
|
||||
"fallbackSshDest": "SSH-Fallback-Ziel",
|
||||
"fdroidReleaseTip": "Wenn Sie diese App von F-Droid heruntergeladen haben, wird empfohlen, diese Option zu deaktivieren.",
|
||||
"fgService": "Vordergrund-Dienst",
|
||||
"fgServiceTip": "Nach dem Einschalten kann es bei einigen Gerätemodellen zu Abstürzen kommen. Das Ausschalten kann bei einigen Modellen dazu führen, dass SSH-Verbindungen im Hintergrund nicht aufrechterhalten werden können. Bitte erlauben Sie ServerBox in den Systemeinstellungen Benachrichtigungsrechte, Hintergrundausführung und Selbstaktivierung.",
|
||||
"fileTooLarge": "Datei '{file}' ist zu groß {size}, max {sizeMax}",
|
||||
"followSystem": "System verfolgen",
|
||||
"font": "Schriftarten",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Extra arguments",
|
||||
"fallbackSshDest": "Fallback SSH destination",
|
||||
"fdroidReleaseTip": "If you downloaded this app from F-Droid, it is recommended to turn off this option.",
|
||||
"fgService": "Foreground Service",
|
||||
"fgServiceTip": "After enabling, some device models may crash. Disabling it may cause some models to be unable to maintain SSH connections in the background. Please allow ServerBox notification permissions, background running, and self-wake-up in system settings.",
|
||||
"fileTooLarge": "File '{file}' too large {size}, max {sizeMax}",
|
||||
"followSystem": "Follow system",
|
||||
"font": "Font",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Argumentos extra",
|
||||
"fallbackSshDest": "Destino SSH alternativo",
|
||||
"fdroidReleaseTip": "Si descargaste esta aplicación desde F-Droid, se recomienda desactivar esta opción.",
|
||||
"fgService": "Servicio en primer plano",
|
||||
"fgServiceTip": "Después de activarlo, algunos modelos de dispositivos pueden bloquearse. Desactivarlo puede hacer que algunos modelos no puedan mantener las conexiones SSH en segundo plano. Por favor, permita los permisos de notificación de ServerBox, la ejecución en segundo plano y el auto-despertar en la configuración del sistema.",
|
||||
"fileTooLarge": "El archivo '{file}' es demasiado grande '{size}', supera el {sizeMax}",
|
||||
"followSystem": "Seguir al sistema",
|
||||
"font": "Fuente",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Arguments supplémentaires",
|
||||
"fallbackSshDest": "Destino SSH alternativo",
|
||||
"fdroidReleaseTip": "Si vous avez téléchargé cette application depuis F-Droid, il est recommandé de désactiver cette option.",
|
||||
"fgService": "Service de premier plan",
|
||||
"fgServiceTip": "Après l'activation, certains modèles d'appareils peuvent planter. La désactivation peut empêcher certains modèles de maintenir les connexions SSH en arrière-plan. Veuillez autoriser les permissions de notification ServerBox, l'exécution en arrière-plan et l'auto-réveil dans les paramètres système.",
|
||||
"fileTooLarge": "Fichier '{file}' trop volumineux {size}, max {sizeMax}",
|
||||
"followSystem": "Suivre le système",
|
||||
"font": "Police",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Args ekstra",
|
||||
"fallbackSshDest": "Tujuan SSH mundur",
|
||||
"fdroidReleaseTip": "Jika Anda mengunduh aplikasi ini dari F-Droid, disarankan untuk mematikan opsi ini.",
|
||||
"fgService": "Layanan Latar Depan",
|
||||
"fgServiceTip": "Setelah diaktifkan, beberapa model perangkat mungkin crash. Menonaktifkannya dapat menyebabkan beberapa model tidak dapat mempertahankan koneksi SSH di latar belakang. Harap izinkan perizinan notifikasi ServerBox, menjalankan di latar belakang, dan bangun mandiri di pengaturan sistem.",
|
||||
"fileTooLarge": "File '{file}' terlalu besar {size}, max {sizeMax}",
|
||||
"followSystem": "Ikuti sistem",
|
||||
"font": "Font",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "追加引数",
|
||||
"fallbackSshDest": "フォールバックSSH宛先",
|
||||
"fdroidReleaseTip": "このアプリをF-Droidからダウンロードした場合、このオプションをオフにすることをお勧めします。",
|
||||
"fgService": "フォアグラウンドサービス",
|
||||
"fgServiceTip": "有効にすると、一部の機種でクラッシュする可能性があります。無効にすると、一部の機種でバックグラウンドでのSSH接続を維持できなくなる可能性があります。システム設定でServerBoxの通知権限、バックグラウンド実行、自己起動を許可してください。",
|
||||
"fileTooLarge": "ファイル '{file}' は大きすぎます '{size}'、{sizeMax} を超えています",
|
||||
"followSystem": "システムに従う",
|
||||
"font": "フォント",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Extra argumenten",
|
||||
"fallbackSshDest": "Fallback SSH-bestemming",
|
||||
"fdroidReleaseTip": "Als u deze app van F-Droid heeft gedownload, wordt aanbevolen deze optie uit te schakelen.",
|
||||
"fgService": "Voorgrondservice",
|
||||
"fgServiceTip": "Na het inschakelen kunnen sommige apparaatmodellen crashen. Uitschakelen kan ertoe leiden dat sommige modellen SSH-verbindingen niet op de achtergrond kunnen behouden. Sta ServerBox notificatierechten, achtergronduitvoering en zelf-ontwaken toe in systeeminstellingen.",
|
||||
"fileTooLarge": "Bestand '{file}' te groot {size}, max {sizeMax}",
|
||||
"followSystem": "Volg systeem",
|
||||
"font": "Lettertype",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Argumentos extras",
|
||||
"fallbackSshDest": "Destino SSH de fallback",
|
||||
"fdroidReleaseTip": "Se você baixou este aplicativo do F-Droid, é recomendado desativar esta opção.",
|
||||
"fgService": "Serviço em primeiro plano",
|
||||
"fgServiceTip": "Após ativar, alguns modelos de dispositivos podem travar. Desativar pode fazer com que alguns modelos não consigam manter conexões SSH em segundo plano. Por favor, permita as permissões de notificação do ServerBox, execução em segundo plano e auto-despertar nas configurações do sistema.",
|
||||
"fileTooLarge": "Arquivo '{file}' muito grande '{size}', excedendo {sizeMax}",
|
||||
"followSystem": "Seguir sistema",
|
||||
"font": "Fonte",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Дополнительные аргументы",
|
||||
"fallbackSshDest": "Резервное место назначения SSH",
|
||||
"fdroidReleaseTip": "Если вы скачали это приложение с F-Droid, рекомендуется отключить эту опцию.",
|
||||
"fgService": "Сервис переднего плана",
|
||||
"fgServiceTip": "После включения некоторые модели устройств могут вылетать. Отключение может привести к тому, что некоторые модели не смогут поддерживать SSH-соединения в фоновом режиме. Пожалуйста, разрешите ServerBox права на уведомления, фоновую работу и самопробуждение в системных настройках.",
|
||||
"fileTooLarge": "Файл '{file}' слишком большой '{size}', превышает {sizeMax}",
|
||||
"followSystem": "Следовать за системой",
|
||||
"font": "Шрифт",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Ek argümanlar",
|
||||
"fallbackSshDest": "Yedek SSH hedefi",
|
||||
"fdroidReleaseTip": "Bu uygulamayı F-Droid'den indirdiyseniz, bu seçeneği kapatmanız önerilir.",
|
||||
"fgService": "Ön plan hizmeti",
|
||||
"fgServiceTip": "Etkinleştirdikten sonra, bazı cihaz modellerinde çökme olabilir. Devre dışı bırakmak, bazı modellerin SSH bağlantılarını arka planda sürdürememesine neden olabilir. Lütfen sistem ayarlarında ServerBox bildirim izinlerine, arka planda çalışmaya ve kendiliğinden uyanmaya izin verin.",
|
||||
"fileTooLarge": "'{file}' dosyası çok büyük {size}, maksimum {sizeMax}",
|
||||
"followSystem": "Sistemi takip et",
|
||||
"font": "Yazı tipi",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "Додаткові аргументи",
|
||||
"fallbackSshDest": "Резервна SSH адреса",
|
||||
"fdroidReleaseTip": "Якщо ви завантажили цей застосунок з F-Droid, рекомендується відключити цю опцію.",
|
||||
"fgService": "Служба переднього плану",
|
||||
"fgServiceTip": "Після увімкнення деякі моделі пристроїв можуть вилітати. Вимкнення може призвести до того, що деякі моделі не зможуть підтримувати SSH-з'єднання у фоновому режимі. Будь ласка, дозвольте ServerBox права на сповіщення, фонову роботу та самопробудження в системних налаштуваннях.",
|
||||
"fileTooLarge": "Файл '{file}' занадто великий ({size}), макс {sizeMax}",
|
||||
"followSystem": "Слідувати системі",
|
||||
"font": "Шрифт",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "额外参数",
|
||||
"fallbackSshDest": "备选 SSH 目标",
|
||||
"fdroidReleaseTip": "如果你是从 F-Droid 下载的本应用,推荐关闭此选项",
|
||||
"fgService": "前台服务",
|
||||
"fgServiceTip": "开启后,可能会导致部分机型闪退。关闭可能导致部分机型无法后台保持 SSH 连接。请在系统设置内允许 ServerBox 通知权限、后台运行、自我唤醒。",
|
||||
"fileTooLarge": "文件 '{file}' 过大 '{size}',超过了 {sizeMax}",
|
||||
"followSystem": "跟随系统",
|
||||
"font": "字体",
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
"extraArgs": "額外參數",
|
||||
"fallbackSshDest": "備選 SSH 目標",
|
||||
"fdroidReleaseTip": "如果你是從 F-Droid 下載的本應用,推薦關閉此選項",
|
||||
"fgService": "前台服務",
|
||||
"fgServiceTip": "開啟後,可能會導致部分機型閃退。關閉可能導致部分機型無法後台保持 SSH 連接。請在系統設置內允許 ServerBox 通知權限、後台運行、自我喚醒。",
|
||||
"fileTooLarge": "文件 '{file}' 過大 '{size}',超過了 {sizeMax}",
|
||||
"followSystem": "跟隨系統",
|
||||
"font": "字型",
|
||||
|
||||
@@ -21,6 +21,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 17),
|
||||
children: [
|
||||
_buildFgService(),
|
||||
_buildBgRun(),
|
||||
_buildAndroidWidgetSharedPreference(),
|
||||
if (BioAuth.isPlatformSupported)
|
||||
@@ -115,4 +116,11 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget _buildFgService() {
|
||||
return ListTile(
|
||||
title: TipText(l10n.fgService, l10n.fgServiceTip),
|
||||
trailing: StoreSwitch(prop: Stores.setting.fgService),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ class SSHPageState extends State<SSHPage>
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_virtKeyLongPressTimer?.cancel();
|
||||
_terminalController.dispose();
|
||||
_discontinuityTimer?.cancel();
|
||||
@@ -87,6 +86,7 @@ class SSHPageState extends State<SSHPage>
|
||||
MethodChans.stopService();
|
||||
}
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -270,6 +270,161 @@ class SSHPageState extends State<SSHPage>
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
void _initStoredCfg() {
|
||||
final fontFamilly = Stores.setting.fontPath.fetch().getFileName();
|
||||
final textSize = Stores.setting.termFontSize.fetch();
|
||||
final textStyle = TextStyle(
|
||||
fontFamily: fontFamilly,
|
||||
fontSize: textSize,
|
||||
);
|
||||
|
||||
_terminalStyle = TerminalStyle.fromTextStyle(textStyle);
|
||||
}
|
||||
|
||||
Future<void> _showHelp() async {
|
||||
if (Stores.setting.sshTermHelpShown.fetch()) return;
|
||||
|
||||
return await context.showRoundDialog(
|
||||
title: libL10n.doc,
|
||||
child: Text(l10n.sshTermHelp),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Stores.setting.sshTermHelpShown.put(true);
|
||||
context.pop();
|
||||
},
|
||||
child: Text(l10n.noPromptAgain),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> afterFirstLayout(BuildContext context) async {
|
||||
await _showHelp();
|
||||
await _initTerminal();
|
||||
|
||||
if (Stores.setting.sshWakeLock.fetch()) WakelockPlus.enable();
|
||||
}
|
||||
}
|
||||
|
||||
extension _Init on SSHPageState {
|
||||
Future<void> _initTerminal() async {
|
||||
_writeLn(l10n.waitConnection);
|
||||
_client ??= await genClient(
|
||||
widget.spi,
|
||||
onStatus: (p0) {
|
||||
_writeLn(p0.toString());
|
||||
},
|
||||
onKeyboardInteractive: _onKeyboardInteractive,
|
||||
);
|
||||
|
||||
_writeLn('${libL10n.execute}: Shell');
|
||||
final session = await _client?.shell(
|
||||
pty: SSHPtyConfig(
|
||||
width: _terminal.viewWidth,
|
||||
height: _terminal.viewHeight,
|
||||
),
|
||||
environment: widget.spi.envs,
|
||||
);
|
||||
|
||||
//_setupDiscontinuityTimer();
|
||||
|
||||
if (session == null) {
|
||||
_writeLn(libL10n.fail);
|
||||
return;
|
||||
}
|
||||
|
||||
_terminal.buffer.clear();
|
||||
_terminal.buffer.setCursor(0, 0);
|
||||
|
||||
_terminal.onOutput = (data) {
|
||||
session.write(utf8.encode(data));
|
||||
};
|
||||
_terminal.onResize = (width, height, pixelWidth, pixelHeight) {
|
||||
session.resizeTerminal(width, height);
|
||||
};
|
||||
|
||||
_listen(session.stdout);
|
||||
_listen(session.stderr);
|
||||
|
||||
for (final snippet in SnippetProvider.snippets.value) {
|
||||
if (snippet.autoRunOn?.contains(widget.spi.id) == true) {
|
||||
snippet.runInTerm(_terminal, widget.spi);
|
||||
}
|
||||
}
|
||||
|
||||
if (widget.initCmd != null) {
|
||||
_terminal.textInput(widget.initCmd!);
|
||||
_terminal.keyInput(TerminalKey.enter);
|
||||
}
|
||||
|
||||
if (widget.initSnippet != null) {
|
||||
widget.initSnippet!.runInTerm(_terminal, widget.spi);
|
||||
}
|
||||
|
||||
widget.focusNode?.requestFocus();
|
||||
|
||||
await session.done;
|
||||
if (mounted && widget.notFromTab) {
|
||||
context.pop();
|
||||
}
|
||||
widget.onSessionEnd?.call();
|
||||
}
|
||||
|
||||
void _listen(Stream<Uint8List>? stream) {
|
||||
if (stream == null) {
|
||||
return;
|
||||
}
|
||||
stream
|
||||
.cast<List<int>>()
|
||||
.transform(const Utf8Decoder())
|
||||
.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 _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,
|
||||
);
|
||||
}
|
||||
|
||||
void _writeLn(String p0) {
|
||||
_terminal.write('$p0\r\n');
|
||||
}
|
||||
}
|
||||
|
||||
extension _VirtKey on SSHPageState {
|
||||
void _doVirtualKey(VirtKey item) {
|
||||
if (item.func != null) {
|
||||
HapticFeedback.mediumImpact();
|
||||
@@ -380,10 +535,6 @@ class SSHPageState extends State<SSHPage>
|
||||
return _terminal.buffer.getText(range);
|
||||
}
|
||||
|
||||
void _writeLn(String p0) {
|
||||
_terminal.write('$p0\r\n');
|
||||
}
|
||||
|
||||
void _initVirtKeys() {
|
||||
final virtKeys = VirtKeyX.loadFromStore();
|
||||
for (int len = 0; len < virtKeys.length; len += 7) {
|
||||
@@ -398,151 +549,4 @@ class SSHPageState extends State<SSHPage>
|
||||
FutureOr<List<String>?> _onKeyboardInteractive(SSHUserInfoRequest req) {
|
||||
return KeybordInteractive.defaultHandle(widget.spi, ctx: context);
|
||||
}
|
||||
|
||||
Future<void> _initTerminal() async {
|
||||
_writeLn(l10n.waitConnection);
|
||||
_client ??= await genClient(
|
||||
widget.spi,
|
||||
onStatus: (p0) {
|
||||
_writeLn(p0.toString());
|
||||
},
|
||||
onKeyboardInteractive: _onKeyboardInteractive,
|
||||
);
|
||||
|
||||
_writeLn('${libL10n.execute}: Shell');
|
||||
final session = await _client?.shell(
|
||||
pty: SSHPtyConfig(
|
||||
width: _terminal.viewWidth,
|
||||
height: _terminal.viewHeight,
|
||||
),
|
||||
environment: widget.spi.envs,
|
||||
);
|
||||
|
||||
//_setupDiscontinuityTimer();
|
||||
|
||||
if (session == null) {
|
||||
_writeLn(libL10n.fail);
|
||||
return;
|
||||
}
|
||||
|
||||
_terminal.buffer.clear();
|
||||
_terminal.buffer.setCursor(0, 0);
|
||||
|
||||
_terminal.onOutput = (data) {
|
||||
session.write(utf8.encode(data));
|
||||
};
|
||||
_terminal.onResize = (width, height, pixelWidth, pixelHeight) {
|
||||
session.resizeTerminal(width, height);
|
||||
};
|
||||
|
||||
_listen(session.stdout);
|
||||
_listen(session.stderr);
|
||||
|
||||
for (final snippet in SnippetProvider.snippets.value) {
|
||||
if (snippet.autoRunOn?.contains(widget.spi.id) == true) {
|
||||
snippet.runInTerm(_terminal, widget.spi);
|
||||
}
|
||||
}
|
||||
|
||||
if (widget.initCmd != null) {
|
||||
_terminal.textInput(widget.initCmd!);
|
||||
_terminal.keyInput(TerminalKey.enter);
|
||||
}
|
||||
|
||||
if (widget.initSnippet != null) {
|
||||
widget.initSnippet!.runInTerm(_terminal, widget.spi);
|
||||
}
|
||||
|
||||
widget.focusNode?.requestFocus();
|
||||
|
||||
await session.done;
|
||||
if (mounted && widget.notFromTab) {
|
||||
context.pop();
|
||||
}
|
||||
widget.onSessionEnd?.call();
|
||||
}
|
||||
|
||||
void _listen(Stream<Uint8List>? stream) {
|
||||
if (stream == null) {
|
||||
return;
|
||||
}
|
||||
stream
|
||||
.cast<List<int>>()
|
||||
.transform(const Utf8Decoder())
|
||||
.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 _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;
|
||||
|
||||
void _initStoredCfg() {
|
||||
final fontFamilly = Stores.setting.fontPath.fetch().getFileName();
|
||||
final textSize = Stores.setting.termFontSize.fetch();
|
||||
final textStyle = TextStyle(
|
||||
fontFamily: fontFamilly,
|
||||
fontSize: textSize,
|
||||
);
|
||||
|
||||
_terminalStyle = TerminalStyle.fromTextStyle(textStyle);
|
||||
}
|
||||
|
||||
Future<void> _showHelp() async {
|
||||
if (Stores.setting.sshTermHelpShown.fetch()) return;
|
||||
|
||||
return await context.showRoundDialog(
|
||||
title: libL10n.doc,
|
||||
child: Text(l10n.sshTermHelp),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Stores.setting.sshTermHelpShown.put(true);
|
||||
context.pop();
|
||||
},
|
||||
child: Text(l10n.noPromptAgain),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<void> afterFirstLayout(BuildContext context) async {
|
||||
await _showHelp();
|
||||
await _initTerminal();
|
||||
|
||||
if (Stores.setting.sshWakeLock.fetch()) WakelockPlus.enable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,30 +67,6 @@ class _SSHTabPageState extends State<SSHTabPage>
|
||||
);
|
||||
}
|
||||
|
||||
void _onTapTab(int idx) async {
|
||||
await _toPage(idx);
|
||||
}
|
||||
|
||||
void _onTapClose(String name) async {
|
||||
final confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(libL10n.attention),
|
||||
content: Text('${libL10n.close} SSH ${l10n.conn}($name) ?'),
|
||||
actions: Btnx.okReds,
|
||||
);
|
||||
},
|
||||
);
|
||||
Future.delayed(Durations.short1, FocusScope.of(context).unfocus);
|
||||
if (confirm != true) return;
|
||||
|
||||
_tabMap.remove(name);
|
||||
_tabRN.notify();
|
||||
_pageCtrl.previousPage(
|
||||
duration: Durations.medium1, curve: Curves.fastEaseInToSlowEaseOut);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return ListenBuilder(
|
||||
listenable: _tabRN,
|
||||
@@ -109,6 +85,11 @@ class _SSHTabPageState extends State<SSHTabPage>
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
}
|
||||
|
||||
extension on _SSHTabPageState {
|
||||
void _onTapInitCard(Spi spi) async {
|
||||
final name = () {
|
||||
final reg = RegExp('${spi.name}\\((\\d+)\\)');
|
||||
@@ -155,8 +136,29 @@ class _SSHTabPageState extends State<SSHTabPage>
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
void _onTapTab(int idx) async {
|
||||
await _toPage(idx);
|
||||
}
|
||||
|
||||
void _onTapClose(String name) async {
|
||||
final confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(libL10n.attention),
|
||||
content: Text('${libL10n.close} SSH ${l10n.conn}($name) ?'),
|
||||
actions: Btnx.okReds,
|
||||
);
|
||||
},
|
||||
);
|
||||
Future.delayed(Durations.short1, FocusScope.of(context).unfocus);
|
||||
if (confirm != true) return;
|
||||
|
||||
_tabMap.remove(name);
|
||||
_tabRN.notify();
|
||||
_pageCtrl.previousPage(
|
||||
duration: Durations.medium1, curve: Curves.fastEaseInToSlowEaseOut);
|
||||
}
|
||||
}
|
||||
|
||||
final class _TabBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
|
||||
@@ -471,7 +471,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
|
||||
@@ -481,7 +481,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "Server Box";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -608,7 +608,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
|
||||
@@ -618,7 +618,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "Server Box";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -638,7 +638,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1117;
|
||||
CURRENT_PROJECT_VERSION = 1124;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -649,7 +649,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MARKETING_VERSION = 1.0.1117;
|
||||
MARKETING_VERSION = 1.0.1124;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "Server Box";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: server_box
|
||||
description: server status & toolbox app.
|
||||
publish_to: 'none'
|
||||
version: 1.0.1117+1117
|
||||
version: 1.0.1124+1124
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0"
|
||||
|
||||
Reference in New Issue
Block a user