4 Commits

Author SHA1 Message Date
white
69f395275e change build.gradle version 2025-10-16 16:18:03 +03:00
CherretGit
39dc2baad3 Merge remote-tracking branch 'origin/main' 2025-10-16 19:46:05 +07:00
CherretGit
ad5c556241 fix ipsets loading 2025-10-16 19:45:57 +07:00
white
48e7497e79 add no hosts dialog, optimize imports 2025-10-16 15:45:19 +03:00
7 changed files with 42 additions and 19 deletions

View File

@@ -16,8 +16,8 @@ android {
applicationId = "com.cherret.zaprett"
minSdk = 29
targetSdk = 35
versionCode = 21
versionName = "2.9"
versionCode = 22
versionName = "2.10"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

View File

@@ -37,6 +37,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.TextButton
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -45,7 +46,6 @@ 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
@@ -122,6 +122,7 @@ fun StrategySelectionScreen(navController: NavController, vpnLauncher: ActivityR
horizontalArrangement = Arrangement.Center
)
{
NoHostsCard(viewModel.noHostsCard)
FilledTonalButton(
onClick = {
viewModel.viewModelScope.launch {
@@ -175,3 +176,21 @@ fun InfoAlert(onDismiss: () -> Unit) {
)
}
@Composable
private fun NoHostsCard(noHostsCard: MutableState<Boolean>) {
if (noHostsCard.value) {
AlertDialog(
title = { Text(text = stringResource(R.string.selection_no_hosts_title)) },
text = { Text(text = stringResource(R.string.selection_no_hosts_message)) },
onDismissRequest = {
noHostsCard.value = false
},
confirmButton = {
TextButton(onClick = { noHostsCard.value = false }) {
Text(stringResource(R.string.btn_continue))
}
}
)
}
}

View File

@@ -9,6 +9,7 @@ import com.cherret.zaprett.utils.enableIpset
import com.cherret.zaprett.utils.enableList
import com.cherret.zaprett.utils.getActiveExcludeIpsets
import com.cherret.zaprett.utils.getActiveExcludeLists
import com.cherret.zaprett.utils.getActiveIpsets
import com.cherret.zaprett.utils.getAllExcludeIpsets
import com.cherret.zaprett.utils.getAllIpsets
import com.cherret.zaprett.utils.getHostListMode
@@ -23,8 +24,8 @@ class IpsetViewModel(application: Application): BaseListsViewModel(application)
if (getHostListMode(sharedPreferences) == "whitelist") getAllIpsets()
else getAllExcludeIpsets()
override fun loadActiveItems(): Array<String> =
if (getHostListMode(sharedPreferences) == "whitelist") getActiveExcludeIpsets(sharedPreferences)
else getActiveExcludeLists(sharedPreferences)
if (getHostListMode(sharedPreferences) == "whitelist") getActiveIpsets(sharedPreferences)
else getActiveExcludeIpsets(sharedPreferences)
override fun deleteItem(item: String, snackbarHostState: SnackbarHostState, scope: CoroutineScope) {
val wasChecked = checked[item] == true
@@ -61,5 +62,4 @@ class IpsetViewModel(application: Application): BaseListsViewModel(application)
setHostListMode(sharedPreferences, type)
refresh()
}
}

View File

@@ -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.compose.runtime.mutableStateOf
import androidx.core.content.ContextCompat
import androidx.lifecycle.AndroidViewModel
import com.cherret.zaprett.R
@@ -14,6 +15,7 @@ import com.cherret.zaprett.data.StrategyCheckResult
import com.cherret.zaprett.utils.disableStrategy
import com.cherret.zaprett.utils.enableStrategy
import com.cherret.zaprett.utils.getActiveLists
import com.cherret.zaprett.utils.getActiveStrategy
import com.cherret.zaprett.utils.getAllStrategies
import com.cherret.zaprett.utils.getStatus
import com.cherret.zaprett.utils.startService
@@ -38,14 +40,15 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
.callTimeout(prefs.getLong("probe_timeout", 1000L), TimeUnit.MILLISECONDS)
.build()
val context = application
private val _requestVpnPermission = MutableStateFlow(false)
val requestVpnPermission = _requestVpnPermission.asStateFlow()
val strategyStates = mutableStateListOf<StrategyCheckResult>()
var noHostsCard = mutableStateOf(false)
private set
init {
loadStrategies()
checkHosts()
}
fun loadStrategies() {
@@ -64,7 +67,6 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
val request = Request.Builder()
.url("https://${domain}")
.build()
try {
client.newCall(request).execute().use { response ->
response.isSuccessful || (response.code in 300..399)
@@ -100,19 +102,15 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
}
suspend fun performTest() {
val targets = readActiveListsLines()
for (index in strategyStates.indices) {
val current = strategyStates[index]
strategyStates[index] = current.copy(status = R.string.strategy_status_testing)
enableStrategy(current.path, prefs)
if (prefs.getBoolean("use_module", false)) {
getStatus { if (it) stopService {} }
startService {}
try {
val progress = countReachable(targets)
val old = strategyStates[index]
strategyStates[index] = old.copy(
progress = progress,
@@ -134,14 +132,12 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
/*context.startService(Intent(context, ByeDpiVpnService::class.java).apply {
action = "START_VPN"
})*/
val connected = withTimeoutOrNull(10_000L) {
while (ByeDpiVpnService.status != ServiceStatus.Connected) {
delay(100L)
}
true
} ?: false
if (connected) delay(150L)
try {
val progress = countReachable(targets)
@@ -160,11 +156,15 @@ class StrategySelectionViewModel(application: Application) : AndroidViewModel(ap
}
}
}
val sorted = strategyStates.sortedByDescending { it.progress }
strategyStates.clear()
strategyStates.addAll(sorted)
}
fun checkHosts() {
if (getActiveLists(prefs).isEmpty()) noHostsCard.value = true
Log.d("getActiveLists.isEmpty", getActiveLists(prefs).isEmpty().toString())
}
fun startVpn() {
ContextCompat.startForegroundService(context, Intent(context, ByeDpiVpnService::class.java).apply { action = "START_VPN" })
}

View File

@@ -192,7 +192,7 @@ fun getActiveIpsets(sharedPreferences: SharedPreferences): Array<String> {
}
return emptyArray()
}
else return emptyArray()
else return sharedPreferences.getStringSet("ipsets", emptySet())?.toTypedArray() ?: emptyArray()
}
fun getActiveExcludeLists(sharedPreferences: SharedPreferences): Array<String> {
if (sharedPreferences.getBoolean("use_module", false)) {
@@ -236,7 +236,7 @@ fun getActiveExcludeIpsets(sharedPreferences: SharedPreferences): Array<String>
}
return emptyArray()
}
else return emptyArray()
else return sharedPreferences.getStringSet("exclude_ipsets", emptySet())?.toTypedArray() ?: emptyArray()
}
fun getActiveNfqwsStrategy(): Array<String> {
@@ -363,7 +363,7 @@ fun enableIpset(path: String, sharedPreferences: SharedPreferences) {
currentSet.add(path)
sharedPreferences.edit { putStringSet(
if (getHostListMode(sharedPreferences) == "whitelist") "ipsets"
else "exclude_ipsetss", currentSet) }
else "exclude_ipsets", currentSet) }
}
}
}

View File

@@ -114,4 +114,6 @@
<string name="hint_enter_probe_timeout">Введите таймаут пробы</string>
<string name="strategy_selection_info_title">Информация</string>
<string name="strategy_selection_info_msg">"В этом разделе настроек приложения представлен перебор стратегий\n Подбор проходит среди скачанных стратегий, поэтому заранее скачайте из репозитория или добавьте из файловой системы интересующие вас стратегии для сравнения. \n Перед началом так же выберете один или несколько листов доменов на вкладке \"Листы\", затем нажмите на \"Начать подбор\". Не используйте для перебора списки с большим количеством доменов."</string>
<string name="selection_no_hosts_title">Нет активных листов</string>
<string name="selection_no_hosts_message">Не обнаружено активных списков хостов, включите один или несколько, иначе подбор не сработает</string>
</resources>

View File

@@ -119,4 +119,6 @@
<string name="hint_enter_probe_timeout">Enter probe timeout</string>
<string name="strategy_selection_info_title">Tip</string>
<string name="strategy_selection_info_msg">This section of the application settings allows you to iterate through strategies.\n The selection is based on downloaded strategies, so download the strategies you\'re interested in from the repository or add them from the file system for comparison.\n Before starting, select one or more domain lists in the \"Lists\" tab, then click \"Start selection\". Avoid using lists with a large number of domains.</string>
<string name="selection_no_hosts_title">No active hosts</string>
<string name="selection_no_hosts_message">No active host lists found, please enable one or more, otherwise the selection will not work</string>
</resources>