From d00a183033b9973686203a2e06af5eb00a148dc3 Mon Sep 17 00:00:00 2001 From: Patryk Michalik Date: Mon, 13 Jun 2022 19:02:58 +0200 Subject: [PATCH] Rework search provider selection UI --- lawnchair/res/values/strings.xml | 2 + .../ui/preferences/DockPreferences.kt | 39 ++-- .../preferences/SearchProviderPreferences.kt | 168 ++++++++++++++++++ .../components/QsbProviderPreference.kt | 137 -------------- 4 files changed, 195 insertions(+), 151 deletions(-) create mode 100644 lawnchair/src/app/lawnchair/ui/preferences/SearchProviderPreferences.kt delete mode 100644 lawnchair/src/app/lawnchair/ui/preferences/components/QsbProviderPreference.kt diff --git a/lawnchair/res/values/strings.xml b/lawnchair/res/values/strings.xml index 3badca00a7..7f6c885f3e 100644 --- a/lawnchair/res/values/strings.xml +++ b/lawnchair/res/values/strings.xml @@ -319,4 +319,6 @@ Home Button Tap Back Button Tap %s & %s + App + Website diff --git a/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt index fdb049a010..23aebd28ac 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt @@ -16,19 +16,30 @@ package app.lawnchair.ui.preferences -import androidx.compose.animation.* import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource import androidx.navigation.NavGraphBuilder import app.lawnchair.preferences.getAdapter import app.lawnchair.preferences.preferenceManager import app.lawnchair.preferences2.preferenceManager2 -import app.lawnchair.qsb.providers.QsbSearchProviderType -import app.lawnchair.ui.preferences.components.* +import app.lawnchair.qsb.providers.QsbSearchProvider +import app.lawnchair.ui.preferences.components.DividerColumn +import app.lawnchair.ui.preferences.components.ExpandAndShrink +import app.lawnchair.ui.preferences.components.NavigationActionPreference +import app.lawnchair.ui.preferences.components.PreferenceGroup +import app.lawnchair.ui.preferences.components.PreferenceLayout +import app.lawnchair.ui.preferences.components.SliderPreference +import app.lawnchair.ui.preferences.components.SwitchPreference import com.android.launcher3.R +object DockRoutes { + const val SEARCH_PROVIDER = "searchProvider" +} + fun NavGraphBuilder.dockGraph(route: String) { - preferenceGraph(route, { DockPreferences() }) + preferenceGraph(route, { DockPreferences() }) { subRoute -> + searchProviderGraph(subRoute(DockRoutes.SEARCH_PROVIDER)) + } } @Composable @@ -55,16 +66,16 @@ fun DockPreferences() { valueRange = 0F..1F, showAsPercentage = true, ) - QsbProviderPreference() - val hotseatQsbProviderAdapter = - preferenceManager2().hotseatQsbProvider.getAdapter() - ExpandAndShrink(visible = hotseatQsbProviderAdapter.state.value.type == QsbSearchProviderType.APP_AND_WEBSITE) { - SwitchPreference( - adapter = prefs2.hotseatQsbForceWebsite.getAdapter(), - label = stringResource(R.string.always_open_website_label), - description = stringResource(R.string.always_open_website_description), - ) - } + val hotseatQsbProviderAdapter by preferenceManager2().hotseatQsbProvider.getAdapter() + NavigationActionPreference( + label = stringResource(R.string.search_provider), + destination = subRoute(DockRoutes.SEARCH_PROVIDER), + subtitle = stringResource( + id = QsbSearchProvider.values() + .first { it == hotseatQsbProviderAdapter } + .name, + ), + ) } } } diff --git a/lawnchair/src/app/lawnchair/ui/preferences/SearchProviderPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/SearchProviderPreferences.kt new file mode 100644 index 0000000000..b5d2ca7834 --- /dev/null +++ b/lawnchair/src/app/lawnchair/ui/preferences/SearchProviderPreferences.kt @@ -0,0 +1,168 @@ +package app.lawnchair.ui.preferences + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +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.unit.dp +import androidx.navigation.NavGraphBuilder +import app.lawnchair.preferences.getAdapter +import app.lawnchair.preferences2.preferenceManager2 +import app.lawnchair.qsb.providers.QsbSearchProvider +import app.lawnchair.qsb.providers.QsbSearchProviderType +import app.lawnchair.ui.preferences.components.ClickableIcon +import app.lawnchair.ui.preferences.components.DividerColumn +import app.lawnchair.ui.preferences.components.ExpandAndShrink +import app.lawnchair.ui.preferences.components.PreferenceDivider +import app.lawnchair.ui.preferences.components.PreferenceGroup +import app.lawnchair.ui.preferences.components.PreferenceLayout +import app.lawnchair.ui.preferences.components.PreferenceTemplate +import com.android.launcher3.R + +fun NavGraphBuilder.searchProviderGraph(route: String) { + preferenceGraph(route, { SearchProviderPreferences() }) +} + +@Composable +fun SearchProviderPreferences() { + val context = LocalContext.current + val adapter = preferenceManager2().hotseatQsbProvider.getAdapter() + val forceWebsiteAdapter = preferenceManager2().hotseatQsbForceWebsite.getAdapter() + PreferenceLayout(label = stringResource(R.string.search_provider)) { + PreferenceGroup { + QsbSearchProvider.values().forEach { qsbSearchProvider -> + val appInstalled = qsbSearchProvider.isDownloaded(context) + val selected = adapter.state.value == qsbSearchProvider + val hasAppAndWebsite = qsbSearchProvider.type == QsbSearchProviderType.APP_AND_WEBSITE + val showDownloadButton = qsbSearchProvider.type == QsbSearchProviderType.APP && !appInstalled + Column { + ListItem( + title = stringResource(id = qsbSearchProvider.name), + showDownloadButton = showDownloadButton, + enabled = qsbSearchProvider.type != QsbSearchProviderType.APP || appInstalled, + selected = selected, + onClick = { adapter.onChange(newValue = qsbSearchProvider) }, + onDownloadClick = { qsbSearchProvider.launchOnAppMarket(context = context) }, + description = if (showDownloadButton) { + stringResource(id = R.string.qsb_search_provider_app_required) + } else null, + ) + ExpandAndShrink(visible = selected && hasAppAndWebsite) { + Options( + appEnabled = appInstalled, + appSelected = !forceWebsiteAdapter.state.value && appInstalled, + onAppClick = { forceWebsiteAdapter.onChange(newValue = false) }, + onAppDownloadClick = { qsbSearchProvider.launchOnAppMarket(context = context) }, + onWebsiteClick = { forceWebsiteAdapter.onChange(newValue = true) }, + showAppDownloadButton = !appInstalled, + ) + } + } + } + } + } +} + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +private fun ListItem( + title: String, + description: String?, + showDownloadButton: Boolean, + enabled: Boolean, + selected: Boolean, + onClick: () -> Unit, + onDownloadClick: () -> Unit, +) { + Column { + PreferenceTemplate( + title = { Text(text = title) }, + verticalPadding = if (showDownloadButton) 12.dp else 16.dp, + horizontalPadding = 0.dp, + enabled = enabled, + modifier = Modifier.clickable(enabled = enabled, onClick = onClick), + description = { if (description != null) Text(text = description) }, + startWidget = { + RadioButton( + selected = selected, + onClick = null, + enabled = enabled, + modifier = Modifier.padding(start = 16.dp) + ) + }, + endWidget = { + if (showDownloadButton) { + ClickableIcon( + painter = painterResource(id = R.drawable.ic_download), + onClick = onDownloadClick, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(end = 4.dp), + ) + } + }, + ) + } +} + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +private fun Options( + appEnabled: Boolean, + appSelected: Boolean, + showAppDownloadButton: Boolean, + onAppClick: () -> Unit, + onAppDownloadClick: () -> Unit, + onWebsiteClick: () -> Unit, +) { + PreferenceDivider(startIndent = 40.dp) + DividerColumn(startIndent = 40.dp) { + PreferenceTemplate( + title = { Text(stringResource(id = R.string.app_label)) }, + enabled = appEnabled, + verticalPadding = if (!appEnabled) 4.dp else 16.dp, + horizontalPadding = 0.dp, + modifier = Modifier.clickable( + enabled = appEnabled, + onClick = onAppClick, + ), + startWidget = { + RadioButton( + selected = appSelected, + onClick = null, + enabled = appEnabled, + modifier = Modifier.padding(start = 56.dp), + ) + }, + endWidget = { + if (showAppDownloadButton) { + ClickableIcon( + painter = painterResource(R.drawable.ic_download), + onClick = onAppDownloadClick, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(end = 4.dp), + ) + } + }, + ) + PreferenceTemplate( + title = { Text(text = stringResource(id = R.string.website_label)) }, + modifier = Modifier.clickable(onClick = onWebsiteClick), + horizontalPadding = 0.dp, + startWidget = { + RadioButton( + selected = !appSelected, + onClick = null, + modifier = Modifier.padding(start = 56.dp), + ) + }, + ) + } +} diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/QsbProviderPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/QsbProviderPreference.kt deleted file mode 100644 index ae202fb314..0000000000 --- a/lawnchair/src/app/lawnchair/ui/preferences/components/QsbProviderPreference.kt +++ /dev/null @@ -1,137 +0,0 @@ -package app.lawnchair.ui.preferences.components - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material.RadioButton -import androidx.compose.material3.Icon -import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -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.unit.dp -import app.lawnchair.preferences.getAdapter -import app.lawnchair.preferences2.preferenceManager2 -import app.lawnchair.qsb.providers.QsbSearchProvider -import app.lawnchair.qsb.providers.QsbSearchProviderType -import app.lawnchair.ui.AlertBottomSheetContent -import app.lawnchair.ui.util.addIf -import app.lawnchair.ui.util.bottomSheetHandler -import com.android.launcher3.R - -@Composable -fun QsbProviderPreference() { - val adapter = preferenceManager2().hotseatQsbProvider.getAdapter() - val context = LocalContext.current - val entries = remember { - QsbSearchProvider.values().map { - // Enabled is true if provider type is not app or it is app & the app is installed - val enabled = it.type != QsbSearchProviderType.APP || it.isDownloaded(context) - ListPreferenceEntry(it, enabled) { stringResource(id = it.name) } - } - } - - QsbProviderListPreference( - entries = entries, - value = adapter.state.value, - onValueChange = adapter::onChange, - label = stringResource(R.string.search_provider), - ) -} - -@Composable -fun QsbProviderListPreference( - entries: List>, - value: QsbSearchProvider, - onValueChange: (QsbSearchProvider) -> Unit, - label: String, - enabled: Boolean = true, - description: String? = null, -) { - val context = LocalContext.current - - val bottomSheetHandler = bottomSheetHandler - val currentDescription = description ?: entries - .firstOrNull { it.value == value } - ?.label?.invoke() - - val paddingVertical = 16.dp - val paddingHorizontal = 16.dp - - PreferenceTemplate( - title = { Text(text = label) }, - description = { currentDescription?.let { Text(text = it) } }, - enabled = enabled, - modifier = Modifier.clickable(enabled) { - bottomSheetHandler.show { - AlertBottomSheetContent( - title = { Text(label) }, - buttons = { - OutlinedButton(onClick = { bottomSheetHandler.hide() }) { - Text(text = stringResource(id = android.R.string.cancel)) - } - } - ) { - LazyColumn { - itemsIndexed(entries) { index, item -> - if (index > 0) { - PreferenceDivider(startIndent = 40.dp) - } - PreferenceTemplate( - enabled = item.enabled, - title = { Text(item.label()) }, - description = { - if (item.value.type == QsbSearchProviderType.APP) { - Text(stringResource(id = R.string.qsb_search_provider_app_required)) - } - }, - applyPaddings = false, - modifier = Modifier - .clickable(item.enabled) { - onValueChange(item.value) - bottomSheetHandler.hide() - }, - startWidget = { - RadioButton( - modifier = Modifier.padding( - horizontal = paddingHorizontal, - vertical = paddingVertical - ), - selected = item.value == value, - onClick = null, - enabled = item.enabled, - ) - }, - endWidget = { - if (item.value.type.downloadable) { - val downloaded = item.value.isDownloaded(context) - Icon( - modifier = Modifier - .addIf(!downloaded) { - clickable { - item.value.launchOnAppMarket(context = context) - bottomSheetHandler.hide() - } - } - .padding( - horizontal = paddingHorizontal, - vertical = paddingVertical - ), - painter = painterResource(id = if (downloaded) R.drawable.ic_tick else R.drawable.ic_download), - contentDescription = null, - ) - } - } - ) - } - } - } - } - } - ) -} \ No newline at end of file