From 0065b8a92bf265c939a120ccc049e2d0c8530b6e Mon Sep 17 00:00:00 2001 From: white Date: Thu, 4 Dec 2025 16:08:05 +0300 Subject: [PATCH] added module errors handling on service start, stop, restart, added automated service status updating on start, stop, restart --- .idea/appInsightsSettings.xml | 21 +++++++++ .../java/com/cherret/zaprett/MainActivity.kt | 2 +- .../cherret/zaprett/ui/screen/HomeScreen.kt | 43 ++++++++++++++++++- .../zaprett/ui/viewmodel/HomeViewModel.kt | 22 ++++++++-- .../cherret/zaprett/utils/ZaprettManager.kt | 28 ++++++++---- 5 files changed, 102 insertions(+), 14 deletions(-) diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml index 6bbe2ae..6d93a00 100644 --- a/.idea/appInsightsSettings.xml +++ b/.idea/appInsightsSettings.xml @@ -2,5 +2,26 @@ \ No newline at end of file diff --git a/app/src/main/java/com/cherret/zaprett/MainActivity.kt b/app/src/main/java/com/cherret/zaprett/MainActivity.kt index f2cb24e..908fc2c 100644 --- a/app/src/main/java/com/cherret/zaprett/MainActivity.kt +++ b/app/src/main/java/com/cherret/zaprett/MainActivity.kt @@ -209,7 +209,7 @@ class MainActivity : ComponentActivity() { startDestination = Screen.home.route, Modifier.padding(innerPadding) ) { - composable(Screen.home.route) { HomeScreen(viewModel = viewModel, vpnPermissionLauncher) } + composable(Screen.home.route) { HomeScreen(viewModel = viewModel, navController,vpnPermissionLauncher) } composable(Screen.hosts.route) { HostsScreen(navController) } composable(Screen.strategies.route) { StrategyScreen(navController) } composable(Screen.ipsets.route) { IpsetsScreen(navController) } diff --git a/app/src/main/java/com/cherret/zaprett/ui/screen/HomeScreen.kt b/app/src/main/java/com/cherret/zaprett/ui/screen/HomeScreen.kt index 0f1973a..c4fd7e3 100644 --- a/app/src/main/java/com/cherret/zaprett/ui/screen/HomeScreen.kt +++ b/app/src/main/java/com/cherret/zaprett/ui/screen/HomeScreen.kt @@ -1,9 +1,13 @@ package com.cherret.zaprett.ui.screen +import android.content.ClipData +import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.net.VpnService +import android.os.Build +import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically @@ -65,16 +69,19 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController import com.cherret.zaprett.BuildConfig import com.cherret.zaprett.R import com.cherret.zaprett.data.ServiceStatusUI import com.cherret.zaprett.ui.viewmodel.HomeViewModel import dev.jeziellago.compose.markdowntext.MarkdownText import kotlinx.coroutines.CoroutineScope +import kotlinx.serialization.SerializationException +import java.io.IOException @OptIn(ExperimentalMaterial3Api::class) @Composable -fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResultLauncher) { +fun HomeScreen(viewModel: HomeViewModel = viewModel(), navController: NavController, vpnLauncher: ActivityResultLauncher) { val context = LocalContext.current val sharedPreferences: SharedPreferences = remember { context.getSharedPreferences("settings", Context.MODE_PRIVATE) } val requestVpnPermission by viewModel.requestVpnPermission.collectAsState() @@ -89,6 +96,7 @@ fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResu val nfqwsVer = viewModel.nfqwsVer; val byedpiVer = viewModel.byedpiVer; val serviceMode = viewModel.serviceMode + val error by viewModel.errorFlow.collectAsState() LaunchedEffect(Unit) { viewModel.checkForUpdate() viewModel.checkServiceStatus() @@ -107,6 +115,39 @@ fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResu } } + if (error.isNotEmpty()) { + AlertDialog( + onDismissRequest = { + viewModel.clearError() + navController.popBackStack() + }, + title = { Text(stringResource(R.string.error_text)) }, + text = { + Text(stringResource(R.string.error_unknown)) + }, + dismissButton = { + TextButton(onClick = { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clip: ClipData = ClipData.newPlainText("Error log", error) + clipboard.setPrimaryClip(clip) + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) { + Toast.makeText(context, context.getString(R.string.log_copied), Toast.LENGTH_SHORT).show() + } + }) { + Text(stringResource(R.string.btn_copy_log)) + } + }, + confirmButton = { + TextButton(onClick = { + viewModel.clearError() + navController.popBackStack() + }) { + Text(stringResource(R.string.btn_continue)) + } + } + ) + } + Scaffold( topBar = { TopAppBar( diff --git a/app/src/main/java/com/cherret/zaprett/ui/viewmodel/HomeViewModel.kt b/app/src/main/java/com/cherret/zaprett/ui/viewmodel/HomeViewModel.kt index a29079b..8d2c744 100644 --- a/app/src/main/java/com/cherret/zaprett/ui/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/com/cherret/zaprett/ui/viewmodel/HomeViewModel.kt @@ -45,6 +45,9 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { private val _serviceStatus = MutableStateFlow(ServiceStatusUI()) val serviceStatus: StateFlow = _serviceStatus.asStateFlow() + private val _errorFlow = MutableStateFlow("") + val errorFlow = _errorFlow.asStateFlow() + var moduleVer = mutableStateOf(context.getString(R.string.unknown_text)) private set @@ -129,7 +132,10 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { ) ) } - if (!isEnabled) startService {} + if (!isEnabled) startService { error -> + _errorFlow.value = error + onCardClick() + } } } else { if (ByeDpiVpnService.status == ServiceStatus.Disconnected || ByeDpiVpnService.status == ServiceStatus.Failed) { @@ -169,7 +175,10 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { ) ) } - if (isEnabled) stopService {} + if (isEnabled) stopService { error -> + _errorFlow.value = error + onCardClick() + } } } else { if (ByeDpiVpnService.status == ServiceStatus.Connected) { @@ -192,7 +201,10 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { fun onBtnRestart(snackbarHostState: SnackbarHostState, scope: CoroutineScope) { if (prefs.getBoolean("use_module", false)) { - restartService {} + restartService { error -> + _errorFlow.value = error + onCardClick() + } scope.launch { snackbarHostState.showSnackbar(context.getString(R.string.snack_reload)) } @@ -242,6 +254,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { } } + // unused? fun parseArgs(ip: String, port: String, lines: List): Array { val regex = Regex("""--?\S+(?:=(?:[^"'\s]+|"[^"]*"|'[^']*'))?|[^\s]+""") val parsedArgs = lines @@ -249,4 +262,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { return arrayOf("ciadpi", "--ip", ip, "--port", port) + parsedArgs } + fun clearError() { + _errorFlow.value = "" + } } \ No newline at end of file diff --git a/app/src/main/java/com/cherret/zaprett/utils/ZaprettManager.kt b/app/src/main/java/com/cherret/zaprett/utils/ZaprettManager.kt index 118b740..f6ac628 100644 --- a/app/src/main/java/com/cherret/zaprett/utils/ZaprettManager.kt +++ b/app/src/main/java/com/cherret/zaprett/utils/ZaprettManager.kt @@ -75,21 +75,31 @@ fun getStatus(callback: (Boolean) -> Unit) { } } -fun startService(callback: (Boolean) -> Unit) { - Shell.cmd("zaprett start").submit { result -> - callback(result.isSuccess) +fun startService(callback: (String) -> Unit) { + Shell.cmd("zaprett start 2>&1").submit { result -> + callback( + if (result.isSuccess) "" + else result.out.joinToString("\n") + ) } } -fun stopService(callback: (Boolean) -> Unit) { - Shell.cmd("zaprett stop").submit { result -> - callback(result.isSuccess) + +fun stopService(callback: (String) -> Unit) { + Shell.cmd("zaprett stop 2>&1").submit { result -> + callback( + if (result.isSuccess) "" + else result.out.joinToString("\n") + ) } } -fun restartService(callback: (Boolean) -> Unit) { - Shell.cmd("zaprett restart").submit { result -> - callback(result.isSuccess) +fun restartService(callback: (String) -> Unit) { + Shell.cmd("zaprett restart 2>&1").submit { result -> + callback( + if (result.isSuccess) "" + else result.out.joinToString("\n") + ) } }