diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 41a08b3..a222fed 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,7 +13,7 @@ android { minSdk = 31 targetSdk = 34 versionCode = 1 - versionName = "3.0.1" + versionName = "3.0.3" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/ru/n00byara/notificationcode/components/terminal/Terminal.kt b/app/src/main/java/ru/n00byara/notificationcode/components/terminal/Terminal.kt index aff99ba..367b0d7 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/components/terminal/Terminal.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/components/terminal/Terminal.kt @@ -8,13 +8,7 @@ object Terminal { this.runCommand("killall com.android.systemui") } - fun restartModule() { - this.runCommand( - "killall ru.n00byara.notificationcode && am start -n ru.n00byara.notificationcode/.ui.activities.SettingsActivity" - ) - } - - private fun runCommand(cmd: String) { + private fun runCommand(cmd: String): String { val process = Runtime.getRuntime().exec(arrayOf("su", "-c", cmd)) val reader = BufferedReader( @@ -31,5 +25,6 @@ object Terminal { reader.close() process.waitFor() + return output.toString() } } \ No newline at end of file diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/activities/GlobalSettingsActivity.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/GlobalSettingsActivity.kt index 2d6a93a..e1bd9ff 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/activities/GlobalSettingsActivity.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/GlobalSettingsActivity.kt @@ -21,6 +21,8 @@ class GlobalSettingsActivity : ComponentActivity() { val globalSettingsScreenViewModel = ViewModelProvider(this).get(GlobalSettingsScreenViewModel::class.java) val globalSettingsActivityViewModel = ViewModelProvider(this, GlobalSettingsActivityViewModelFactory(this::finish)).get(GlobalSettingsActivityViewModel::class.java) + lifecycle.addObserver(globalSettingsScreenViewModel) + setContent { NotificationCodeTheme { val topBarModel by globalSettingsActivityViewModel.topBarUiState.collectAsState() diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/activities/SettingsActivity.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/SettingsActivity.kt index c45053e..44bc880 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/activities/SettingsActivity.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/SettingsActivity.kt @@ -15,9 +15,7 @@ import androidx.navigation.compose.rememberNavController import ru.n00byara.notificationcode.ui.components.bottomnavigationbar.BottomNavBar import ru.n00byara.notificationcode.ui.components.bottomnavigationbar.BottomNavBarModel import ru.n00byara.notificationcode.ui.components.bottomnavigationbar.Screen -import ru.n00byara.notificationcode.ui.components.permissionalertdialog.PermissionAlertDialog import ru.n00byara.notificationcode.ui.components.topbar.TopBar -import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialog import ru.n00byara.notificationcode.ui.screens.ApplicationsScreen import ru.n00byara.notificationcode.ui.screens.SettingsScreen import ru.n00byara.notificationcode.ui.theme.NotificationCodeTheme @@ -38,21 +36,10 @@ class SettingsActivity : ComponentActivity() { val settingsScreenViewModel = ViewModelProvider(this).get(SettingsScreenViewModel::class.java) val applicationsScreenViewModel = ViewModelProvider(this).get(ApplicationsScreenViewModel::class.java) + lifecycle.addObserver(settingsScreenViewModel) + setContent { NotificationCodeTheme { - val openRootDialogState = settingsActivityViewModel.openRootDialogState - if (openRootDialogState.value) { - val useCaseAlertDialogModel by settingsActivityViewModel.useCaseAlertDialogUiState.collectAsState() - UseCaseAlertDialog(useCaseAlertDialogModel) - } - - val openNonRootDialogState = settingsActivityViewModel.openNonRootDialogState - if (openNonRootDialogState.value) { - val permissionAlertDialogModel by settingsActivityViewModel.permissionAlertDialogState.collectAsState() - PermissionAlertDialog(permissionAlertDialogModel) - } - - val topBarModel by settingsActivityViewModel.topBarUiState.collectAsState() val navController = rememberNavController() diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt index 039a784..75c3246 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt @@ -1,6 +1,5 @@ package ru.n00byara.notificationcode.ui.components.bottomnavigationbar -import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.Icon import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem @@ -14,16 +13,9 @@ import androidx.compose.ui.res.stringResource import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.compose.currentBackStackEntryAsState -import com.google.accompanist.systemuicontroller.rememberSystemUiController @Composable fun BottomNavBar(bottomNavBarModel: BottomNavBarModel) { - val systemUiController = rememberSystemUiController() - systemUiController.setNavigationBarColor( - Color.Transparent, - darkIcons = !isSystemInDarkTheme() - ) - val items = listOf(Screen.Settings, Screen.ApplicationsList) val selectedState by remember { mutableStateOf(bottomNavBarModel.selected) diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissioncard/PermissionCard.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissioncard/PermissionCard.kt new file mode 100644 index 0000000..c9b4abb --- /dev/null +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissioncard/PermissionCard.kt @@ -0,0 +1,40 @@ +package ru.n00byara.notificationcode.ui.components.permissioncard + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import ru.n00byara.notificationcode.R + +@Composable +fun PermissionCard(permissionCardModel: PermissionCardModel) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(start = 15.dp, end = 15.dp, top = 7.dp, bottom = 7.dp) + .clip(RoundedCornerShape(19.dp)) + .clickable { + permissionCardModel.openSettings() + } + ) { + Row( + modifier = Modifier.padding(10.dp), + horizontalArrangement = Arrangement.Center + ) { + Text( + text = stringResource(R.string.access_notification_listener), + fontSize = 15.sp + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissioncard/PermissionCardModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissioncard/PermissionCardModel.kt new file mode 100644 index 0000000..16287ca --- /dev/null +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissioncard/PermissionCardModel.kt @@ -0,0 +1,5 @@ +package ru.n00byara.notificationcode.ui.components.permissioncard + +data class PermissionCardModel( + val openSettings: () -> Unit +) \ No newline at end of file diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt index b552e0b..854de2e 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt @@ -26,7 +26,12 @@ fun Switcher(switcherModel: SwitcherModel) { mutableStateOf(switcherModel.state) } - if (!switcherModel.moduleActive && switcherModel.isRoot) chechedState.value = false + if ( + (!switcherModel.moduleActive.value && switcherModel.useCase.value == 0) || + (!switcherModel.premissionAccess.value && switcherModel.useCase.value == 1) + ) { + chechedState.value = false + } Card( Modifier @@ -50,7 +55,8 @@ fun Switcher(switcherModel: SwitcherModel) { chechedState.value, { if ( - (switcherModel.moduleActive && switcherModel.isRoot) || (!switcherModel.moduleActive && !switcherModel.isRoot) + (switcherModel.moduleActive.value && switcherModel.useCase.value == 0) || + (switcherModel.premissionAccess.value && switcherModel.useCase.value == 1) ) { chechedState.value = it switcherModel.setState(switcherModel.prefName, it) diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt index 5caaec7..ce30f23 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt @@ -1,10 +1,13 @@ package ru.n00byara.notificationcode.ui.components.switcher +import androidx.compose.runtime.MutableState + data class SwitcherModel( val title: Int, val prefName: String, val state: Boolean, val setState: (String, Boolean) -> Unit, - val moduleActive: Boolean, - val isRoot: Boolean + val useCase: MutableState, + val moduleActive: MutableState, + val premissionAccess: MutableState ) diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt index 5174143..5363c3c 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt @@ -13,8 +13,10 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController @OptIn(ExperimentalMaterial3Api::class) @Composable fun TopBar(topBarModel: TopBarModel) { + + // Edge to Edge val systemUiController = rememberSystemUiController() - systemUiController.setStatusBarColor( + systemUiController.setSystemBarsColor( Color.Transparent, darkIcons = !isSystemInDarkTheme() ) diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialog.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialog.kt index b0783db..48f5e68 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialog.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialog.kt @@ -32,7 +32,10 @@ fun UseCaseAlertDialog(useCaseAlertDialogModel: UseCaseAlertDialogModel) { useCaseAlertDialogModel.openDialogState.value = false }, ) { - val cases = listOf(R.string.alert_dialog_use_case_root, R.string.alert_dialog_use_case_non_root) + val cases = listOf( + "${stringResource(R.string.alert_dialog_use_case_root)} ${stringResource(R.string.alert_dialog_use_case_recommended)}", + stringResource(R.string.alert_dialog_use_case_non_root) + ) Card( modifier = Modifier @@ -70,9 +73,9 @@ fun UseCaseAlertDialog(useCaseAlertDialogModel: UseCaseAlertDialogModel) { @Composable fun UseCaseCheckBox( - case: Int, - selectedOption: Int, - onOptionSelected: (Int) -> Unit, + case: String, + selectedOption: String, + onOptionSelected: (String) -> Unit, setSelectItem: ((Int) -> Unit)?, index: Int ) { @@ -88,7 +91,7 @@ fun UseCaseCheckBox( } ) Text( - text = stringResource(case) + text = case ) } } \ No newline at end of file diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/GlobalSettingsScreen.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/GlobalSettingsScreen.kt index bad23a2..a070c33 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/GlobalSettingsScreen.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/GlobalSettingsScreen.kt @@ -1,5 +1,6 @@ package ru.n00byara.notificationcode.ui.screens +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -23,6 +24,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import ru.n00byara.notificationcode.R +import ru.n00byara.notificationcode.ui.components.permissioncard.PermissionCard import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialog import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialogModel import ru.n00byara.notificationcode.ui.viewmodels.GlobalSettingsScreenViewModel @@ -38,10 +40,19 @@ fun GlobalSettingsScreen( LazyColumn( Modifier.padding(paddingValues) ) { - if (globalSettingsScreenViewModel.isRoot) { - item { - val useCaseDialogModel by globalSettingsScreenViewModel.useCaseDialogState.collectAsState() - UseCaseDialog(useCaseDialogModel) + item { + val useCaseDialogModel by globalSettingsScreenViewModel.useCaseDialogState.collectAsState() + UseCaseDialog(useCaseDialogModel) + } + + val permissionCardVisibilityUiState = globalSettingsScreenViewModel.permissionCardVisibilityUiState + + item { + AnimatedVisibility( + visible = permissionCardVisibilityUiState.value + ) { + val permissionCardModel by globalSettingsScreenViewModel.permissionCardModelUiStateFlow.collectAsState() + PermissionCard(permissionCardModel) } } } @@ -77,7 +88,8 @@ fun UseCaseDialog( .wrapContentHeight() .clip(RoundedCornerShape(19.dp)) .clickable { - useCaseAlertDialogModel.openDialogState.value = !useCaseAlertDialogModel.openDialogState.value + useCaseAlertDialogModel.openDialogState.value = + !useCaseAlertDialogModel.openDialogState.value } ) { diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt index e33849c..a06a920 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt @@ -1,5 +1,6 @@ package ru.n00byara.notificationcode.ui.screens +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -17,6 +18,8 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource @@ -26,8 +29,11 @@ import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import ru.n00byara.notificationcode.Constants import ru.n00byara.notificationcode.R +import ru.n00byara.notificationcode.ui.components.permissionalertdialog.PermissionAlertDialog +import ru.n00byara.notificationcode.ui.components.permissioncard.PermissionCard import ru.n00byara.notificationcode.ui.components.switcher.Switcher import ru.n00byara.notificationcode.ui.components.switcher.SwitcherModel +import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialog import ru.n00byara.notificationcode.ui.viewmodels.SettingsScreenViewModel import kotlin.reflect.KFunction1 @@ -38,10 +44,24 @@ fun SettingsScreen( ) { setTopBarTitle(stringResource(R.string.screen_settings_title)) + val openRootDialogState = settingsScreenViewModel.openRootDialogState + if (openRootDialogState.value) { + val useCaseAlertDialogModel by settingsScreenViewModel.useCaseAlertDialogUiState.collectAsState() + UseCaseAlertDialog(useCaseAlertDialogModel) + } + + val openNonRootDialogState = settingsScreenViewModel.openNonRootDialogState + if (openNonRootDialogState.value) { + val permissionAlertDialogModel by settingsScreenViewModel.permissionAlertDialogState.collectAsState() + PermissionAlertDialog(permissionAlertDialogModel) + } + LazyColumn { - if (settingsScreenViewModel.isRoot) { - item { - LsposedInfoCard(settingsScreenViewModel.isActive) + item { + AnimatedVisibility( + visible = settingsScreenViewModel.visibilityLsposedCardState.value, + ) { + LsposedInfoCard(settingsScreenViewModel.moduleActive.value) } } @@ -52,37 +72,52 @@ fun SettingsScreen( Constants.SWITCH_CODE, settingsScreenViewModel.getBoolean(Constants.SWITCH_CODE), settingsScreenViewModel::setBoolean, - settingsScreenViewModel.isActive, - settingsScreenViewModel.isRoot + settingsScreenViewModel.useCase, + settingsScreenViewModel.moduleActive, + settingsScreenViewModel.permissionAccess ), SwitcherModel( R.string.switcher_phone, Constants.SWITCH_PHONE, settingsScreenViewModel.getBoolean(Constants.SWITCH_PHONE), settingsScreenViewModel::setBoolean, - settingsScreenViewModel.isActive, - settingsScreenViewModel.isRoot + settingsScreenViewModel.useCase, + settingsScreenViewModel.moduleActive, + settingsScreenViewModel.permissionAccess ), SwitcherModel( R.string.switcher_shazam, Constants.APPLICATION_PREF + Constants.SHAZAM_PACKAGE, settingsScreenViewModel.getBoolean(Constants.APPLICATION_PREF + Constants.SHAZAM_PACKAGE), settingsScreenViewModel::setBoolean, - settingsScreenViewModel.isActive, - settingsScreenViewModel.isRoot + settingsScreenViewModel.useCase, + settingsScreenViewModel.moduleActive, + settingsScreenViewModel.permissionAccess ), SwitcherModel( R.string.switcher_track_numbers, Constants.SWITHC_TRACK_NUMBER, settingsScreenViewModel.getBoolean(Constants.SWITHC_TRACK_NUMBER), settingsScreenViewModel::setBoolean, - settingsScreenViewModel.isActive, - settingsScreenViewModel.isRoot + settingsScreenViewModel.useCase, + settingsScreenViewModel.moduleActive, + settingsScreenViewModel.permissionAccess ) ) ) { _, item -> Switcher(item) } + + val permissionCardVisibilityUiState = settingsScreenViewModel.permissionCardVisibilityUiState + + item { + AnimatedVisibility( + visible = permissionCardVisibilityUiState.value + ) { + val permissionCardModel by settingsScreenViewModel.permissionCardModelUiStateFlow.collectAsState() + PermissionCard(permissionCardModel) + } + } } } diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsActivityViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsActivityViewModel.kt index f07d031..7dcf71d 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsActivityViewModel.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsActivityViewModel.kt @@ -2,6 +2,7 @@ package ru.n00byara.notificationcode.ui.viewmodels import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.lifecycle.ViewModel @@ -9,6 +10,7 @@ import androidx.lifecycle.ViewModelProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import ru.n00byara.notificationcode.components.terminal.Terminal import ru.n00byara.notificationcode.ui.components.topbar.TopBarModel import kotlin.reflect.KFunction0 @@ -19,6 +21,16 @@ class GlobalSettingsActivityViewModel(private val finishActivity: KFunction0 = this._useCaseDialogState.asStateFlow() - val isRoot = RootBeer(this.context).isRooted + val permissionCardVisibilityUiState = mutableStateOf( + this.settings.getInt(Constants.USE_CASE) == 1 && !permission.checkPermission() + ) + private val _permissionCardModelUiState = MutableStateFlow( + PermissionCardModel(openSettings = this::openSettings) + ) + val permissionCardModelUiStateFlow: StateFlow = this._permissionCardModelUiState.asStateFlow() init { setVariantDialogDescription() @@ -31,16 +42,15 @@ class GlobalSettingsScreenViewModel(application: Application) : AndroidViewModel } private fun setUseCase(case: Int) { - this.permission = Permission(this.context) - - if (case == 1 && !this.permission.checkPermission()) { - this.permission.requestPermissions() - } - this.settings.setInt(Constants.USE_CASE, case) this._useCaseDialogState.value.selectedCaseIndex = this.settings.getInt(Constants.USE_CASE) - this.setVariantDialogDescription() this.openDialogState.value = false + setVariantDialogDescription() + when (case) { + 0 -> this.permissionCardVisibilityUiState.value = false + 1 -> this.permissionCardVisibilityUiState.value = + !this.permission.checkPermission() + } } // 0 == Root 1 == Non Root @@ -51,4 +61,14 @@ class GlobalSettingsScreenViewModel(application: Application) : AndroidViewModel this._useCaseDialogState.value.useCaseTitle = R.string.alert_dialog_use_case_non_root } } + + private fun openSettings() { + this.permission.requestPermissions() + } + + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + private fun onResume() { + this.permissionCardVisibilityUiState.value = + this.settings.getInt(Constants.USE_CASE) == 1 && !permission.checkPermission() + } } \ No newline at end of file diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsActivityViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsActivityViewModel.kt index f7da841..cac7750 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsActivityViewModel.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsActivityViewModel.kt @@ -6,86 +6,21 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.AndroidViewModel import com.scottyab.rootbeer.RootBeer import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import ru.n00byara.notificationcode.Constants -import ru.n00byara.notificationcode.components.permission.Permission -import ru.n00byara.notificationcode.components.terminal.Terminal import ru.n00byara.notificationcode.models.SettingsModel import ru.n00byara.notificationcode.ui.activities.GlobalSettingsActivity -import ru.n00byara.notificationcode.ui.components.permissionalertdialog.PermissionAlertDialogModel import ru.n00byara.notificationcode.ui.components.topbar.TopBarModel -import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialogModel class SettingsActivityViewModel(application: Application) : AndroidViewModel(application) { - companion object { - private const val IS_FIRST_LAUNCH = "is_first_launch" - } - private val context = application.applicationContext - private var permission = Permission(this.context) private val settings = SettingsModel() + private val isRooted = RootBeer(this.context).isRooted private val _topBarUiState = MutableStateFlow(TopBarModel()) val topBarUiState: StateFlow = _topBarUiState.asStateFlow() - val isRooted = RootBeer(this.context).isRooted - val isFirstLaunch = this.settings.getBoolean(IS_FIRST_LAUNCH, true) - val openRootDialogState = mutableStateOf(false) - val openNonRootDialogState = mutableStateOf(false) - private val _useCaseAlertDialogUiState = MutableStateFlow( - UseCaseAlertDialogModel( - this.openRootDialogState, - this::setSelectedCase, - 0 - ) - ) - val useCaseAlertDialogUiState: StateFlow = this._useCaseAlertDialogUiState - private val _permissionAlertDialogState = MutableStateFlow( - PermissionAlertDialogModel( - openDialogState = this.openNonRootDialogState, - openSettings = this::openSettings - ) - ) - val permissionAlertDialogState: StateFlow = this._permissionAlertDialogState - - init { - this.openAlertDialog() - } - - private fun openAlertDialog() { - if (!this.isFirstLaunch) return - - if (!this.isRooted) { - this.settings.setInt(Constants.USE_CASE, 1) - this.openNonRootDialogState.value = true - return - } - - when (this.settings.getInt(Constants.USE_CASE, 2)) { - 1 -> this.openNonRootDialogState.value = true - 0 -> this.settings.setBoolean(IS_FIRST_LAUNCH, false) - else -> this.openRootDialogState.value = true - } - } - - private fun openSettings() { - this.permission.requestPermissions() - } - - private fun setSelectedCase(case: Int) { - this.settings.setInt(Constants.USE_CASE, case) - - when (case) { - 1 -> Terminal.restartModule() - 0 -> { - this.settings.setBoolean(IS_FIRST_LAUNCH, false) - this.openRootDialogState.value = false - } - } - } fun updateTopBarTitle(title: String) { this._topBarUiState.value = TopBarModel( diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt index 6dba1f1..6e10bb6 100644 --- a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt +++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt @@ -1,14 +1,101 @@ package ru.n00byara.notificationcode.ui.viewmodels -import androidx.lifecycle.ViewModel +import android.app.Application +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.OnLifecycleEvent +import com.scottyab.rootbeer.RootBeer +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import ru.n00byara.notificationcode.Constants +import ru.n00byara.notificationcode.components.permission.Permission import ru.n00byara.notificationcode.models.SettingsModel +import ru.n00byara.notificationcode.ui.components.permissionalertdialog.PermissionAlertDialogModel +import ru.n00byara.notificationcode.ui.components.permissioncard.PermissionCardModel +import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialogModel -class SettingsScreenViewModel : ViewModel() { +class SettingsScreenViewModel(private val application: Application) : + AndroidViewModel(application), + LifecycleObserver +{ + companion object { + private const val IS_FIRST_LAUNCH = "is_first_launch" + } + private val context = this.application.applicationContext private val settingsModel = SettingsModel() - val isActive = this.settingsModel.isActive - val isRoot = this.settingsModel.getInt(Constants.USE_CASE) == 0 + private var permission = Permission(this.context) + private val settings = SettingsModel() + val isRootedDevice = RootBeer(this.context).isRooted + val isFirstLaunch = this.settings.getBoolean(IS_FIRST_LAUNCH, true) + val openRootDialogState = mutableStateOf(false) + val openNonRootDialogState = mutableStateOf(false) + private val _useCaseAlertDialogUiState = MutableStateFlow( + UseCaseAlertDialogModel( + this.openRootDialogState, + this::setSelectedCase, + 0 + ) + ) + val useCaseAlertDialogUiState: StateFlow = this._useCaseAlertDialogUiState + private val _permissionAlertDialogState = MutableStateFlow( + PermissionAlertDialogModel( + openDialogState = this.openNonRootDialogState, + openSettings = this::openSettings + ) + ) + val permissionAlertDialogState: StateFlow = this._permissionAlertDialogState + val visibilityLsposedCardState = mutableStateOf( + this.settings.getInt(Constants.USE_CASE, 0) == 0 && this.isRootedDevice + ) + val useCase = mutableStateOf(this.settings.getInt(Constants.USE_CASE, 1)) + val moduleActive = mutableStateOf(this.settingsModel.isActive) + val permissionAccess = mutableStateOf(this.permission.checkPermission()) + val permissionCardVisibilityUiState = mutableStateOf( + this.settings.getInt(Constants.USE_CASE) == 1 && !permission.checkPermission() + ) + private val _permissionCardModelUiState = MutableStateFlow( + PermissionCardModel(openSettings = this::openSettings) + ) + val permissionCardModelUiStateFlow: StateFlow = this._permissionCardModelUiState.asStateFlow() + + init { + this.openAlertDialog() + } + + private fun openAlertDialog() { + if (!this.isFirstLaunch) return + + if (this.isRootedDevice) { + this.visibilityLsposedCardState.value = true + this.openRootDialogState.value = true + return + } + + this.settings.setInt(Constants.USE_CASE, 1) + this.openNonRootDialogState.value = true + this.useCase.value = this.settings.getInt(Constants.USE_CASE) + } + + private fun openSettings() { + this.settings.setBoolean(IS_FIRST_LAUNCH, false) + this.permission.requestPermissions() + } + + private fun setSelectedCase(case: Int) { + this.settings.setInt(Constants.USE_CASE, case) + this.settings.setBoolean(IS_FIRST_LAUNCH, false) + this.openRootDialogState.value = false + this.useCase.value = case + + if (case != 1) return + this.openNonRootDialogState.value = true + this.visibilityLsposedCardState.value = false + } + fun getBoolean(prefName: String): Boolean { return this.settingsModel.getBoolean(prefName) } @@ -16,4 +103,12 @@ class SettingsScreenViewModel : ViewModel() { fun setBoolean(prefName: String, value: Boolean) { this.settingsModel.setBoolean(prefName, value) } + + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + private fun onResume() { + this.visibilityLsposedCardState.value = + this.settings.getInt(Constants.USE_CASE) == 0 && this.isRootedDevice + this.permissionCardVisibilityUiState.value = + this.settings.getInt(Constants.USE_CASE) == 1 && !permission.checkPermission() + } } \ No newline at end of file diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 6d0ab7b..0e02262 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -17,4 +17,7 @@ For the service to work, provide permission to listen to notifications Cancel OK + Need to restart SystemUI + (Recommended) + Grant access to notification listener \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6095925..920387f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -17,4 +17,7 @@ Для работы сервиса предоставьте разрешение на прослушивание уведомлений Отмена Предоставить + Необходимо перезапустить SystemUI + (Рекомендуемый) + Предоставить доступ к слушателю уведомлений \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 274509c..8a6dc7f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,4 +21,7 @@ For the service to work, provide permission to listen to notifications Cancel OK + Need to restart SystemUI + (Recommended) + Grant access to notification listener \ No newline at end of file