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")
+ )
}
}