diff --git a/app/src/main/java/com/cherret/zaprett/MainActivity.kt b/app/src/main/java/com/cherret/zaprett/MainActivity.kt index f41782d..bb03570 100644 --- a/app/src/main/java/com/cherret/zaprett/MainActivity.kt +++ b/app/src/main/java/com/cherret/zaprett/MainActivity.kt @@ -240,7 +240,7 @@ class MainActivity : ComponentActivity() { } } composable("debugScreen") { DebugScreen(navController) } - composable("selectionScreen") { StrategySelectionScreen(navController) } + composable("selectionScreen") { StrategySelectionScreen(navController, vpnPermissionLauncher) } } } } diff --git a/app/src/main/java/com/cherret/zaprett/ui/component/ListItems.kt b/app/src/main/java/com/cherret/zaprett/ui/component/ListItems.kt index ea417c1..8efae18 100644 --- a/app/src/main/java/com/cherret/zaprett/ui/component/ListItems.kt +++ b/app/src/main/java/com/cherret/zaprett/ui/component/ListItems.kt @@ -205,7 +205,7 @@ fun StrategySelectionItem(strategy : StrategyCheckResult, prefs : SharedPreferen ) FilledTonalIconButton( onClick = { - disableStrategy(getActiveStrategy(prefs)[0], prefs) + if (getActiveStrategy(prefs).isNotEmpty()) disableStrategy(getActiveStrategy(prefs)[0], prefs) enableStrategy(strategy.path, prefs) scope.launch { snackbarHostState.showSnackbar( diff --git a/app/src/main/java/com/cherret/zaprett/ui/screen/StrategySelectionScreen.kt b/app/src/main/java/com/cherret/zaprett/ui/screen/StrategySelectionScreen.kt index f6a9e22..c598caa 100644 --- a/app/src/main/java/com/cherret/zaprett/ui/screen/StrategySelectionScreen.kt +++ b/app/src/main/java/com/cherret/zaprett/ui/screen/StrategySelectionScreen.kt @@ -1,6 +1,9 @@ package com.cherret.zaprett.ui.screen import android.content.Context.MODE_PRIVATE +import android.content.Intent +import android.net.VpnService +import androidx.activity.result.ActivityResultLauncher import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -33,29 +36,46 @@ import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.TextButton +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import com.cherret.zaprett.R +import com.cherret.zaprett.byedpi.ByeDpiVpnService import com.cherret.zaprett.ui.component.StrategySelectionItem import com.cherret.zaprett.ui.viewmodel.StrategySelectionViewModel import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable -fun StrategySelectionScreen(navController: NavController, viewModel : StrategySelectionViewModel = viewModel()){ +fun StrategySelectionScreen(navController: NavController, vpnLauncher: ActivityResultLauncher, viewModel : StrategySelectionViewModel = viewModel()){ val snackbarHostState = remember { SnackbarHostState() } val strategyStates = viewModel.strategyStates val context = LocalContext.current val prefs = context.getSharedPreferences("settings", MODE_PRIVATE) var showDialog = remember { mutableStateOf(false) } + val requestVpnPermission by viewModel.requestVpnPermission.collectAsState() if (showDialog.value) { InfoAlert { showDialog.value = false } } + LaunchedEffect(requestVpnPermission) { + if (requestVpnPermission) { + val intent = VpnService.prepare(context) + if (intent != null) { + vpnLauncher.launch(intent) + } else { + viewModel.startVpn() + viewModel.clearVpnPermissionRequest() + } + } + } + Scaffold( topBar = { TopAppBar( diff --git a/app/src/main/java/com/cherret/zaprett/ui/viewmodel/IpsetViewModel.kt b/app/src/main/java/com/cherret/zaprett/ui/viewmodel/IpsetViewModel.kt index 618145a..77aea72 100644 --- a/app/src/main/java/com/cherret/zaprett/ui/viewmodel/IpsetViewModel.kt +++ b/app/src/main/java/com/cherret/zaprett/ui/viewmodel/IpsetViewModel.kt @@ -28,7 +28,7 @@ class IpsetViewModel(application: Application): BaseListsViewModel(application) override fun deleteItem(item: String, snackbarHostState: SnackbarHostState, scope: CoroutineScope) { val wasChecked = checked[item] == true - disableList(item, sharedPreferences) + disableIpset(item, sharedPreferences) val success = File(item).delete() if (success) refresh() if (sharedPreferences.getBoolean("use_module", false)) { diff --git a/app/src/main/java/com/cherret/zaprett/ui/viewmodel/StrategySelectionViewModel.kt b/app/src/main/java/com/cherret/zaprett/ui/viewmodel/StrategySelectionViewModel.kt index 3ca16b2..a9197a3 100644 --- a/app/src/main/java/com/cherret/zaprett/ui/viewmodel/StrategySelectionViewModel.kt +++ b/app/src/main/java/com/cherret/zaprett/ui/viewmodel/StrategySelectionViewModel.kt @@ -5,6 +5,7 @@ import android.content.Context.MODE_PRIVATE import android.content.Intent import android.util.Log import androidx.compose.runtime.mutableStateListOf +import androidx.core.content.ContextCompat import androidx.lifecycle.AndroidViewModel import com.cherret.zaprett.R import com.cherret.zaprett.byedpi.ByeDpiVpnService @@ -22,6 +23,8 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeoutOrNull import okhttp3.OkHttpClient @@ -36,6 +39,9 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap .build() val context = application + private val _requestVpnPermission = MutableStateFlow(false) + val requestVpnPermission = _requestVpnPermission.asStateFlow() + val strategyStates = mutableStateListOf() init { @@ -124,9 +130,10 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap }) delay(300L) } - context.startService(Intent(context, ByeDpiVpnService::class.java).apply { + _requestVpnPermission.value = true + /*context.startService(Intent(context, ByeDpiVpnService::class.java).apply { action = "START_VPN" - }) + })*/ val connected = withTimeoutOrNull(10_000L) { while (ByeDpiVpnService.status != ServiceStatus.Connected) { @@ -158,4 +165,10 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap strategyStates.clear() strategyStates.addAll(sorted) } + fun startVpn() { + ContextCompat.startForegroundService(context, Intent(context, ByeDpiVpnService::class.java).apply { action = "START_VPN" }) + } + fun clearVpnPermissionRequest() { + _requestVpnPermission.value = false + } } \ No newline at end of file