9 Commits
2_1 ... 2_2

Author SHA1 Message Date
egor-white
c8c3b6de96 change ver 2025-07-07 12:25:46 +03:00
egor-white
b832be9556 add icon to status card 2025-07-07 12:22:38 +03:00
egor-white
817f3a0e7d move setupProxy checks to HomeViewModel.kt 2025-07-07 11:18:20 +03:00
egor-white
7d25f7e600 fix startVpn crashes 2025-07-06 20:48:35 +03:00
egor-white
8dcb4d1997 fix startVpn crashes 2025-07-06 12:34:39 +03:00
egor-white
ba2cf523bd Merge remote-tracking branch 'origin/main' 2025-07-05 14:35:51 +03:00
egor-white
c268ee8ccd get install unknown apps permission before loading, add module installation check on up startup 2025-07-05 14:30:23 +03:00
egor-white
72905f4180 change navbar icons 2025-07-05 13:19:38 +03:00
egor-white
a7bb250a64 move utils to com.cherret.zaprett.utils 2025-07-05 12:57:44 +03:00
18 changed files with 171 additions and 96 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId = "com.cherret.zaprett" applicationId = "com.cherret.zaprett"
minSdk = 30 minSdk = 30
targetSdk = 35 targetSdk = 35
versionCode = 13 versionCode = 14
versionName = "2.1" versionName = "2.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
ndk { ndk {

View File

@@ -45,7 +45,7 @@
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name=".QSTileService" android:name=".utils.QSTileService"
android:exported="true" android:exported="true"
android:label="@string/qs_name" android:label="@string/qs_name"
android:icon="@drawable/ic_launcher_monochrome" android:icon="@drawable/ic_launcher_monochrome"

View File

@@ -2,6 +2,7 @@ package com.cherret.zaprett
import android.Manifest import android.Manifest
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
@@ -18,9 +19,9 @@ import androidx.activity.viewModels
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Dashboard
import androidx.compose.material.icons.filled.Dns
import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Lan
import androidx.compose.material.icons.filled.MultipleStop
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -30,13 +31,13 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.edit import androidx.core.content.edit
@@ -55,14 +56,15 @@ import com.cherret.zaprett.ui.theme.ZaprettTheme
import com.cherret.zaprett.ui.viewmodel.HomeViewModel import com.cherret.zaprett.ui.viewmodel.HomeViewModel
import com.cherret.zaprett.ui.viewmodel.HostRepoViewModel import com.cherret.zaprett.ui.viewmodel.HostRepoViewModel
import com.cherret.zaprett.ui.viewmodel.StrategyRepoViewModel import com.cherret.zaprett.ui.viewmodel.StrategyRepoViewModel
import com.cherret.zaprett.utils.checkModuleInstallation
import com.google.firebase.Firebase import com.google.firebase.Firebase
import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.analytics import com.google.firebase.analytics.analytics
sealed class Screen(val route: String, @StringRes val nameResId: Int, val icon: ImageVector) { sealed class Screen(val route: String, @StringRes val nameResId: Int, val icon: ImageVector) {
object home : Screen("home", R.string.title_home, Icons.Default.Home) object home : Screen("home", R.string.title_home, Icons.Default.Home)
object hosts : Screen("hosts", R.string.title_hosts, Icons.Default.Dashboard) object hosts : Screen("hosts", R.string.title_hosts, Icons.Default.Lan)
object strategies : Screen("strategies", R.string.title_strategies, Icons.Default.Dns) object strategies : Screen("strategies", R.string.title_strategies, Icons.Default.MultipleStop)
object settings : Screen("settings", R.string.title_settings, Icons.Default.Settings) object settings : Screen("settings", R.string.title_settings, Icons.Default.Settings)
} }
val topLevelRoutes = listOf(Screen.home, Screen.hosts, Screen.strategies, Screen.settings) val topLevelRoutes = listOf(Screen.home, Screen.hosts, Screen.strategies, Screen.settings)
@@ -86,6 +88,17 @@ class MainActivity : ComponentActivity() {
setContent { setContent {
ZaprettTheme { ZaprettTheme {
val sharedPreferences = remember { getSharedPreferences("settings", MODE_PRIVATE) } val sharedPreferences = remember { getSharedPreferences("settings", MODE_PRIVATE) }
LaunchedEffect(Unit) {
checkModuleInstallation { result ->
if (getSharedPreferences("settings", Context.MODE_PRIVATE).getBoolean("use_module", false) && !result) sharedPreferences.edit {
putBoolean(
"use_module",
false
)
}
}
}
var showStoragePermissionDialog by remember { mutableStateOf(!Environment.isExternalStorageManager()) } var showStoragePermissionDialog by remember { mutableStateOf(!Environment.isExternalStorageManager()) }
var showNotificationPermissionDialog by remember { var showNotificationPermissionDialog by remember {
mutableStateOf( mutableStateOf(
@@ -133,6 +146,7 @@ class MainActivity : ComponentActivity() {
} }
} }
@Composable @Composable
fun BottomBar() { fun BottomBar() {
val navController = rememberNavController() val navController = rememberNavController()

View File

@@ -14,7 +14,7 @@ import android.widget.Toast
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.cherret.zaprett.MainActivity import com.cherret.zaprett.MainActivity
import com.cherret.zaprett.R import com.cherret.zaprett.R
import com.cherret.zaprett.getActiveStrategy import com.cherret.zaprett.utils.getActiveStrategy
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -40,6 +40,7 @@ class ByeDpiVpnService : VpnService() {
super.onStartCommand(intent, flags, startId) super.onStartCommand(intent, flags, startId)
return when (intent?.action) { return when (intent?.action) {
"START_VPN" -> { "START_VPN" -> {
startForeground(NOTIFICATION_ID, createNotification())
setupProxy() setupProxy()
START_STICKY START_STICKY
} }
@@ -98,23 +99,14 @@ class ByeDpiVpnService : VpnService() {
} }
private fun setupProxy() { private fun setupProxy() {
if (getActiveStrategy(sharedPreferences).isNotEmpty()) { try {
startForeground(NOTIFICATION_ID, createNotification()) startSocksProxy()
try { startByeDpi()
startSocksProxy() status = ServiceStatus.Connected
startByeDpi() } catch (e: Exception) {
status = ServiceStatus.Connected Log.e("proxy", "Failed to start")
} catch (e: Exception) { status = ServiceStatus.Failed
Log.e("proxy", "Failed to start") stopSelf()
status = ServiceStatus.Failed
}
}
else {
Toast.makeText(
this@ByeDpiVpnService,
getString(R.string.toast_no_strategy_selected),
Toast.LENGTH_SHORT
).show()
} }
} }

View File

@@ -10,9 +10,11 @@ import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -49,6 +51,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.graphics.vector.rememberVectorPainter
@@ -75,6 +78,7 @@ fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResu
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val cardText = viewModel.cardText val cardText = viewModel.cardText
val cardIcon = viewModel.cardIcon;
val changeLog = viewModel.changeLog val changeLog = viewModel.changeLog
val newVersion = viewModel.newVersion val newVersion = viewModel.newVersion
val updateAvailable = viewModel.updateAvailable val updateAvailable = viewModel.updateAvailable
@@ -119,7 +123,7 @@ fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResu
Column(modifier = Modifier Column(modifier = Modifier
.padding(paddingValues) .padding(paddingValues)
.verticalScroll(rememberScrollState())) { .verticalScroll(rememberScrollState())) {
ServiceStatusCard(viewModel, cardText, snackbarHostState, scope) ServiceStatusCard(viewModel, cardText, cardIcon, snackbarHostState, scope)
UpdateCard(updateAvailable) { viewModel.showUpdateDialog() } UpdateCard(updateAvailable) { viewModel.showUpdateDialog() }
if (showUpdateDialog) { if (showUpdateDialog) {
UpdateDialog(viewModel, changeLog.value.orEmpty(), newVersion) { viewModel.dismissUpdateDialog() } UpdateDialog(viewModel, changeLog.value.orEmpty(), newVersion) { viewModel.dismissUpdateDialog() }
@@ -137,25 +141,40 @@ fun HomeScreen(viewModel: HomeViewModel = viewModel(), vpnLauncher: ActivityResu
} }
@Composable @Composable
private fun ServiceStatusCard(viewModel: HomeViewModel, cardText: MutableState<Int>, snackbarHostState: SnackbarHostState, scope: CoroutineScope) { private fun ServiceStatusCard(viewModel: HomeViewModel, cardText: MutableState<Int>, cardIcon : MutableState<ImageVector>, snackbarHostState: SnackbarHostState, scope: CoroutineScope) {
ElevatedCard( ElevatedCard(
elevation = CardDefaults.cardElevation(6.dp), elevation = CardDefaults.cardElevation(6.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary), colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 10.dp, top = 25.dp, end = 10.dp) .padding(start = 10.dp, top = 25.dp, end = 10.dp)
.width(240.dp)
.height(150.dp), .height(150.dp),
onClick = { viewModel.onCardClick() } onClick = { viewModel.onCardClick() }
) { ) {
Text( Row (
text = stringResource(cardText.value),
fontFamily = FontFamily(Font(R.font.unbounded, FontWeight.Normal)),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxSize()
.padding(16.dp), .padding(16.dp),
textAlign = TextAlign.Center verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) )
{
Icon(
painter = rememberVectorPainter(cardIcon.value),
modifier = Modifier
.width(60.dp)
.height(60.dp),
contentDescription = "icon"
)
Text(
text = stringResource(cardText.value),
fontFamily = FontFamily(Font(R.font.unbounded, FontWeight.Normal)),
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
textAlign = TextAlign.Center
)
}
} }
} }

View File

@@ -25,10 +25,11 @@ import com.cherret.zaprett.BuildConfig
import com.cherret.zaprett.byedpi.ByeDpiVpnService import com.cherret.zaprett.byedpi.ByeDpiVpnService
import com.cherret.zaprett.R import com.cherret.zaprett.R
import com.cherret.zaprett.byedpi.ServiceStatus import com.cherret.zaprett.byedpi.ServiceStatus
import com.cherret.zaprett.checkModuleInstallation import com.cherret.zaprett.utils.checkModuleInstallation
import com.cherret.zaprett.checkRoot import com.cherret.zaprett.utils.checkRoot
import com.cherret.zaprett.getStartOnBoot import com.cherret.zaprett.utils.getStartOnBoot
import com.cherret.zaprett.setStartOnBoot import com.cherret.zaprett.utils.setStartOnBoot
import com.cherret.zaprett.utils.stopService
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -66,7 +67,10 @@ fun SettingsScreen() {
openNoRootDialog = openNoRootDialog, openNoRootDialog = openNoRootDialog,
openNoModuleDialog = openNoModuleDialog openNoModuleDialog = openNoModuleDialog
) { success -> ) { success ->
if (success) useModule.value = isChecked if (success) {
useModule.value = isChecked
if (!isChecked) stopService { }
}
} }
} }
), ),

View File

@@ -13,8 +13,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import com.cherret.zaprett.R import com.cherret.zaprett.R
import com.cherret.zaprett.getZaprettPath import com.cherret.zaprett.utils.getZaprettPath
import com.cherret.zaprett.restartService import com.cherret.zaprett.utils.restartService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File

View File

@@ -9,13 +9,13 @@ import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.cherret.zaprett.RepoItemInfo import com.cherret.zaprett.utils.RepoItemInfo
import com.cherret.zaprett.R import com.cherret.zaprett.R
import com.cherret.zaprett.download import com.cherret.zaprett.utils.download
import com.cherret.zaprett.getFileSha256 import com.cherret.zaprett.utils.getFileSha256
import com.cherret.zaprett.getZaprettPath import com.cherret.zaprett.utils.getZaprettPath
import com.cherret.zaprett.registerDownloadListenerHost import com.cherret.zaprett.utils.registerDownloadListenerHost
import com.cherret.zaprett.restartService import com.cherret.zaprett.utils.restartService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File

View File

@@ -3,6 +3,12 @@ package com.cherret.zaprett.ui.viewmodel
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.widget.Toast
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Help
import androidx.compose.material.icons.filled.Cancel
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -11,17 +17,18 @@ import androidx.lifecycle.AndroidViewModel
import com.cherret.zaprett.byedpi.ByeDpiVpnService import com.cherret.zaprett.byedpi.ByeDpiVpnService
import com.cherret.zaprett.R import com.cherret.zaprett.R
import com.cherret.zaprett.byedpi.ServiceStatus import com.cherret.zaprett.byedpi.ServiceStatus
import com.cherret.zaprett.download import com.cherret.zaprett.utils.download
import com.cherret.zaprett.getBinVersion import com.cherret.zaprett.utils.getActiveStrategy
import com.cherret.zaprett.getChangelog import com.cherret.zaprett.utils.getBinVersion
import com.cherret.zaprett.getModuleVersion import com.cherret.zaprett.utils.getChangelog
import com.cherret.zaprett.getStatus import com.cherret.zaprett.utils.getModuleVersion
import com.cherret.zaprett.getUpdate import com.cherret.zaprett.utils.getStatus
import com.cherret.zaprett.installApk import com.cherret.zaprett.utils.getUpdate
import com.cherret.zaprett.registerDownloadListener import com.cherret.zaprett.utils.installApk
import com.cherret.zaprett.restartService import com.cherret.zaprett.utils.registerDownloadListener
import com.cherret.zaprett.startService import com.cherret.zaprett.utils.restartService
import com.cherret.zaprett.stopService import com.cherret.zaprett.utils.startService
import com.cherret.zaprett.utils.stopService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@@ -34,6 +41,8 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
val requestVpnPermission = _requestVpnPermission.asStateFlow() val requestVpnPermission = _requestVpnPermission.asStateFlow()
var cardText = mutableIntStateOf(R.string.status_not_availible) // MVP temporarily(maybe) var cardText = mutableIntStateOf(R.string.status_not_availible) // MVP temporarily(maybe)
private set private set
var cardIcon = mutableStateOf(Icons.AutoMirrored.Filled.Help)
private set
var moduleVer = mutableStateOf(context.getString(R.string.unknown_text)) var moduleVer = mutableStateOf(context.getString(R.string.unknown_text))
private set private set
@@ -77,21 +86,49 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
fun checkServiceStatus() { fun checkServiceStatus() {
if (prefs.getBoolean("use_module", false) && prefs.getBoolean("update_on_boot", false)) { if (prefs.getBoolean("use_module", false) && prefs.getBoolean("update_on_boot", false)) {
getStatus { isEnabled -> getStatus { isEnabled ->
cardText.intValue = if (isEnabled) R.string.status_enabled else R.string.status_disabled if (isEnabled){
cardText.value = R.string.status_enabled
cardIcon.value = Icons.Filled.CheckCircle
}
else {
cardText.value = R.string.status_disabled
cardIcon.value = Icons.Filled.Cancel
}
} }
} }
else { else {
cardText.value = if (ByeDpiVpnService.status == ServiceStatus.Connected) R.string.status_enabled else R.string.status_disabled if (ByeDpiVpnService.status == ServiceStatus.Connected){
cardText.value = R.string.status_enabled
cardIcon.value = Icons.Filled.CheckCircle
}
else {
cardText.value = R.string.status_disabled
cardIcon.value = Icons.Filled.Cancel
}
} }
} }
fun onCardClick() { fun onCardClick() {
if (prefs.getBoolean("use_module", false)) { if (prefs.getBoolean("use_module", false)) {
getStatus { isEnabled -> getStatus { isEnabled ->
cardText.value = if (isEnabled) R.string.status_enabled else R.string.status_disabled if (isEnabled){
cardText.value = R.string.status_enabled
cardIcon.value = Icons.Filled.CheckCircle
}
else {
cardText.value = R.string.status_disabled
cardIcon.value = Icons.Filled.Cancel
}
} }
} else { } else {
cardText.value = if (ByeDpiVpnService.status == ServiceStatus.Connected) R.string.status_enabled else R.string.status_disabled if (ByeDpiVpnService.status == ServiceStatus.Connected){
cardText.value = R.string.status_enabled
cardIcon.value = Icons.Filled.CheckCircle
}
else {
cardText.value = R.string.status_disabled
cardIcon.value = Icons.Filled.Cancel
}
} }
} }
@@ -113,10 +150,19 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
} }
} else { } else {
if (ByeDpiVpnService.status == ServiceStatus.Disconnected || ByeDpiVpnService.status == ServiceStatus.Failed) { if (ByeDpiVpnService.status == ServiceStatus.Disconnected || ByeDpiVpnService.status == ServiceStatus.Failed) {
scope.launch { if (getActiveStrategy(prefs).isNotEmpty()) {
snackbarHostState.showSnackbar(context.getString(R.string.snack_starting_service)) scope.launch {
snackbarHostState.showSnackbar(context.getString(R.string.snack_starting_service))
}
_requestVpnPermission.value = true
}
else {
Toast.makeText(
context,
context.getString(R.string.toast_no_strategy_selected),
Toast.LENGTH_SHORT
).show()
} }
_requestVpnPermission.value = true
} }
else { else {
scope.launch { scope.launch {

View File

@@ -1,16 +1,9 @@
package com.cherret.zaprett.ui.viewmodel package com.cherret.zaprett.ui.viewmodel
import android.app.Application import android.app.Application
import androidx.lifecycle.viewModelScope import com.cherret.zaprett.utils.RepoItemInfo
import com.cherret.zaprett.RepoItemInfo import com.cherret.zaprett.utils.getAllLists
import com.cherret.zaprett.download import com.cherret.zaprett.utils.getHostList
import com.cherret.zaprett.getAllLists
import com.cherret.zaprett.getHostList
import com.cherret.zaprett.getZaprettPath
import com.cherret.zaprett.registerDownloadListenerHost
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class HostRepoViewModel(application: Application): BaseRepoViewModel(application) { class HostRepoViewModel(application: Application): BaseRepoViewModel(application) {
override fun getInstalledLists(): Array<String> = getAllLists() override fun getInstalledLists(): Array<String> = getAllLists()

View File

@@ -3,11 +3,11 @@ package com.cherret.zaprett.ui.viewmodel
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import com.cherret.zaprett.disableList import com.cherret.zaprett.utils.disableList
import com.cherret.zaprett.enableList import com.cherret.zaprett.utils.enableList
import com.cherret.zaprett.getActiveLists import com.cherret.zaprett.utils.getActiveLists
import com.cherret.zaprett.getAllLists import com.cherret.zaprett.utils.getAllLists
import com.cherret.zaprett.getStatus import com.cherret.zaprett.utils.getStatus
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import java.io.File import java.io.File

View File

@@ -1,10 +1,10 @@
package com.cherret.zaprett.ui.viewmodel package com.cherret.zaprett.ui.viewmodel
import android.app.Application import android.app.Application
import com.cherret.zaprett.RepoItemInfo import com.cherret.zaprett.utils.RepoItemInfo
import com.cherret.zaprett.getAllByeDPIStrategies import com.cherret.zaprett.utils.getAllByeDPIStrategies
import com.cherret.zaprett.getAllNfqwsStrategies import com.cherret.zaprett.utils.getAllNfqwsStrategies
import com.cherret.zaprett.getStrategiesList import com.cherret.zaprett.utils.getStrategiesList
class StrategyRepoViewModel(application: Application): BaseRepoViewModel(application) { class StrategyRepoViewModel(application: Application): BaseRepoViewModel(application) {
override fun getInstalledLists(): Array<String> = override fun getInstalledLists(): Array<String> =

View File

@@ -6,13 +6,13 @@ import android.content.SharedPreferences
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import com.cherret.zaprett.byedpi.ByeDpiVpnService import com.cherret.zaprett.byedpi.ByeDpiVpnService
import com.cherret.zaprett.byedpi.ServiceStatus import com.cherret.zaprett.byedpi.ServiceStatus
import com.cherret.zaprett.disableStrategy import com.cherret.zaprett.utils.disableStrategy
import com.cherret.zaprett.enableStrategy import com.cherret.zaprett.utils.enableStrategy
import com.cherret.zaprett.getActiveByeDPIStrategies import com.cherret.zaprett.utils.getActiveByeDPIStrategies
import com.cherret.zaprett.getActiveNfqwsStrategies import com.cherret.zaprett.utils.getActiveNfqwsStrategies
import com.cherret.zaprett.getAllByeDPIStrategies import com.cherret.zaprett.utils.getAllByeDPIStrategies
import com.cherret.zaprett.getAllNfqwsStrategies import com.cherret.zaprett.utils.getAllNfqwsStrategies
import com.cherret.zaprett.getStatus import com.cherret.zaprett.utils.getStatus
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import java.io.File import java.io.File

View File

@@ -1,4 +1,4 @@
package com.cherret.zaprett package com.cherret.zaprett.utils
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Environment import android.os.Environment

View File

@@ -1,7 +1,8 @@
package com.cherret.zaprett package com.cherret.zaprett.utils
import android.service.quicksettings.Tile import android.service.quicksettings.Tile
import android.service.quicksettings.TileService import android.service.quicksettings.TileService
import com.cherret.zaprett.R
class QSTileService: TileService() { class QSTileService: TileService() {
override fun onTileAdded() { override fun onTileAdded() {

View File

@@ -1,4 +1,4 @@
package com.cherret.zaprett package com.cherret.zaprett.utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.DownloadManager import android.app.DownloadManager

View File

@@ -1,4 +1,4 @@
package com.cherret.zaprett package com.cherret.zaprett.utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.DownloadManager import android.app.DownloadManager
@@ -13,6 +13,7 @@ import android.provider.Settings
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.net.toUri import androidx.core.net.toUri
import com.cherret.zaprett.BuildConfig
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.Call import okhttp3.Call
@@ -101,6 +102,11 @@ fun installApk(context: Context, uri: Uri) {
} }
fun registerDownloadListener(context: Context, downloadId: Long, onDownloaded: (Uri) -> Unit) {// AI Generated fun registerDownloadListener(context: Context, downloadId: Long, onDownloaded: (Uri) -> Unit) {// AI Generated
if (!context.packageManager.canRequestPackageInstalls()){
val packageUri = Uri.fromParts("package", context.packageName, null)
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageUri)
context.startActivity(intent)
}
val receiver = object : BroadcastReceiver() { val receiver = object : BroadcastReceiver() {
@SuppressLint("Range") @SuppressLint("Range")
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {