mirror of
https://github.com/whyorean/AuroraStore.git
synced 2025-12-23 22:27:55 -05:00
compose: preferences: Migrate installer logic to compose
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.aurora.store.compose.composable
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.compose.preview.PreviewTemplate
|
||||
import com.aurora.store.data.installer.SessionInstaller
|
||||
import com.aurora.store.data.model.InstallerInfo
|
||||
|
||||
/**
|
||||
* Composable to display installer details in a list
|
||||
* @param modifier The modifier to be applied to the composable
|
||||
* @param installerInfo A [InstallerInfo] object to display details
|
||||
* @param isSelected Whether this installer is selected
|
||||
* @param onClick Callback when this composable is clicked
|
||||
*/
|
||||
@Composable
|
||||
fun InstallerListItem(
|
||||
modifier: Modifier = Modifier,
|
||||
installerInfo: InstallerInfo,
|
||||
isSelected: Boolean = false,
|
||||
onClick: () -> Unit = {}
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(dimensionResource(R.dimen.padding_small)),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1F)) {
|
||||
Text(
|
||||
text = stringResource(installerInfo.title),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Text(
|
||||
text = stringResource(installerInfo.subtitle),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Text(
|
||||
text = stringResource(installerInfo.description),
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
}
|
||||
RadioButton(selected = isSelected, onClick = onClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun InstallerListItemPreview() {
|
||||
PreviewTemplate {
|
||||
InstallerListItem(installerInfo = SessionInstaller.installerInfo, isSelected = true)
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import com.aurora.store.compose.ui.dispenser.DispenserScreen
|
||||
import com.aurora.store.compose.ui.downloads.DownloadsScreen
|
||||
import com.aurora.store.compose.ui.favourite.FavouriteScreen
|
||||
import com.aurora.store.compose.ui.onboarding.OnboardingScreen
|
||||
import com.aurora.store.compose.ui.preferences.installation.InstallerScreen
|
||||
import com.aurora.store.compose.ui.search.SearchScreen
|
||||
import com.aurora.store.compose.ui.spoof.SpoofScreen
|
||||
|
||||
@@ -140,6 +141,10 @@ fun NavDisplay(startDestination: NavKey) {
|
||||
entry<Screen.Dispenser> {
|
||||
DispenserScreen(onNavigateUp = ::onNavigateUp)
|
||||
}
|
||||
|
||||
entry<Screen.Installer> {
|
||||
InstallerScreen(onNavigateUp = ::onNavigateUp)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -57,4 +57,7 @@ sealed class Screen : NavKey, Parcelable {
|
||||
|
||||
@Serializable
|
||||
data object Dispenser : Screen()
|
||||
|
||||
@Serializable
|
||||
data object Installer : Screen()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.aurora.store.compose.ui.preferences.installation
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.compose.composable.InstallerListItem
|
||||
import com.aurora.store.compose.composable.TopAppBar
|
||||
import com.aurora.store.compose.preview.PreviewTemplate
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.installer.SessionInstaller
|
||||
import com.aurora.store.data.model.Installer
|
||||
import com.aurora.store.data.model.InstallerInfo
|
||||
import com.aurora.store.viewmodel.preferences.InstallerViewModel
|
||||
|
||||
@Composable
|
||||
fun InstallerScreen(onNavigateUp: () -> Unit, viewModel: InstallerViewModel = hiltViewModel()) {
|
||||
val currentInstallerId by viewModel.currentInstaller.collectAsStateWithLifecycle()
|
||||
val snackBarHostState = remember { SnackbarHostState() }
|
||||
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
viewModel.error.collect { error ->
|
||||
snackBarHostState.showSnackbar(message = error)
|
||||
}
|
||||
}
|
||||
|
||||
ScreenContent(
|
||||
onNavigateUp = onNavigateUp,
|
||||
snackBarHostState = snackBarHostState,
|
||||
currentInstaller = Installer.entries[currentInstallerId],
|
||||
availableInstallers = AppInstaller.getAvailableInstallersInfo(LocalContext.current),
|
||||
onInstallerSelected = { installer -> viewModel.save(installer) }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScreenContent(
|
||||
onNavigateUp: () -> Unit = {},
|
||||
snackBarHostState: SnackbarHostState = SnackbarHostState(),
|
||||
currentInstaller: Installer = Installer.SESSION,
|
||||
availableInstallers: List<InstallerInfo> = emptyList(),
|
||||
onInstallerSelected: (installer: Installer) -> Unit = {}
|
||||
) {
|
||||
val snackBarHostState = remember { snackBarHostState }
|
||||
|
||||
Scaffold(
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackBarHostState)
|
||||
},
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(R.string.pref_install_mode_title),
|
||||
onNavigateUp = onNavigateUp
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize()
|
||||
.padding(vertical = dimensionResource(R.dimen.padding_medium))
|
||||
) {
|
||||
items(items = availableInstallers, key = { i -> i.id }) { installerInfo ->
|
||||
InstallerListItem(
|
||||
installerInfo = installerInfo,
|
||||
isSelected = installerInfo.installer == currentInstaller,
|
||||
onClick = { onInstallerSelected(installerInfo.installer) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun InstallerScreenPreview() {
|
||||
PreviewTemplate {
|
||||
ScreenContent(
|
||||
availableInstallers = listOf(SessionInstaller.installerInfo)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.epoxy.views.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.CompoundButton
|
||||
import com.airbnb.epoxy.CallbackProp
|
||||
import com.airbnb.epoxy.ModelProp
|
||||
import com.airbnb.epoxy.ModelView
|
||||
import com.aurora.store.data.model.InstallerInfo
|
||||
import com.aurora.store.databinding.ViewInstallerBinding
|
||||
import com.aurora.store.view.epoxy.views.BaseModel
|
||||
import com.aurora.store.view.epoxy.views.BaseView
|
||||
|
||||
@ModelView(
|
||||
autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT,
|
||||
baseModelClass = BaseModel::class
|
||||
)
|
||||
class InstallerView @JvmOverloads constructor(
|
||||
context: Context?,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : BaseView<ViewInstallerBinding>(context, attrs, defStyleAttr) {
|
||||
|
||||
@ModelProp
|
||||
fun installer(installer: InstallerInfo) {
|
||||
binding.line1.text = context.getString(installer.title)
|
||||
binding.line2.text = context.getString(installer.subtitle)
|
||||
binding.line3.text = context.getString(installer.description)
|
||||
}
|
||||
|
||||
@ModelProp
|
||||
fun markChecked(isChecked: Boolean) {
|
||||
binding.radiobutton.isChecked = isChecked
|
||||
}
|
||||
|
||||
@CallbackProp
|
||||
fun checked(onCheckedChangeListener: CompoundButton.OnCheckedChangeListener?) {
|
||||
binding.radiobutton.setOnCheckedChangeListener(onCheckedChangeListener)
|
||||
}
|
||||
|
||||
@CallbackProp
|
||||
fun click(onClickListener: OnClickListener?) {
|
||||
binding.root.setOnClickListener(onClickListener)
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,10 @@ import androidx.core.content.getSystemService
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.aurora.extensions.navigate
|
||||
import com.aurora.extensions.showDialog
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.compose.navigation.Screen
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLATION_DEVICE_OWNER
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
@@ -42,7 +44,7 @@ class InstallationPreference : PreferenceFragmentCompat() {
|
||||
|
||||
findPreference<Preference>(PREFERENCE_INSTALLER_ID)?.apply {
|
||||
setOnPreferenceClickListener {
|
||||
findNavController().navigate(R.id.installerFragment)
|
||||
requireContext().navigate(Screen.Installer)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.view.ui.preferences.installation
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.aurora.extensions.isMIUI
|
||||
import com.aurora.extensions.isMiuiOptimizationDisabled
|
||||
import com.aurora.extensions.isOAndAbove
|
||||
import com.aurora.extensions.showDialog
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.databinding.FragmentInstallerBinding
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
|
||||
import com.aurora.store.util.save
|
||||
import com.aurora.store.view.epoxy.views.preference.InstallerViewModel_
|
||||
import com.aurora.store.view.ui.commons.BaseFragment
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import rikka.shizuku.Shizuku
|
||||
import rikka.sui.Sui
|
||||
|
||||
@AndroidEntryPoint
|
||||
class InstallerFragment : BaseFragment<FragmentInstallerBinding>() {
|
||||
|
||||
private val TAG = InstallerFragment::class.java.simpleName
|
||||
|
||||
private var installerId: Int = 0
|
||||
|
||||
private var shizukuAlive = Sui.isSui()
|
||||
private val shizukuAliveListener = Shizuku.OnBinderReceivedListener {
|
||||
Log.d(TAG, "ShizukuInstaller Alive!")
|
||||
shizukuAlive = true
|
||||
}
|
||||
private val shizukuDeadListener = Shizuku.OnBinderDeadListener {
|
||||
Log.d(TAG, "ShizukuInstaller Dead!")
|
||||
shizukuAlive = false
|
||||
}
|
||||
|
||||
private val shizukuResultListener =
|
||||
Shizuku.OnRequestPermissionResultListener { _: Int, result: Int ->
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
this.installerId = 5
|
||||
save(PREFERENCE_INSTALLER_ID, 5)
|
||||
binding.epoxyRecycler.requestModelBuild()
|
||||
} else {
|
||||
showDialog(
|
||||
R.string.action_installations,
|
||||
R.string.installer_shizuku_unavailable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// Toolbar
|
||||
binding.toolbar.setNavigationOnClickListener { findNavController().navigateUp() }
|
||||
|
||||
installerId = Preferences.getInteger(requireContext(), PREFERENCE_INSTALLER_ID)
|
||||
|
||||
if (AppInstaller.hasShizukuOrSui(requireContext())) {
|
||||
Shizuku.addBinderReceivedListenerSticky(shizukuAliveListener)
|
||||
Shizuku.addBinderDeadListener(shizukuDeadListener)
|
||||
Shizuku.addRequestPermissionResultListener(shizukuResultListener)
|
||||
}
|
||||
|
||||
// RecyclerView
|
||||
binding.epoxyRecycler.withModels {
|
||||
setFilterDuplicates(true)
|
||||
AppInstaller.getAvailableInstallersInfo(requireContext()).forEach {
|
||||
add(
|
||||
InstallerViewModel_()
|
||||
.id(it.id)
|
||||
.installer(it)
|
||||
.markChecked(installerId == it.id)
|
||||
.click { _ ->
|
||||
save(it.id)
|
||||
requestModelBuild()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (isMIUI && !isMiuiOptimizationDisabled) {
|
||||
findNavController().navigate(R.id.deviceMiuiSheet)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (AppInstaller.hasShizukuOrSui(requireContext())) {
|
||||
Shizuku.removeBinderReceivedListener(shizukuAliveListener)
|
||||
Shizuku.removeBinderDeadListener(shizukuDeadListener)
|
||||
Shizuku.removeRequestPermissionResultListener(shizukuResultListener)
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun save(installerId: Int) {
|
||||
when (installerId) {
|
||||
0 -> {
|
||||
if (isMIUI && !isMiuiOptimizationDisabled) {
|
||||
findNavController().navigate(R.id.deviceMiuiSheet)
|
||||
}
|
||||
this.installerId = installerId
|
||||
save(PREFERENCE_INSTALLER_ID, installerId)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
if (AppInstaller.hasRootAccess()) {
|
||||
this.installerId = installerId
|
||||
save(PREFERENCE_INSTALLER_ID, installerId)
|
||||
} else {
|
||||
showDialog(
|
||||
R.string.action_installations,
|
||||
R.string.installer_root_unavailable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
3 -> {
|
||||
if (AppInstaller.hasAuroraService(requireContext())) {
|
||||
this.installerId = installerId
|
||||
save(PREFERENCE_INSTALLER_ID, installerId)
|
||||
} else {
|
||||
showDialog(
|
||||
R.string.action_installations,
|
||||
R.string.installer_service_unavailable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
4 -> {
|
||||
if (AppInstaller.hasAppManager(requireContext())) {
|
||||
this.installerId = installerId
|
||||
save(PREFERENCE_INSTALLER_ID, installerId)
|
||||
} else {
|
||||
showDialog(
|
||||
R.string.action_installations,
|
||||
R.string.installer_am_unavailable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
5 -> {
|
||||
if (isOAndAbove && AppInstaller.hasShizukuOrSui(requireContext())) {
|
||||
if (shizukuAlive && AppInstaller.hasShizukuPerm()) {
|
||||
this.installerId = installerId
|
||||
save(PREFERENCE_INSTALLER_ID, installerId)
|
||||
} else if (shizukuAlive && !Shizuku.shouldShowRequestPermissionRationale()) {
|
||||
Shizuku.requestPermission(9000)
|
||||
} else {
|
||||
showDialog(
|
||||
R.string.action_installations,
|
||||
R.string.installer_shizuku_unavailable
|
||||
)
|
||||
}
|
||||
} else {
|
||||
showDialog(
|
||||
R.string.action_installations,
|
||||
R.string.installer_shizuku_unavailable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
this.installerId = installerId
|
||||
save(PREFERENCE_INSTALLER_ID, installerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.aurora.store.viewmodel.preferences
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.aurora.extensions.isMIUI
|
||||
import com.aurora.extensions.isMiuiOptimizationDisabled
|
||||
import com.aurora.extensions.observeAsStateFlow
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.model.Installer
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
|
||||
import com.aurora.store.util.save
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import rikka.shizuku.Shizuku
|
||||
import rikka.sui.Sui
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class InstallerViewModel @Inject constructor(
|
||||
@ApplicationContext private val context: Context
|
||||
) : ViewModel(), Shizuku.OnBinderReceivedListener, Shizuku.OnBinderDeadListener,
|
||||
Shizuku.OnRequestPermissionResultListener {
|
||||
|
||||
private val TAG = InstallerViewModel::class.java.simpleName
|
||||
private val sharedPreferences = Preferences.getPrefs(context)
|
||||
private var isShizukuAlive = Sui.isSui()
|
||||
|
||||
private val _error = MutableSharedFlow<String>()
|
||||
val error = _error.asSharedFlow()
|
||||
|
||||
private var _installerId: Int
|
||||
get() = sharedPreferences.getInt(PREFERENCE_INSTALLER_ID, 0)
|
||||
set(value) = sharedPreferences.edit { putInt(PREFERENCE_INSTALLER_ID, value) }
|
||||
|
||||
val currentInstaller = sharedPreferences.observeAsStateFlow(
|
||||
key = PREFERENCE_INSTALLER_ID,
|
||||
scope = viewModelScope,
|
||||
initial = AppInstaller.getCurrentInstaller(context).ordinal,
|
||||
valueProvider = { _installerId }
|
||||
)
|
||||
|
||||
init {
|
||||
Shizuku.addBinderReceivedListenerSticky(this)
|
||||
Shizuku.addBinderDeadListener(this)
|
||||
Shizuku.addRequestPermissionResultListener(this)
|
||||
}
|
||||
|
||||
override fun onBinderReceived() {
|
||||
isShizukuAlive = true
|
||||
}
|
||||
|
||||
override fun onBinderDead() {
|
||||
isShizukuAlive = false
|
||||
}
|
||||
|
||||
override fun onRequestPermissionResult(requestCode: Int, grantResult: Int) {
|
||||
if (grantResult == PackageManager.PERMISSION_GRANTED) {
|
||||
save(Installer.SHIZUKU)
|
||||
} else {
|
||||
viewModelScope.launch {
|
||||
Log.e(TAG, "Permission denied for shizuku")
|
||||
_error.emit(context.getString(R.string.permissions_denied))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun save(installer: Installer) {
|
||||
viewModelScope.launch {
|
||||
// Error handling for different installers
|
||||
when (installer) {
|
||||
Installer.SESSION -> {
|
||||
if (isMIUI && !isMiuiOptimizationDisabled) {
|
||||
Log.e(TAG, "Trying to set session installer with MIUI optimizations")
|
||||
_error.emit(context.getString(R.string.device_miui_description))
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
Installer.ROOT -> {
|
||||
if (!AppInstaller.hasRootAccess()) {
|
||||
Log.e(TAG, "Trying to set root installer without root access")
|
||||
_error.emit(context.getString(R.string.installer_root_unavailable))
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
Installer.SERVICE -> {
|
||||
if (!AppInstaller.hasAuroraService(context)) {
|
||||
Log.e(TAG, "Trying to set service installer without companion app")
|
||||
_error.emit(context.getString(R.string.installer_service_unavailable))
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
Installer.SHIZUKU -> {
|
||||
if (AppInstaller.hasShizukuOrSui(context) && isShizukuAlive) {
|
||||
if (!AppInstaller.hasShizukuPerm()) {
|
||||
Log.i(TAG, "Requesting permission for shizuku")
|
||||
Shizuku.requestPermission(9000)
|
||||
return@launch
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Trying to set shizuku installer without appropriate setup")
|
||||
_error.emit(context.getString(R.string.installer_shizuku_unavailable))
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
Installer.AM -> {
|
||||
if (!AppInstaller.hasAppManager(context)) {
|
||||
Log.e(TAG, "Trying to set AM installer without companion app")
|
||||
_error.emit(context.getString(R.string.installer_am_unavailable))
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
else -> Log.i(TAG, "Trying to set ${installer.name} installer without any checks")
|
||||
}
|
||||
|
||||
context.save(PREFERENCE_INSTALLER_ID, installer.ordinal)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
~ Aurora Store
|
||||
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
~
|
||||
~ Aurora Store is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Aurora Store is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
app:navigationIcon="@drawable/ic_arrow_back"
|
||||
app:title="@string/pref_install_mode_title" />
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/epoxy_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="never"
|
||||
android:padding="@dimen/padding_normal"
|
||||
android:scrollbars="none"
|
||||
app:itemSpacing="@dimen/margin_small"
|
||||
tools:listitem="@layout/view_installer" />
|
||||
</LinearLayout>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
~ Aurora Store
|
||||
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
~
|
||||
~ Aurora Store is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Aurora Store is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
app:navigationIcon="@drawable/ic_arrow_back"
|
||||
app:title="@string/pref_install_mode_title" />
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/epoxy_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="never"
|
||||
android:padding="@dimen/padding_normal"
|
||||
android:scrollbars="none"
|
||||
app:itemSpacing="@dimen/margin_small"
|
||||
tools:listitem="@layout/view_installer" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Aurora Store
|
||||
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
~
|
||||
~ Aurora Store is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Aurora Store is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/padding_small">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/line1"
|
||||
style="@style/AuroraTextStyle.Subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/radiobutton" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/line2"
|
||||
style="@style/AuroraTextStyle.Line1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/line1"
|
||||
android:layout_alignStart="@id/line1"
|
||||
android:layout_alignEnd="@id/line1"
|
||||
android:layout_marginTop="@dimen/margin_xxsmall" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/line3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/line2"
|
||||
android:layout_alignStart="@id/line1"
|
||||
android:layout_alignEnd="@id/line1"
|
||||
android:layout_marginTop="@dimen/margin_xxsmall"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/radiobutton"
|
||||
android:layout_width="@dimen/icon_size_category"
|
||||
android:layout_height="@dimen/icon_size_category"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:minWidth="0dp" />
|
||||
</RelativeLayout>
|
||||
@@ -184,11 +184,6 @@
|
||||
app:popUpTo="@id/splashFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/installerFragment"
|
||||
android:name="com.aurora.store.view.ui.preferences.installation.InstallerFragment"
|
||||
android:label="InstallerFragment"
|
||||
tools:layout="@layout/fragment_installer" />
|
||||
<dialog
|
||||
android:id="@+id/appMenuSheet"
|
||||
android:name="com.aurora.store.view.ui.sheets.AppMenuSheet"
|
||||
|
||||
Reference in New Issue
Block a user