mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-11 14:54:00 +00:00
Rework search provider selection UI
This commit is contained in:
@@ -319,4 +319,6 @@
|
||||
<string name="gesture_home_tap">Home Button Tap</string>
|
||||
<string name="gesture_back_tap">Back Button Tap</string>
|
||||
<string name="x_and_y">%s & %s</string>
|
||||
<string name="app_label">App</string>
|
||||
<string name="website_label">Website</string>
|
||||
</resources>
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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<ListPreferenceEntry<QsbSearchProvider>>,
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user