Feat: App list view (#1170)
* Feat: grid icon visibility settings and migration support * fix: remove unnecessary padding * Feat: Create List View Settings * fix FavoritesPartProvider * small fix * fix favorites * Remove useless datastore migration * Change app list default value * Revert migration 3 * Hide list icon preference if list is not enabled * Use ListResults for app list --------- Co-authored-by: MM20 <15646950+MM2-0@users.noreply.github.com>
This commit is contained in:
parent
b2cf7f5e5e
commit
2c2c88b93c
@ -13,7 +13,6 @@ import de.mm20.launcher2.widgets.FavoritesWidget
|
||||
import de.mm20.launcher2.widgets.WidgetRepository
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koin.androidx.compose.inject
|
||||
|
||||
@Composable
|
||||
|
||||
@ -64,6 +64,7 @@ fun SearchColumn(
|
||||
) {
|
||||
|
||||
val columns = LocalGridSettings.current.columnCount
|
||||
val showList = LocalGridSettings.current.showList
|
||||
val context = LocalContext.current
|
||||
|
||||
val viewModel: SearchVM = viewModel()
|
||||
@ -111,6 +112,7 @@ fun SearchColumn(
|
||||
val expandedCategory: SearchCategory? by viewModel.expandedCategory
|
||||
|
||||
var selectedAppProfileIndex: Int by remember(isSearchEmpty) { mutableIntStateOf(0) }
|
||||
var selectedAppIndex: Int by remember(website) { mutableIntStateOf(-1) }
|
||||
var selectedContactIndex: Int by remember(contacts) { mutableIntStateOf(-1) }
|
||||
var selectedFileIndex: Int by remember(files) { mutableIntStateOf(-1) }
|
||||
var selectedCalendarIndex: Int by remember(events) { mutableIntStateOf(-1) }
|
||||
@ -193,6 +195,9 @@ fun SearchColumn(
|
||||
columns = columns,
|
||||
reverse = reverse,
|
||||
showProfileLockControls = hasProfilesPermission,
|
||||
showList = showList,
|
||||
selectedIndex = selectedAppIndex,
|
||||
onSelect = { selectedAppIndex = it },
|
||||
)
|
||||
} else {
|
||||
AppResults(
|
||||
@ -202,7 +207,10 @@ fun SearchColumn(
|
||||
selectedAppProfileIndex = it
|
||||
},
|
||||
columns = columns,
|
||||
reverse = reverse
|
||||
reverse = reverse,
|
||||
showList = showList,
|
||||
selectedIndex = selectedAppIndex,
|
||||
onSelect = { selectedAppIndex = it },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SharedTransitionLayout
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.MutableTransitionState
|
||||
import androidx.compose.animation.core.tween
|
||||
@ -61,7 +62,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.IntRect
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.lerp
|
||||
import androidx.compose.ui.unit.roundToIntRect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coil.compose.AsyncImage
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
@ -85,11 +85,15 @@ import kotlinx.coroutines.launch
|
||||
fun AppItem(
|
||||
modifier: Modifier = Modifier,
|
||||
app: Application,
|
||||
showDetails: Boolean,
|
||||
onBack: () -> Unit
|
||||
) {
|
||||
val viewModel: SearchableItemVM = listItemViewModel(key = "search-${app.key}")
|
||||
val iconSize = LocalGridSettings.current.iconSize.dp.toPixels()
|
||||
|
||||
val badge by viewModel.badge.collectAsStateWithLifecycle(null)
|
||||
val icon by viewModel.icon.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(app) {
|
||||
viewModel.init(app, iconSize.toInt())
|
||||
}
|
||||
@ -97,8 +101,11 @@ fun AppItem(
|
||||
val context = LocalContext.current
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
SharedTransitionLayout(modifier = modifier) {
|
||||
AnimatedContent(showDetails) { showDetails ->
|
||||
if (showDetails) {
|
||||
Column(
|
||||
modifier = modifier.verticalScroll(rememberScrollState())
|
||||
modifier = Modifier.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Row {
|
||||
Column(
|
||||
@ -108,7 +115,12 @@ fun AppItem(
|
||||
) {
|
||||
Text(
|
||||
text = app.labelOverride ?: app.label,
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier
|
||||
.sharedBounds(
|
||||
rememberSharedContentState("label"),
|
||||
this@AnimatedContent,
|
||||
),
|
||||
)
|
||||
|
||||
if (!app.isPrivate) {
|
||||
@ -150,8 +162,6 @@ fun AppItem(
|
||||
}
|
||||
|
||||
}
|
||||
val badge by viewModel.badge.collectAsStateWithLifecycle(null)
|
||||
val icon by viewModel.icon.collectAsStateWithLifecycle()
|
||||
ShapedLauncherIcon(
|
||||
size = 48.dp,
|
||||
modifier = Modifier
|
||||
@ -183,7 +193,11 @@ fun AppItem(
|
||||
) {
|
||||
for ((i, not) in notifications.withIndex()) {
|
||||
val icon =
|
||||
remember(not.smallIcon) { not.smallIcon?.loadDrawable(context) }
|
||||
remember(not.smallIcon) {
|
||||
not.smallIcon?.loadDrawable(
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
if (not.title == null && not.text == null) continue
|
||||
|
||||
@ -195,7 +209,9 @@ fun AppItem(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
try {
|
||||
not.contentIntent?.sendWithBackgroundPermission(context)
|
||||
not.contentIntent?.sendWithBackgroundPermission(
|
||||
context
|
||||
)
|
||||
} catch (e: PendingIntent.CanceledException) {
|
||||
CrashReporter.logException(e)
|
||||
}
|
||||
@ -299,7 +315,11 @@ fun AppItem(
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
) {
|
||||
for ((i, shortcut) in shortcuts.withIndex()) {
|
||||
val isPinned by remember(shortcut) { viewModel.isChildPinned(shortcut) }.collectAsState(
|
||||
val isPinned by remember(shortcut) {
|
||||
viewModel.isChildPinned(
|
||||
shortcut
|
||||
)
|
||||
}.collectAsState(
|
||||
false
|
||||
)
|
||||
|
||||
@ -404,7 +424,8 @@ fun AppItem(
|
||||
|
||||
val sheetManager = LocalBottomSheetManager.current
|
||||
if (!app.isPrivate) {
|
||||
toolbarActions.add(DefaultToolbarAction(
|
||||
toolbarActions.add(
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_customize),
|
||||
icon = Icons.Rounded.Tune,
|
||||
action = { sheetManager.showCustomizeSearchableModal(app) }
|
||||
@ -435,9 +456,17 @@ fun AppItem(
|
||||
icon = Icons.Rounded.Link,
|
||||
action = {
|
||||
val shareIntent = Intent(Intent.ACTION_SEND)
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, storeDetails.url)
|
||||
shareIntent.putExtra(
|
||||
Intent.EXTRA_TEXT,
|
||||
storeDetails.url
|
||||
)
|
||||
shareIntent.type = "text/plain"
|
||||
context.startActivity(Intent.createChooser(shareIntent, null))
|
||||
context.startActivity(
|
||||
Intent.createChooser(
|
||||
shareIntent,
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
),
|
||||
DefaultToolbarAction(
|
||||
@ -478,6 +507,35 @@ fun AppItem(
|
||||
rightActions = toolbarActions
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (LocalGridSettings.current.showListIcons) {
|
||||
ShapedLauncherIcon(
|
||||
size = LocalGridSettings.current.iconSize.dp,
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp),
|
||||
badge = { badge },
|
||||
icon = { icon },
|
||||
)
|
||||
}
|
||||
Text(
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = app.labelOverride ?: app.label,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier
|
||||
.sharedBounds(
|
||||
rememberSharedContentState("label"),
|
||||
this@AnimatedContent,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -507,6 +565,7 @@ fun AppItemGridPopup(
|
||||
y = lerp(-16.dp, 0.dp, animationProgress)
|
||||
),
|
||||
app = app,
|
||||
showDetails = true,
|
||||
onBack = onDismiss
|
||||
)
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@ -22,9 +22,9 @@ import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LeadingIconTab
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.PrimaryScrollableTabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@ -36,6 +36,8 @@ import de.mm20.launcher2.search.Application
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.launcher.search.common.grid.GridItem
|
||||
import de.mm20.launcher2.ui.launcher.search.common.grid.GridResults
|
||||
import de.mm20.launcher2.ui.launcher.search.common.list.ListItem
|
||||
import de.mm20.launcher2.ui.launcher.search.common.list.ListResults
|
||||
import de.mm20.launcher2.ui.layout.BottomReversed
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
|
||||
@ -47,16 +49,15 @@ fun LazyListScope.AppResults(
|
||||
isProfileLocked: Boolean = false,
|
||||
onProfileLockChange: ((Profile, Boolean) -> Unit)? = null,
|
||||
apps: List<Application>,
|
||||
selectedIndex: Int,
|
||||
onSelect: (Int) -> Unit,
|
||||
highlightedItem: Application? = null,
|
||||
columns: Int,
|
||||
reverse: Boolean,
|
||||
showList: Boolean,
|
||||
) {
|
||||
|
||||
GridResults(
|
||||
key = "apps",
|
||||
items = apps,
|
||||
before = if (profiles.size > 1) {
|
||||
{
|
||||
val before = if (profiles.size > 1) {
|
||||
@Composable {
|
||||
Column(
|
||||
verticalArrangement = if (reverse) Arrangement.BottomReversed else Arrangement.Top,
|
||||
) {
|
||||
@ -102,7 +103,10 @@ fun LazyListScope.AppResults(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!showList || isProfileLocked) {
|
||||
HorizontalDivider()
|
||||
}
|
||||
|
||||
val profileType = profiles[selectedProfileIndex].type
|
||||
if (profileType != Profile.Type.Personal) {
|
||||
@ -111,8 +115,15 @@ fun LazyListScope.AppResults(
|
||||
modifier = Modifier
|
||||
.padding(12.dp)
|
||||
.fillMaxWidth()
|
||||
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, MaterialTheme.shapes.small)
|
||||
.background(MaterialTheme.colorScheme.surfaceContainer, MaterialTheme.shapes.small)
|
||||
.border(
|
||||
1.dp,
|
||||
MaterialTheme.colorScheme.outlineVariant,
|
||||
MaterialTheme.shapes.small
|
||||
)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainer,
|
||||
MaterialTheme.shapes.small
|
||||
)
|
||||
.padding(vertical = 64.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
@ -190,7 +201,30 @@ fun LazyListScope.AppResults(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else null,
|
||||
} else null
|
||||
if (showList) {
|
||||
ListResults(
|
||||
key = "apps",
|
||||
items = apps,
|
||||
before = before?.let { { it() } },
|
||||
selectedIndex = selectedIndex,
|
||||
itemContent = { app, showDetails, index ->
|
||||
ListItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
item = app,
|
||||
showDetails = showDetails,
|
||||
onShowDetails = { onSelect(if(it) index else -1) },
|
||||
highlight = highlightedItem?.key == app.key
|
||||
)
|
||||
},
|
||||
reverse = reverse,
|
||||
)
|
||||
} else {
|
||||
GridResults(
|
||||
key = "apps",
|
||||
items = apps,
|
||||
before = before,
|
||||
itemContent = {
|
||||
GridItem(
|
||||
item = it,
|
||||
@ -202,3 +236,5 @@ fun LazyListScope.AppResults(
|
||||
columns = columns,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
package de.mm20.launcher2.ui.launcher.search.common.grid
|
||||
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.MutableTransitionState
|
||||
@ -13,6 +12,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -110,6 +110,7 @@ fun GridItem(
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.padding(4.dp)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
if (!launchOnPress || !viewModel.launch(context, bounds)) {
|
||||
@ -170,7 +171,9 @@ fun GridItem(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.onGloballyPositioned {
|
||||
bounds = it.boundsInWindow().roundToIntRect()
|
||||
bounds = it
|
||||
.boundsInWindow()
|
||||
.roundToIntRect()
|
||||
} then
|
||||
if (highlight) Modifier.background(
|
||||
MaterialTheme.colorScheme.surface,
|
||||
@ -195,12 +198,12 @@ fun GridItem(
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (showPopup) {
|
||||
ItemPopup(origin = bounds, searchable = item, onDismissRequest = { showPopup = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ItemPopup(origin: IntRect, searchable: Searchable, onDismissRequest: () -> Unit) {
|
||||
@ -398,7 +401,7 @@ private fun Modifier.placeOverlay(
|
||||
constraints.maxHeight - placeable.height,
|
||||
),
|
||||
animationProgress.pow(2)
|
||||
).toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,8 +83,8 @@ fun <T : SavableSearchable> LazyListScope.GridResults(
|
||||
.padding(
|
||||
top = if (it == 0) 8.dp else 0.dp,
|
||||
bottom = if (it == rows - 1) 8.dp else 0.dp,
|
||||
start = 4.dp,
|
||||
end = 4.dp,
|
||||
start = if (columns == 1) 0.dp else 4.dp,
|
||||
end = if (columns == 1) 0.dp else 4.dp,
|
||||
)
|
||||
) {
|
||||
Row {
|
||||
@ -94,7 +94,6 @@ fun <T : SavableSearchable> LazyListScope.GridResults(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(4.dp)
|
||||
) {
|
||||
itemContent(item)
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -22,6 +23,7 @@ import androidx.compose.ui.unit.IntRect
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.roundToIntRect
|
||||
import de.mm20.launcher2.search.AppShortcut
|
||||
import de.mm20.launcher2.search.Application
|
||||
import de.mm20.launcher2.search.Article
|
||||
import de.mm20.launcher2.search.CalendarEvent
|
||||
import de.mm20.launcher2.search.Contact
|
||||
@ -30,6 +32,7 @@ import de.mm20.launcher2.search.Location
|
||||
import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.search.Website
|
||||
import de.mm20.launcher2.ui.ktx.toPixels
|
||||
import de.mm20.launcher2.ui.launcher.search.apps.AppItem
|
||||
import de.mm20.launcher2.ui.launcher.search.calendar.CalendarItem
|
||||
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
|
||||
import de.mm20.launcher2.ui.launcher.search.contacts.ContactItem
|
||||
@ -80,6 +83,25 @@ fun ListItem(
|
||||
LocalContentColor provides MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
when (item) {
|
||||
is Application -> {
|
||||
AppItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 9999.dp) // we have infinite space, but there is an inner scroll that needs a constraint
|
||||
.combinedClickable(
|
||||
enabled = !showDetails,
|
||||
onClick = {
|
||||
if (!viewModel.launch(context, bounds)) {
|
||||
onShowDetails(true)
|
||||
}
|
||||
},
|
||||
onLongClick = { onShowDetails(true) }
|
||||
),
|
||||
app = item,
|
||||
showDetails = showDetails,
|
||||
onBack = { onShowDetails(false) }
|
||||
)
|
||||
}
|
||||
is Contact -> {
|
||||
ContactItem(
|
||||
modifier = Modifier
|
||||
|
||||
@ -110,6 +110,26 @@ fun IconsSettingsScreen() {
|
||||
viewModel.setShowLabels(it)
|
||||
}
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_grid_list_style),
|
||||
summary = stringResource(R.string.preference_grid_list_style_summary),
|
||||
value = grid.showList,
|
||||
onValueChanged = {
|
||||
viewModel.setShowList(it)
|
||||
}
|
||||
)
|
||||
AnimatedVisibility(
|
||||
grid.showList
|
||||
) {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_grid_list_icons),
|
||||
summary = stringResource(R.string.preference_grid_list_icons_summary),
|
||||
value = grid.showListIcons,
|
||||
onValueChanged = {
|
||||
viewModel.setShowListIcons(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_grid_column_count),
|
||||
value = grid.columnCount,
|
||||
|
||||
@ -53,6 +53,14 @@ class IconsSettingsScreenVM(
|
||||
uiSettings.setGridShowLabels(showLabels)
|
||||
}
|
||||
|
||||
fun setShowList(showList: Boolean) {
|
||||
uiSettings.setGridShowList(showList)
|
||||
}
|
||||
|
||||
fun setShowListIcons(showIcons: Boolean) {
|
||||
uiSettings.setGridShowListIcons(showIcons)
|
||||
}
|
||||
|
||||
val iconShape = uiSettings.iconShape
|
||||
fun setIconShape(iconShape: IconShape) {
|
||||
uiSettings.setIconShape(iconShape)
|
||||
|
||||
@ -557,8 +557,12 @@
|
||||
<string name="preference_category_grid">Grid</string>
|
||||
<string name="preference_grid_icon_size">Icon size</string>
|
||||
<string name="preference_grid_column_count">Number of columns</string>
|
||||
<string name="preference_grid_list_style">Show app results in a list</string>
|
||||
<string name="preference_grid_list_icons">Show app icons in list</string>
|
||||
<string name="preference_grid_labels">Show labels</string>
|
||||
<string name="preference_grid_labels_summary">Show the app name below the icon</string>
|
||||
<string name="preference_grid_list_style_summary">Show applications in a list view instead of grid</string>
|
||||
<string name="preference_grid_list_icons_summary">Show icons in the list view</string>
|
||||
<string name="preference_screen_debug">Debug</string>
|
||||
<string name="preference_screen_debug_summary">Troubleshooting tools</string>
|
||||
<string name="preference_category_widgets">Widgets</string>
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
package de.mm20.launcher2.preferences
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.preferences.search.LocationSearchSettings
|
||||
import de.mm20.launcher2.search.SearchFilters
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class LauncherSettingsData internal constructor(
|
||||
val schemaVersion: Int = 2,
|
||||
val schemaVersion: Int = 3,
|
||||
|
||||
val uiColorScheme: ColorScheme = ColorScheme.System,
|
||||
val uiTheme: ThemeDescriptor = ThemeDescriptor.Default,
|
||||
@ -83,6 +82,8 @@ data class LauncherSettingsData internal constructor(
|
||||
val gridColumnCount: Int = 5,
|
||||
val gridIconSize: Int = 48,
|
||||
val gridLabels: Boolean = true,
|
||||
val gridList: Boolean = false,
|
||||
val gridListIcons: Boolean = true,
|
||||
|
||||
val searchBarStyle: SearchBarStyle = SearchBarStyle.Transparent,
|
||||
val searchBarColors: SearchBarColors = SearchBarColors.Auto,
|
||||
|
||||
@ -2,6 +2,7 @@ package de.mm20.launcher2.preferences
|
||||
|
||||
import androidx.datastore.core.CorruptionException
|
||||
import androidx.datastore.core.Serializer
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
@ -21,6 +22,7 @@ internal object LauncherSettingsDataSerializer : Serializer<LauncherSettingsData
|
||||
override val defaultValue: LauncherSettingsData
|
||||
get() = LauncherSettingsData(schemaVersion = 0)
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
override suspend fun readFrom(input: InputStream): LauncherSettingsData {
|
||||
try {
|
||||
return json.decodeFromStream(input)
|
||||
|
||||
@ -25,6 +25,8 @@ data class GridSettings(
|
||||
val columnCount: Int = 5,
|
||||
val iconSize: Int = 48,
|
||||
val showLabels: Boolean = true,
|
||||
val showList: Boolean = false,
|
||||
val showListIcons: Boolean = true,
|
||||
)
|
||||
|
||||
class UiSettings internal constructor(
|
||||
@ -48,6 +50,8 @@ class UiSettings internal constructor(
|
||||
get() = launcherDataStore.data.map {
|
||||
GridSettings(
|
||||
showLabels = it.gridLabels,
|
||||
showList = it.gridList,
|
||||
showListIcons = it.gridListIcons,
|
||||
iconSize = it.gridIconSize,
|
||||
columnCount = it.gridColumnCount,
|
||||
)
|
||||
@ -71,6 +75,17 @@ class UiSettings internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun setGridShowList(showList: Boolean) {
|
||||
launcherDataStore.update {
|
||||
it.copy(gridList = showList)
|
||||
}
|
||||
}
|
||||
|
||||
fun setGridShowListIcons(showIcons: Boolean) {
|
||||
launcherDataStore.update {
|
||||
it.copy(gridListIcons = showIcons)
|
||||
}
|
||||
}
|
||||
|
||||
val cardStyle
|
||||
get() = launcherDataStore.data.map {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user