updates: granular installer filters + advanced-section move
- New SourceFiltersScreen with All toggle + add/remove of specific installer package names. Backed by PREFERENCE_FILTER_INSTALLERS (Set<String>); PREFERENCE_FILTER_AURORA_ONLY preserved as the All switch for backward compat. - UpdateWorker reads installer via getInstallSourceInfo (R+) / falls back to deprecated getInstallerPackageName below. - UpdatesPreferenceScreen: "Filter F-Droid apps" moved to Advanced; "Filter apps from other sources" becomes a navigation row to the new sub-screen with a state summary.
This commit is contained in:
@@ -45,4 +45,5 @@ sealed class Destination {
|
|||||||
data object Dispenser : Destination()
|
data object Dispenser : Destination()
|
||||||
data object UIPreference : Destination()
|
data object UIPreference : Destination()
|
||||||
data object UpdatesPreference : Destination()
|
data object UpdatesPreference : Destination()
|
||||||
|
data object SourceFilters : Destination()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import com.aurora.store.compose.ui.preferences.UIPreferenceScreen
|
|||||||
import com.aurora.store.compose.ui.preferences.installation.InstallationPreferenceScreen
|
import com.aurora.store.compose.ui.preferences.installation.InstallationPreferenceScreen
|
||||||
import com.aurora.store.compose.ui.preferences.installation.InstallerScreen
|
import com.aurora.store.compose.ui.preferences.installation.InstallerScreen
|
||||||
import com.aurora.store.compose.ui.preferences.network.NetworkPreferenceScreen
|
import com.aurora.store.compose.ui.preferences.network.NetworkPreferenceScreen
|
||||||
|
import com.aurora.store.compose.ui.preferences.updates.SourceFiltersScreen
|
||||||
import com.aurora.store.compose.ui.preferences.updates.UpdatesPreferenceScreen
|
import com.aurora.store.compose.ui.preferences.updates.UpdatesPreferenceScreen
|
||||||
import com.aurora.store.compose.ui.search.SearchScreen
|
import com.aurora.store.compose.ui.search.SearchScreen
|
||||||
import com.aurora.store.compose.ui.splash.SplashScreen
|
import com.aurora.store.compose.ui.splash.SplashScreen
|
||||||
@@ -147,6 +148,7 @@ fun NavDisplay(startDestination: NavKey) {
|
|||||||
Destination.Dispenser -> backstack.add(Screen.Dispenser)
|
Destination.Dispenser -> backstack.add(Screen.Dispenser)
|
||||||
Destination.UIPreference -> backstack.add(Screen.UIPreference)
|
Destination.UIPreference -> backstack.add(Screen.UIPreference)
|
||||||
Destination.UpdatesPreference -> backstack.add(Screen.UpdatesPreference)
|
Destination.UpdatesPreference -> backstack.add(Screen.UpdatesPreference)
|
||||||
|
Destination.SourceFilters -> backstack.add(Screen.SourceFilters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +264,8 @@ fun NavDisplay(startDestination: NavKey) {
|
|||||||
entry<Screen.Settings> { SettingsScreen(onNavigateTo = ::navigate) }
|
entry<Screen.Settings> { SettingsScreen(onNavigateTo = ::navigate) }
|
||||||
entry<Screen.NetworkPreference> { NetworkPreferenceScreen(onNavigateTo = ::navigate) }
|
entry<Screen.NetworkPreference> { NetworkPreferenceScreen(onNavigateTo = ::navigate) }
|
||||||
entry<Screen.UIPreference> { UIPreferenceScreen() }
|
entry<Screen.UIPreference> { UIPreferenceScreen() }
|
||||||
entry<Screen.UpdatesPreference> { UpdatesPreferenceScreen() }
|
entry<Screen.UpdatesPreference> { UpdatesPreferenceScreen(onNavigateTo = ::navigate) }
|
||||||
|
entry<Screen.SourceFilters> { SourceFiltersScreen() }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ sealed class Screen : NavKey, Parcelable {
|
|||||||
@Serializable
|
@Serializable
|
||||||
data object UpdatesPreference : Screen()
|
data object UpdatesPreference : Screen()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data object SourceFilters : Screen()
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data object Splash : Screen()
|
data object Splash : Screen()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2026 Aurora OSS
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.aurora.store.compose.ui.preferences.updates
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
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.AlertDialog
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewWrapper
|
||||||
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.compose.composable.TopAppBar
|
||||||
|
import com.aurora.store.compose.preview.ThemePreviewProvider
|
||||||
|
import com.aurora.store.util.Preferences
|
||||||
|
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY
|
||||||
|
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_INSTALLERS
|
||||||
|
import com.aurora.store.util.save
|
||||||
|
import com.aurora.store.viewmodel.all.UpdatesViewModel
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SourceFiltersScreen(viewModel: UpdatesViewModel = hiltViewModel()) {
|
||||||
|
ScreenContent(onCheckUpdatesNow = { viewModel.updateHelper.checkUpdatesNow() })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ScreenContent(onCheckUpdatesNow: () -> Unit = {}) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
var auroraOnly by remember {
|
||||||
|
mutableStateOf(Preferences.getBoolean(context, PREFERENCE_FILTER_AURORA_ONLY))
|
||||||
|
}
|
||||||
|
var installers by remember {
|
||||||
|
mutableStateOf(Preferences.getStringSet(context, PREFERENCE_FILTER_INSTALLERS))
|
||||||
|
}
|
||||||
|
var showAddDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
// Trigger a fresh check on the way out so removed/added installers take effect
|
||||||
|
// without waiting for the next periodic run.
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onDispose { onCheckUpdatesNow() }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showAddDialog) {
|
||||||
|
AddInstallerDialog(
|
||||||
|
existing = installers,
|
||||||
|
onAdd = { name ->
|
||||||
|
installers = installers + name
|
||||||
|
context.save(PREFERENCE_FILTER_INSTALLERS, installers)
|
||||||
|
showAddDialog = false
|
||||||
|
},
|
||||||
|
onDismiss = { showAddDialog = false }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = { TopAppBar(title = stringResource(R.string.pref_source_filters_title)) }
|
||||||
|
) { paddingValues ->
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
auroraOnly = !auroraOnly
|
||||||
|
context.save(PREFERENCE_FILTER_AURORA_ONLY, auroraOnly)
|
||||||
|
},
|
||||||
|
headlineContent = { Text(stringResource(R.string.source_filters_all)) },
|
||||||
|
supportingContent = {
|
||||||
|
Text(stringResource(R.string.pref_source_filters_desc_all))
|
||||||
|
},
|
||||||
|
trailingContent = {
|
||||||
|
Switch(
|
||||||
|
checked = auroraOnly,
|
||||||
|
onCheckedChange = { checked ->
|
||||||
|
auroraOnly = checked
|
||||||
|
context.save(PREFERENCE_FILTER_AURORA_ONLY, checked)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item { HorizontalDivider() }
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(stringResource(R.string.source_filters_installers_header))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (installers.isEmpty()) {
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.source_filters_installers_empty),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items(items = installers.toList(), key = { it }) { name ->
|
||||||
|
ListItem(
|
||||||
|
headlineContent = { Text(name) },
|
||||||
|
trailingContent = {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
installers = installers - name
|
||||||
|
context.save(PREFERENCE_FILTER_INSTALLERS, installers)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_delete_forever),
|
||||||
|
contentDescription = stringResource(
|
||||||
|
R.string.source_filters_remove
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable { showAddDialog = true },
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_add),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
|
headlineContent = { Text(stringResource(R.string.source_filters_add)) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun AddInstallerDialog(
|
||||||
|
existing: Set<String>,
|
||||||
|
onAdd: (String) -> Unit,
|
||||||
|
onDismiss: () -> Unit
|
||||||
|
) {
|
||||||
|
var value by remember { mutableStateOf("") }
|
||||||
|
val trimmed = value.trim()
|
||||||
|
val canAdd = trimmed.isNotEmpty() && trimmed !in existing
|
||||||
|
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
title = { Text(stringResource(R.string.source_filters_add)) },
|
||||||
|
text = {
|
||||||
|
Column {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = value,
|
||||||
|
label = { Text(stringResource(R.string.source_filters_add_dialog_hint)) },
|
||||||
|
onValueChange = { value = it },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(onClick = { onAdd(trimmed) }, enabled = canAdd) {
|
||||||
|
Text(stringResource(android.R.string.ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = onDismiss) {
|
||||||
|
Text(stringResource(R.string.action_cancel))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewWrapper(ThemePreviewProvider::class)
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun SourceFiltersScreenPreview() {
|
||||||
|
ScreenContent()
|
||||||
|
}
|
||||||
@@ -44,10 +44,14 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.tooling.preview.PreviewWrapper
|
import androidx.compose.ui.tooling.preview.PreviewWrapper
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
||||||
import com.aurora.extensions.isTAndAbove
|
import com.aurora.extensions.isTAndAbove
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
import com.aurora.store.compose.composable.TopAppBar
|
import com.aurora.store.compose.composable.TopAppBar
|
||||||
|
import com.aurora.store.compose.navigation.Destination
|
||||||
import com.aurora.store.compose.preview.ThemePreviewProvider
|
import com.aurora.store.compose.preview.ThemePreviewProvider
|
||||||
import com.aurora.store.compose.ui.preferences.network.SingleChoiceDialog
|
import com.aurora.store.compose.ui.preferences.network.SingleChoiceDialog
|
||||||
import com.aurora.store.data.model.UpdateMode
|
import com.aurora.store.data.model.UpdateMode
|
||||||
@@ -57,6 +61,7 @@ import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_IDLE
|
|||||||
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_METERED
|
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_METERED
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY
|
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_FDROID
|
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_FDROID
|
||||||
|
import com.aurora.store.util.Preferences.PREFERENCE_FILTER_INSTALLERS
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED
|
||||||
@@ -65,12 +70,16 @@ import com.aurora.store.viewmodel.all.UpdatesViewModel
|
|||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UpdatesPreferenceScreen(viewModel: UpdatesViewModel = hiltViewModel()) {
|
fun UpdatesPreferenceScreen(
|
||||||
|
viewModel: UpdatesViewModel = hiltViewModel(),
|
||||||
|
onNavigateTo: (Destination) -> Unit = {}
|
||||||
|
) {
|
||||||
ScreenContent(
|
ScreenContent(
|
||||||
onCancelAutomatedCheck = { viewModel.updateHelper.cancelAutomatedCheck() },
|
onCancelAutomatedCheck = { viewModel.updateHelper.cancelAutomatedCheck() },
|
||||||
onScheduleAutomatedCheck = { viewModel.updateHelper.scheduleAutomatedCheck() },
|
onScheduleAutomatedCheck = { viewModel.updateHelper.scheduleAutomatedCheck() },
|
||||||
onUpdateAutomatedCheck = { viewModel.updateHelper.updateAutomatedCheck() },
|
onUpdateAutomatedCheck = { viewModel.updateHelper.updateAutomatedCheck() },
|
||||||
onCheckUpdatesNow = { viewModel.updateHelper.checkUpdatesNow() }
|
onCheckUpdatesNow = { viewModel.updateHelper.checkUpdatesNow() },
|
||||||
|
onNavigateTo = onNavigateTo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +88,8 @@ private fun ScreenContent(
|
|||||||
onCancelAutomatedCheck: () -> Unit = {},
|
onCancelAutomatedCheck: () -> Unit = {},
|
||||||
onScheduleAutomatedCheck: () -> Unit = {},
|
onScheduleAutomatedCheck: () -> Unit = {},
|
||||||
onUpdateAutomatedCheck: () -> Unit = {},
|
onUpdateAutomatedCheck: () -> Unit = {},
|
||||||
onCheckUpdatesNow: () -> Unit = {}
|
onCheckUpdatesNow: () -> Unit = {},
|
||||||
|
onNavigateTo: (Destination) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val autoEntries = stringArrayResource(R.array.pref_updates_auto)
|
val autoEntries = stringArrayResource(R.array.pref_updates_auto)
|
||||||
@@ -96,12 +106,26 @@ private fun ScreenContent(
|
|||||||
var filterFDroid by remember {
|
var filterFDroid by remember {
|
||||||
mutableStateOf(Preferences.getBoolean(context, PREFERENCE_FILTER_FDROID, true))
|
mutableStateOf(Preferences.getBoolean(context, PREFERENCE_FILTER_FDROID, true))
|
||||||
}
|
}
|
||||||
var filterAuroraOnly by remember {
|
|
||||||
mutableStateOf(Preferences.getBoolean(context, PREFERENCE_FILTER_AURORA_ONLY))
|
|
||||||
}
|
|
||||||
var updatesExtended by remember {
|
var updatesExtended by remember {
|
||||||
mutableStateOf(Preferences.getBoolean(context, PREFERENCE_UPDATES_EXTENDED))
|
mutableStateOf(Preferences.getBoolean(context, PREFERENCE_UPDATES_EXTENDED))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-read source-filter prefs after returning from SourceFiltersScreen.
|
||||||
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
|
var refreshKey by remember { mutableIntStateOf(0) }
|
||||||
|
DisposableEffect(lifecycleOwner) {
|
||||||
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
|
if (event == Lifecycle.Event.ON_RESUME) refreshKey++
|
||||||
|
}
|
||||||
|
lifecycleOwner.lifecycle.addObserver(observer)
|
||||||
|
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
|
||||||
|
}
|
||||||
|
val filterAuroraOnly = remember(refreshKey) {
|
||||||
|
Preferences.getBoolean(context, PREFERENCE_FILTER_AURORA_ONLY)
|
||||||
|
}
|
||||||
|
val installerCount = remember(refreshKey) {
|
||||||
|
Preferences.getStringSet(context, PREFERENCE_FILTER_INSTALLERS).size
|
||||||
|
}
|
||||||
var showAutoDialog by remember { mutableStateOf(false) }
|
var showAutoDialog by remember { mutableStateOf(false) }
|
||||||
var showFrequencyDialog by remember { mutableStateOf(false) }
|
var showFrequencyDialog by remember { mutableStateOf(false) }
|
||||||
var showRestrictionsDialog by remember { mutableStateOf(false) }
|
var showRestrictionsDialog by remember { mutableStateOf(false) }
|
||||||
@@ -248,6 +272,23 @@ private fun ScreenContent(
|
|||||||
Text(stringResource(R.string.pref_updates_app_source))
|
Text(stringResource(R.string.pref_updates_app_source))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
onNavigateTo(Destination.SourceFilters)
|
||||||
|
},
|
||||||
|
headlineContent = {
|
||||||
|
Text(stringResource(R.string.pref_source_filters_title))
|
||||||
|
},
|
||||||
|
supportingContent = {
|
||||||
|
Text(sourceFiltersSummary(filterAuroraOnly, installerCount))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item { HorizontalDivider() }
|
||||||
|
item {
|
||||||
|
ListItem(headlineContent = { Text(stringResource(R.string.pref_common_advanced)) })
|
||||||
|
}
|
||||||
item {
|
item {
|
||||||
ListItem(
|
ListItem(
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
@@ -271,33 +312,6 @@ private fun ScreenContent(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
|
||||||
ListItem(
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
filterAuroraOnly = !filterAuroraOnly
|
|
||||||
context.save(PREFERENCE_FILTER_AURORA_ONLY, filterAuroraOnly)
|
|
||||||
if (filterAuroraOnly) filterFDroid = false
|
|
||||||
onCheckUpdatesNow()
|
|
||||||
},
|
|
||||||
headlineContent = { Text(stringResource(R.string.pref_aurora_only)) },
|
|
||||||
supportingContent = { Text(stringResource(R.string.pref_aurora_only_desc)) },
|
|
||||||
trailingContent = {
|
|
||||||
Switch(
|
|
||||||
checked = filterAuroraOnly,
|
|
||||||
onCheckedChange = { checked ->
|
|
||||||
filterAuroraOnly = checked
|
|
||||||
context.save(PREFERENCE_FILTER_AURORA_ONLY, checked)
|
|
||||||
if (checked) filterFDroid = false
|
|
||||||
onCheckUpdatesNow()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
item { HorizontalDivider() }
|
|
||||||
item {
|
|
||||||
ListItem(headlineContent = { Text(stringResource(R.string.pref_common_advanced)) })
|
|
||||||
}
|
|
||||||
item {
|
item {
|
||||||
ListItem(
|
ListItem(
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
@@ -458,6 +472,13 @@ private fun selectedFrequencyIndex(storedHours: Int): Int {
|
|||||||
return UPDATE_INTERVAL_HOURS.indices.minBy { abs(UPDATE_INTERVAL_HOURS[it] - storedHours) }
|
return UPDATE_INTERVAL_HOURS.indices.minBy { abs(UPDATE_INTERVAL_HOURS[it] - storedHours) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun sourceFiltersSummary(allEnabled: Boolean, count: Int): String = when {
|
||||||
|
allEnabled -> stringResource(R.string.pref_source_filters_desc_all)
|
||||||
|
count == 0 -> stringResource(R.string.pref_source_filters_desc_none)
|
||||||
|
else -> stringResource(R.string.pref_source_filters_desc_count, count)
|
||||||
|
}
|
||||||
|
|
||||||
@PreviewWrapper(ThemePreviewProvider::class)
|
@PreviewWrapper(ThemePreviewProvider::class)
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -166,12 +166,23 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
.filter { if (!isExtendedUpdateEnabled) it.applicationInfo!!.enabled else true }
|
.filter { if (!isExtendedUpdateEnabled) it.applicationInfo!!.enabled else true }
|
||||||
|
|
||||||
// Filter out packages based on user's preferences
|
// Filter out packages based on user's preferences
|
||||||
|
val installerFilters = Preferences.getStringSet(
|
||||||
|
context,
|
||||||
|
Preferences.PREFERENCE_FILTER_INSTALLERS
|
||||||
|
)
|
||||||
val filteredPackages = if (isAuroraOnlyFilterEnabled) {
|
val filteredPackages = if (isAuroraOnlyFilterEnabled) {
|
||||||
packages.filter { CertUtil.isAuroraStoreApp(context, it.packageName) }
|
packages.filter { CertUtil.isAuroraStoreApp(context, it.packageName) }
|
||||||
} else {
|
} else {
|
||||||
packages.filterNot {
|
packages.filterNot { pkg ->
|
||||||
if (isFDroidFilterEnabled) {
|
if (isFDroidFilterEnabled && CertUtil.isFDroidApp(context, pkg.packageName)) {
|
||||||
CertUtil.isFDroidApp(context, it.packageName)
|
return@filterNot true
|
||||||
|
}
|
||||||
|
if (installerFilters.isNotEmpty()) {
|
||||||
|
val installer = PackageUtil.getInstallerPackageName(
|
||||||
|
context,
|
||||||
|
pkg.packageName
|
||||||
|
)
|
||||||
|
installer != null && installer in installerFilters
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE
|
|||||||
import com.aurora.extensions.isHuawei
|
import com.aurora.extensions.isHuawei
|
||||||
import com.aurora.extensions.isOAndAbove
|
import com.aurora.extensions.isOAndAbove
|
||||||
import com.aurora.extensions.isPAndAbove
|
import com.aurora.extensions.isPAndAbove
|
||||||
|
import com.aurora.extensions.isRAndAbove
|
||||||
import com.aurora.extensions.isTAndAbove
|
import com.aurora.extensions.isTAndAbove
|
||||||
import com.aurora.extensions.isVAndAbove
|
import com.aurora.extensions.isVAndAbove
|
||||||
import com.aurora.extensions.isValidApp
|
import com.aurora.extensions.isValidApp
|
||||||
@@ -270,6 +271,22 @@ object PackageUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the installer package name that installed [packageName], or null if unknown / not
|
||||||
|
* installed. Uses [PackageManager.getInstallSourceInfo] on API 30+; falls back to the
|
||||||
|
* pre-30 deprecated API below that.
|
||||||
|
*/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
fun getInstallerPackageName(context: Context, packageName: String): String? = try {
|
||||||
|
if (isRAndAbove) {
|
||||||
|
context.packageManager.getInstallSourceInfo(packageName).installingPackageName
|
||||||
|
} else {
|
||||||
|
context.packageManager.getInstallerPackageName(packageName)
|
||||||
|
}
|
||||||
|
} catch (_: PackageManager.NameNotFoundException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun getPackageInfo(context: Context, packageName: String, flags: Int = 0): PackageInfo =
|
fun getPackageInfo(context: Context, packageName: String, flags: Int = 0): PackageInfo =
|
||||||
if (isTAndAbove) {
|
if (isTAndAbove) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ object Preferences {
|
|||||||
|
|
||||||
const val PREFERENCE_FILTER_FDROID = "PREFERENCE_FILTER_FDROID"
|
const val PREFERENCE_FILTER_FDROID = "PREFERENCE_FILTER_FDROID"
|
||||||
const val PREFERENCE_FILTER_AURORA_ONLY = "PREFERENCE_FILTER_AURORA_ONLY"
|
const val PREFERENCE_FILTER_AURORA_ONLY = "PREFERENCE_FILTER_AURORA_ONLY"
|
||||||
|
const val PREFERENCE_FILTER_INSTALLERS = "PREFERENCE_FILTER_INSTALLERS"
|
||||||
|
|
||||||
const val PREFERENCE_AUTO_DELETE = "PREFERENCE_AUTO_DELETE"
|
const val PREFERENCE_AUTO_DELETE = "PREFERENCE_AUTO_DELETE"
|
||||||
|
|
||||||
|
|||||||
@@ -226,10 +226,20 @@
|
|||||||
<string name="pref_ui_no_for_you">"For you pages"</string>
|
<string name="pref_ui_no_for_you">"For you pages"</string>
|
||||||
<string name="pref_ui_no_for_you_desc">"Display For you pages on home screen"</string>
|
<string name="pref_ui_no_for_you_desc">"Display For you pages on home screen"</string>
|
||||||
<string name="pref_ui_similar_apps">"Similar and related apps"</string>
|
<string name="pref_ui_similar_apps">"Similar and related apps"</string>
|
||||||
<string name="pref_updates_incompatible">Show updates that may fail</string>
|
<string name="pref_updates_incompatible">"Show updates that may fail"</string>
|
||||||
<string name="pref_updates_incompatible_desc">Display updates for incompatible or disabled apps that may fail to install</string>
|
<string name="pref_updates_incompatible_desc">"Display updates for incompatible or disabled apps that may fail to install."</string>
|
||||||
<string name="pref_aurora_only">Filter apps from other sources</string>
|
<string name="pref_aurora_only">"Filter apps from other sources."</string>
|
||||||
<string name="pref_aurora_only_desc">Don\'t check for updates for apps installed from sources outside Aurora Store</string>
|
<string name="pref_aurora_only_desc">"Do not check for updates for apps installed from sources outside Aurora Store"</string>
|
||||||
|
<string name="pref_source_filters_title">"Filter apps from other sources"</string>
|
||||||
|
<string name="pref_source_filters_desc_all">"Skip every app not installed by Aurora Store"</string>
|
||||||
|
<string name="pref_source_filters_desc_none">"No installers excluded"</string>
|
||||||
|
<string name="pref_source_filters_desc_count">"%1$d installer(s) excluded"</string>
|
||||||
|
<string name="source_filters_all">"Filter all other installers"</string>
|
||||||
|
<string name="source_filters_installers_header">"Specific installers"</string>
|
||||||
|
<string name="source_filters_installers_empty">"No installers added yet"</string>
|
||||||
|
<string name="source_filters_add">"Add installer"</string>
|
||||||
|
<string name="source_filters_add_dialog_hint">"Enter package name"</string>
|
||||||
|
<string name="source_filters_remove">"Remove installer"</string>
|
||||||
<string name="purchase_failed">"Download failed"</string>
|
<string name="purchase_failed">"Download failed"</string>
|
||||||
<string name="purchase_invalid">"App not purchased"</string>
|
<string name="purchase_invalid">"App not purchased"</string>
|
||||||
<string name="purchase_unsupported">"App not supported"</string>
|
<string name="purchase_unsupported">"App not supported"</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user