add setting to exclude apps from shortcuts search
This commit is contained in:
@@ -52,6 +52,8 @@ import de.mm20.launcher2.ui.settings.appearance.ImportThemeSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.appearance.ImportThemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.apps.AppSearchSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.apps.AppSearchSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.appshortcuts.AppShortcutsSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.appshortcuts.AppShortcutsSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.backup.BackupSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.breezyweather.BreezyWeatherSettingsRoute
|
||||
@@ -261,6 +263,9 @@ class SettingsActivity : BaseActivity() {
|
||||
entry<FavoritesSettingsRoute> {
|
||||
FavoritesSettingsScreen()
|
||||
}
|
||||
entry<AppShortcutsSettingsRoute> {
|
||||
AppShortcutsSettingsScreen()
|
||||
}
|
||||
entry<ContactsSettingsRoute> {
|
||||
ContactsSettingsScreen()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package de.mm20.launcher2.ui.settings.appshortcuts
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.applications.AppRepository
|
||||
import de.mm20.launcher2.badges.Badge
|
||||
import de.mm20.launcher2.badges.BadgeService
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class AppShortcutSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val appRepository by inject<AppRepository>()
|
||||
private val settings by inject<ShortcutSearchSettings>()
|
||||
private val permissionsManager by inject<PermissionsManager>()
|
||||
private val iconService by inject<IconService>()
|
||||
private val badgeService by inject<BadgeService>()
|
||||
|
||||
val blocklist =
|
||||
settings.blocklist.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptySet())
|
||||
|
||||
val apps = appRepository.findMany().map { it.sorted() }.flowOn(Dispatchers.Default)
|
||||
|
||||
val isShortcutSearchEnabled = settings.enabled
|
||||
|
||||
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setShortcutSearchEnabled(enabled: Boolean) {
|
||||
settings.setEnabled(enabled)
|
||||
}
|
||||
|
||||
fun setAppBlocklisted(appId: String, blocked: Boolean) {
|
||||
val blocklist = blocklist.value.toMutableSet()
|
||||
if (blocked) {
|
||||
blocklist.add(appId)
|
||||
} else {
|
||||
blocklist.remove(appId)
|
||||
}
|
||||
settings.setBlocklist(blocklist)
|
||||
}
|
||||
|
||||
fun requestAppShortcutsPermission(activity: AppCompatActivity) {
|
||||
permissionsManager.requestPermission(activity, PermissionGroup.AppShortcuts)
|
||||
}
|
||||
|
||||
fun getIcon(app: SavableSearchable, size: Int): Flow<LauncherIcon?> {
|
||||
return iconService.getIcon(app, size)
|
||||
}
|
||||
|
||||
fun getBadge(app: SavableSearchable): Flow<Badge?> {
|
||||
return badgeService.getBadge(app)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package de.mm20.launcher2.ui.settings.appshortcuts
|
||||
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
import de.mm20.launcher2.ktx.getSerialNumber
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||
import de.mm20.launcher2.ui.component.preferences.CheckboxPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.GuardedPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.ktx.toPixels
|
||||
|
||||
data object AppShortcutsSettingsRoute : NavKey
|
||||
|
||||
@Composable
|
||||
fun AppShortcutsSettingsScreen() {
|
||||
|
||||
val viewModel: AppShortcutSettingsScreenVM = viewModel()
|
||||
|
||||
val searchEnabled by viewModel.isShortcutSearchEnabled.collectAsStateWithLifecycle(null)
|
||||
val hasPermission by viewModel.hasAppShortcutPermission.collectAsStateWithLifecycle(
|
||||
null
|
||||
)
|
||||
val apps by viewModel.apps.collectAsStateWithLifecycle(emptyList())
|
||||
val blocklist by viewModel.blocklist.collectAsStateWithLifecycle()
|
||||
|
||||
val activity = LocalActivity.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val xsShape = MaterialTheme.shapes.extraSmall
|
||||
val mdShape = MaterialTheme.shapes.medium
|
||||
|
||||
PreferenceScreen(
|
||||
title = { Text(stringResource(R.string.preference_search_appshortcuts)) },
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
item {
|
||||
Box(modifier = Modifier.padding(bottom = 10.dp)) {
|
||||
|
||||
PreferenceCategory {
|
||||
GuardedPreference(
|
||||
locked = hasPermission == false,
|
||||
onUnlock = {
|
||||
viewModel.requestAppShortcutsPermission(activity as AppCompatActivity)
|
||||
},
|
||||
description = stringResource(
|
||||
R.string.missing_permission_appshortcuts_search_settings,
|
||||
stringResource(R.string.app_name),
|
||||
),
|
||||
) {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_search_appshortcuts),
|
||||
summary = stringResource(R.string.preference_search_appshortcuts_summary),
|
||||
icon = R.drawable.mobile_arrow_up_right_24px,
|
||||
value = searchEnabled == true && hasPermission == true,
|
||||
onValueChanged = {
|
||||
viewModel.setShortcutSearchEnabled(it)
|
||||
},
|
||||
enabled = hasPermission == true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
itemsIndexed(apps) { index, app ->
|
||||
val key = "${app.componentName.packageName}:${app.user.getSerialNumber(context)}"
|
||||
Box(
|
||||
modifier = Modifier.clip(
|
||||
when {
|
||||
apps.size == 1 -> mdShape
|
||||
index == 0 -> mdShape.copy(
|
||||
bottomEnd = xsShape.bottomEnd,
|
||||
bottomStart = xsShape.bottomStart
|
||||
)
|
||||
|
||||
index == apps.size - 1 -> mdShape.copy(
|
||||
topEnd = xsShape.topEnd,
|
||||
topStart = xsShape.topStart
|
||||
)
|
||||
|
||||
else -> xsShape
|
||||
}
|
||||
)
|
||||
) {
|
||||
CheckboxPreference(
|
||||
icon = {
|
||||
val size = 32.dp
|
||||
val icon by viewModel.getIcon(app, size.toPixels().toInt())
|
||||
.collectAsStateWithLifecycle(null)
|
||||
val badge by viewModel.getBadge(app)
|
||||
.collectAsStateWithLifecycle(null)
|
||||
ShapedLauncherIcon(size = size, icon = { icon }, badge = { badge })
|
||||
},
|
||||
title = app.label,
|
||||
value = !blocklist.contains(key),
|
||||
onValueChanged = {
|
||||
viewModel.setAppBlocklisted(key, !it)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.launcher.search.filters.SearchFilters
|
||||
import de.mm20.launcher2.ui.locals.LocalBackStack
|
||||
import de.mm20.launcher2.ui.settings.apps.AppSearchSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.appshortcuts.AppShortcutsSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.calendarsearch.CalendarProviderSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.calendarsearch.CalendarSearchSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.contacts.ContactsSettingsRoute
|
||||
@@ -208,15 +209,18 @@ fun SearchSettingsScreen() {
|
||||
stringResource(R.string.app_name),
|
||||
),
|
||||
) {
|
||||
SwitchPreference(
|
||||
PreferenceWithSwitch(
|
||||
title = stringResource(R.string.preference_search_appshortcuts),
|
||||
summary = stringResource(R.string.preference_search_appshortcuts_summary),
|
||||
icon = R.drawable.mobile_arrow_up_right_24px,
|
||||
value = appShortcuts == true && hasAppShortcutsPermission == true,
|
||||
onValueChanged = {
|
||||
switchValue = appShortcuts == true && hasAppShortcutsPermission == true,
|
||||
onSwitchChanged = {
|
||||
viewModel.setAppShortcuts(it)
|
||||
},
|
||||
enabled = hasAppShortcutsPermission == true
|
||||
enabled = hasAppShortcutsPermission == true,
|
||||
onClick = {
|
||||
backStack += AppShortcutsSettingsRoute
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user