mirror of
https://github.com/CherretGit/zaprett-app.git
synced 2025-12-10 05:29:37 +05:00
Compare commits
2 Commits
80f5934060
...
57217bbe1c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57217bbe1c | ||
|
|
6f9bd86d70 |
@@ -1,7 +1,11 @@
|
||||
package com.cherret.zaprett.ui.screen
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -79,11 +83,43 @@ fun HostsScreen(navController: NavController, viewModel: HostsViewModel = viewMo
|
||||
if (getHostListMode(prefs) == "whitelist") viewModel.copySelectedFile(context, "/lists/include", it)
|
||||
else viewModel.copySelectedFile(context, "/lists/exclude", it) }
|
||||
}
|
||||
val error by viewModel.errorFlow.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
if (error.isNotEmpty()) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
viewModel.clearError()
|
||||
},
|
||||
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()
|
||||
}) {
|
||||
Text(stringResource(R.string.btn_continue))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.cherret.zaprett.ui.screen
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -79,11 +83,43 @@ fun IpsetsScreen(navController: NavController, viewModel: IpsetViewModel = viewM
|
||||
if (getHostListMode(prefs) == "whitelist") viewModel.copySelectedFile(context, "/ipset/include", it)
|
||||
else viewModel.copySelectedFile(context, "/ipset/exclude", it) }
|
||||
}
|
||||
val error by viewModel.errorFlow.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
if (error.isNotEmpty()) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
viewModel.clearError()
|
||||
},
|
||||
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()
|
||||
}) {
|
||||
Text(stringResource(R.string.btn_continue))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.cherret.zaprett.ui.screen
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -73,11 +77,43 @@ fun StrategyScreen(navController: NavController, viewModel: StrategyViewModel =
|
||||
it
|
||||
) }
|
||||
}
|
||||
val error by viewModel.errorFlow.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
if (error.isNotEmpty()) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
viewModel.clearError()
|
||||
},
|
||||
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()
|
||||
}) {
|
||||
Text(stringResource(R.string.btn_continue))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package com.cherret.zaprett.ui.screen
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.Intent
|
||||
import android.net.VpnService
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -59,6 +64,7 @@ fun StrategySelectionScreen(navController: NavController, vpnLauncher: ActivityR
|
||||
val prefs = context.getSharedPreferences("settings", MODE_PRIVATE)
|
||||
var showDialog = remember { mutableStateOf(false) }
|
||||
val requestVpnPermission by viewModel.requestVpnPermission.collectAsState()
|
||||
val error by viewModel.errorFlow.collectAsState()
|
||||
|
||||
if (showDialog.value) {
|
||||
InfoAlert { showDialog.value = false }
|
||||
@@ -76,6 +82,37 @@ fun StrategySelectionScreen(navController: NavController, vpnLauncher: ActivityR
|
||||
}
|
||||
}
|
||||
|
||||
if (error.isNotEmpty()) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
viewModel.clearError()
|
||||
},
|
||||
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()
|
||||
}) {
|
||||
Text(stringResource(R.string.btn_continue))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.cherret.zaprett.utils.restartService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@@ -37,6 +38,9 @@ abstract class BaseListsViewModel(application: Application) : AndroidViewModel(a
|
||||
var isRefreshing by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
private val _errorFlow = MutableStateFlow("")
|
||||
val errorFlow = _errorFlow.asStateFlow()
|
||||
|
||||
private var _showNoPermissionDialog = MutableStateFlow(false)
|
||||
val showNoPermissionDialog: StateFlow<Boolean> = _showNoPermissionDialog
|
||||
|
||||
@@ -72,12 +76,18 @@ abstract class BaseListsViewModel(application: Application) : AndroidViewModel(a
|
||||
actionLabel = context.getString(R.string.btn_restart_service)
|
||||
)
|
||||
if (result == SnackbarResult.ActionPerformed) {
|
||||
restartService {}
|
||||
restartService { error ->
|
||||
_errorFlow.value = error
|
||||
}
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.snack_reload))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clearError() {
|
||||
_errorFlow.value = ""
|
||||
}
|
||||
|
||||
fun copySelectedFile(context: Context, path: String, uri: Uri) {
|
||||
//if (!Environment.isExternalStorageManager()) return
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
|
||||
|
||||
@@ -43,6 +43,8 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
|
||||
val context = application
|
||||
private val _requestVpnPermission = MutableStateFlow(false)
|
||||
val requestVpnPermission = _requestVpnPermission.asStateFlow()
|
||||
private val _errorFlow = MutableStateFlow("")
|
||||
val errorFlow = _errorFlow.asStateFlow()
|
||||
val strategyStates = mutableStateListOf<StrategyCheckResult>()
|
||||
var noHostsCard = mutableStateOf(false)
|
||||
private set
|
||||
@@ -125,8 +127,12 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
|
||||
strategyStates[index] = current.copy(status = StrategyTestingStatus.Testing)
|
||||
enableStrategy(current.path, prefs)
|
||||
if (prefs.getBoolean("use_module", false)) {
|
||||
getStatus { if (it) stopService {} }
|
||||
startService {}
|
||||
getStatus { if (it) stopService { error ->
|
||||
_errorFlow.value = error
|
||||
} }
|
||||
startService { error ->
|
||||
_errorFlow.value = error
|
||||
}
|
||||
try {
|
||||
val progress = countReachable(index, targets)
|
||||
val old = strategyStates[index]
|
||||
@@ -135,7 +141,9 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
|
||||
status = StrategyTestingStatus.Completed
|
||||
)
|
||||
} finally {
|
||||
stopService {}
|
||||
stopService { error ->
|
||||
_errorFlow.value = error
|
||||
}
|
||||
disableStrategy(current.path, prefs)
|
||||
}
|
||||
}
|
||||
@@ -189,4 +197,7 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
|
||||
fun clearVpnPermissionRequest() {
|
||||
_requestVpnPermission.value = false
|
||||
}
|
||||
fun clearError() {
|
||||
_errorFlow.value = ""
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
agp = "8.13.0"
|
||||
agp = "8.13.1"
|
||||
kotlin = "2.2.10"
|
||||
coreKtx = "1.17.0"
|
||||
junit = "4.13.2"
|
||||
|
||||
Reference in New Issue
Block a user