mirror of
https://github.com/CherretGit/zaprett-app.git
synced 2025-12-10 05:29:37 +05:00
added module errors handling on service start, stop, restart, added automated service status updating on start, stop, restart
This commit is contained in:
21
.idea/appInsightsSettings.xml
generated
21
.idea/appInsightsSettings.xml
generated
@@ -2,5 +2,26 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="AppInsightsSettings">
|
<component name="AppInsightsSettings">
|
||||||
<option name="selectedTabId" value="Android Vitals" />
|
<option name="selectedTabId" value="Android Vitals" />
|
||||||
|
<option name="tabSettings">
|
||||||
|
<map>
|
||||||
|
<entry key="Firebase Crashlytics">
|
||||||
|
<value>
|
||||||
|
<InsightsFilterSettings>
|
||||||
|
<option name="connection">
|
||||||
|
<ConnectionSetting>
|
||||||
|
<option name="appId" value="com.cherret.zaprett" />
|
||||||
|
<option name="mobileSdkAppId" value="1:1005804036856:android:e7db5546b8bb4daf91510d" />
|
||||||
|
<option name="projectId" value="zaprett-app" />
|
||||||
|
<option name="projectNumber" value="1005804036856" />
|
||||||
|
</ConnectionSetting>
|
||||||
|
</option>
|
||||||
|
<option name="signal" value="SIGNAL_UNSPECIFIED" />
|
||||||
|
<option name="timeIntervalDays" value="THIRTY_DAYS" />
|
||||||
|
<option name="visibilityType" value="ALL" />
|
||||||
|
</InsightsFilterSettings>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -209,7 +209,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
startDestination = Screen.home.route,
|
startDestination = Screen.home.route,
|
||||||
Modifier.padding(innerPadding)
|
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.hosts.route) { HostsScreen(navController) }
|
||||||
composable(Screen.strategies.route) { StrategyScreen(navController) }
|
composable(Screen.strategies.route) { StrategyScreen(navController) }
|
||||||
composable(Screen.ipsets.route) { IpsetsScreen(navController) }
|
composable(Screen.ipsets.route) { IpsetsScreen(navController) }
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package com.cherret.zaprett.ui.screen
|
package com.cherret.zaprett.ui.screen
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.VpnService
|
import android.net.VpnService
|
||||||
|
import android.os.Build
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.expandVertically
|
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.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
import com.cherret.zaprett.BuildConfig
|
import com.cherret.zaprett.BuildConfig
|
||||||
import com.cherret.zaprett.R
|
import com.cherret.zaprett.R
|
||||||
import com.cherret.zaprett.data.ServiceStatusUI
|
import com.cherret.zaprett.data.ServiceStatusUI
|
||||||
import com.cherret.zaprett.ui.viewmodel.HomeViewModel
|
import com.cherret.zaprett.ui.viewmodel.HomeViewModel
|
||||||
import dev.jeziellago.compose.markdowntext.MarkdownText
|
import dev.jeziellago.compose.markdowntext.MarkdownText
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.serialization.SerializationException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResultLauncher<Intent>) {
|
fun HomeScreen(viewModel: HomeViewModel = viewModel(), navController: NavController, vpnLauncher: ActivityResultLauncher<Intent>) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val sharedPreferences: SharedPreferences = remember { context.getSharedPreferences("settings", Context.MODE_PRIVATE) }
|
val sharedPreferences: SharedPreferences = remember { context.getSharedPreferences("settings", Context.MODE_PRIVATE) }
|
||||||
val requestVpnPermission by viewModel.requestVpnPermission.collectAsState()
|
val requestVpnPermission by viewModel.requestVpnPermission.collectAsState()
|
||||||
@@ -89,6 +96,7 @@ fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResu
|
|||||||
val nfqwsVer = viewModel.nfqwsVer;
|
val nfqwsVer = viewModel.nfqwsVer;
|
||||||
val byedpiVer = viewModel.byedpiVer;
|
val byedpiVer = viewModel.byedpiVer;
|
||||||
val serviceMode = viewModel.serviceMode
|
val serviceMode = viewModel.serviceMode
|
||||||
|
val error by viewModel.errorFlow.collectAsState()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.checkForUpdate()
|
viewModel.checkForUpdate()
|
||||||
viewModel.checkServiceStatus()
|
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(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
private val _serviceStatus = MutableStateFlow(ServiceStatusUI())
|
private val _serviceStatus = MutableStateFlow(ServiceStatusUI())
|
||||||
val serviceStatus: StateFlow<ServiceStatusUI> = _serviceStatus.asStateFlow()
|
val serviceStatus: StateFlow<ServiceStatusUI> = _serviceStatus.asStateFlow()
|
||||||
|
|
||||||
|
private val _errorFlow = MutableStateFlow("")
|
||||||
|
val errorFlow = _errorFlow.asStateFlow()
|
||||||
|
|
||||||
var moduleVer = mutableStateOf(context.getString(R.string.unknown_text))
|
var moduleVer = mutableStateOf(context.getString(R.string.unknown_text))
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -129,7 +132,10 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (!isEnabled) startService {}
|
if (!isEnabled) startService { error ->
|
||||||
|
_errorFlow.value = error
|
||||||
|
onCardClick()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ByeDpiVpnService.status == ServiceStatus.Disconnected || ByeDpiVpnService.status == ServiceStatus.Failed) {
|
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 {
|
} else {
|
||||||
if (ByeDpiVpnService.status == ServiceStatus.Connected) {
|
if (ByeDpiVpnService.status == ServiceStatus.Connected) {
|
||||||
@@ -192,7 +201,10 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
|
|
||||||
fun onBtnRestart(snackbarHostState: SnackbarHostState, scope: CoroutineScope) {
|
fun onBtnRestart(snackbarHostState: SnackbarHostState, scope: CoroutineScope) {
|
||||||
if (prefs.getBoolean("use_module", false)) {
|
if (prefs.getBoolean("use_module", false)) {
|
||||||
restartService {}
|
restartService { error ->
|
||||||
|
_errorFlow.value = error
|
||||||
|
onCardClick()
|
||||||
|
}
|
||||||
scope.launch {
|
scope.launch {
|
||||||
snackbarHostState.showSnackbar(context.getString(R.string.snack_reload))
|
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<String>): Array<String> {
|
fun parseArgs(ip: String, port: String, lines: List<String>): Array<String> {
|
||||||
val regex = Regex("""--?\S+(?:=(?:[^"'\s]+|"[^"]*"|'[^']*'))?|[^\s]+""")
|
val regex = Regex("""--?\S+(?:=(?:[^"'\s]+|"[^"]*"|'[^']*'))?|[^\s]+""")
|
||||||
val parsedArgs = lines
|
val parsedArgs = lines
|
||||||
@@ -249,4 +262,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
return arrayOf("ciadpi", "--ip", ip, "--port", port) + parsedArgs
|
return arrayOf("ciadpi", "--ip", ip, "--port", port) + parsedArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clearError() {
|
||||||
|
_errorFlow.value = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -75,21 +75,31 @@ fun getStatus(callback: (Boolean) -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startService(callback: (Boolean) -> Unit) {
|
fun startService(callback: (String) -> Unit) {
|
||||||
Shell.cmd("zaprett start").submit { result ->
|
Shell.cmd("zaprett start 2>&1").submit { result ->
|
||||||
callback(result.isSuccess)
|
callback(
|
||||||
|
if (result.isSuccess) ""
|
||||||
|
else result.out.joinToString("\n")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopService(callback: (Boolean) -> Unit) {
|
|
||||||
Shell.cmd("zaprett stop").submit { result ->
|
fun stopService(callback: (String) -> Unit) {
|
||||||
callback(result.isSuccess)
|
Shell.cmd("zaprett stop 2>&1").submit { result ->
|
||||||
|
callback(
|
||||||
|
if (result.isSuccess) ""
|
||||||
|
else result.out.joinToString("\n")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restartService(callback: (Boolean) -> Unit) {
|
fun restartService(callback: (String) -> Unit) {
|
||||||
Shell.cmd("zaprett restart").submit { result ->
|
Shell.cmd("zaprett restart 2>&1").submit { result ->
|
||||||
callback(result.isSuccess)
|
callback(
|
||||||
|
if (result.isSuccess) ""
|
||||||
|
else result.out.joinToString("\n")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user