diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index bf9dc86b..97b16574 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -470,6 +470,7 @@ This app is free software. Licensed under the GNU General Public License 3.0 Grid + Icon size Number of columns Debug Troubleshooting tools diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt index 01ca27ec..2a5d7bee 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt @@ -6,10 +6,7 @@ import androidx.datastore.core.DataStore import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler import androidx.datastore.dataStore import de.mm20.launcher2.crashreporter.CrashReporter -import de.mm20.launcher2.preferences.migrations.FactorySettingsMigration -import de.mm20.launcher2.preferences.migrations.Migration_1_2 -import de.mm20.launcher2.preferences.migrations.Migration_2_3 -import de.mm20.launcher2.preferences.migrations.Migration_3_4 +import de.mm20.launcher2.preferences.migrations.* typealias LauncherDataStore = DataStore @@ -22,6 +19,7 @@ internal val Context.dataStore: LauncherDataStore by dataStore( Migration_1_2(), Migration_2_3(), Migration_3_4(), + Migration_4_5(), ) }, corruptionHandler = ReplaceFileCorruptionHandler { @@ -31,4 +29,4 @@ internal val Context.dataStore: LauncherDataStore by dataStore( } ) -internal const val SchemaVersion = 4 \ No newline at end of file +internal const val SchemaVersion = 5 \ No newline at end of file diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt index e36cca44..fc1f6eb8 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt @@ -109,6 +109,7 @@ fun createFactorySettings(context: Context): Settings { .setGrid( Settings.GridSettings.newBuilder() .setColumnCount(context.resources.getInteger(R.integer.config_columnCount)) + .setIconSize(48) .build() ) .setSearchBar( diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_4_5.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_4_5.kt new file mode 100644 index 00000000..23fa9f64 --- /dev/null +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_4_5.kt @@ -0,0 +1,13 @@ +package de.mm20.launcher2.preferences.migrations + +import de.mm20.launcher2.preferences.Settings + +class Migration_4_5: VersionedMigration(4, 5) { + override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder { + return builder.setGrid( + builder.grid.toBuilder() + .setIconSize(48) + .build() + ) + } +} \ No newline at end of file diff --git a/preferences/src/main/proto/settings.proto b/preferences/src/main/proto/settings.proto index d8ad4f38..6d7e52d0 100644 --- a/preferences/src/main/proto/settings.proto +++ b/preferences/src/main/proto/settings.proto @@ -127,6 +127,7 @@ message Settings { message GridSettings { uint32 column_count = 1; + uint32 icon_size = 2; } GridSettings grid = 19; diff --git a/ui/src/main/java/de/mm20/launcher2/ui/base/ProvideSettings.kt b/ui/src/main/java/de/mm20/launcher2/ui/base/ProvideSettings.kt index 702dd79e..622aad82 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/base/ProvideSettings.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/base/ProvideSettings.kt @@ -1,12 +1,14 @@ package de.mm20.launcher2.ui.base import androidx.compose.runtime.* +import androidx.compose.ui.unit.dp import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.Settings import de.mm20.launcher2.ui.component.ProvideIconShape import de.mm20.launcher2.ui.locals.LocalCardStyle import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled import de.mm20.launcher2.ui.locals.LocalGridColumns +import de.mm20.launcher2.ui.locals.LocalGridIconSize import de.mm20.launcher2.widgets.WidgetRepository import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -44,10 +46,15 @@ fun ProvideSettings( dataStore.data.map { it.grid.columnCount }.distinctUntilChanged() }.collectAsState(5) + val gridIconSize by remember { + dataStore.data.map { it.grid.iconSize.dp }.distinctUntilChanged() + }.collectAsState(48.dp) + CompositionLocalProvider( LocalCardStyle provides cardStyle, LocalFavoritesEnabled provides favoritesEnabled, LocalGridColumns provides gridColumns, + LocalGridIconSize provides gridIconSize, ) { ProvideIconShape(iconShape) { content() diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt index f250ebf6..5e63595e 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/apps/AppItem.kt @@ -26,6 +26,7 @@ import de.mm20.launcher2.ui.component.* import de.mm20.launcher2.ui.ktx.toDp import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled +import de.mm20.launcher2.ui.locals.LocalGridIconSize import de.mm20.launcher2.ui.modifier.scale import kotlinx.coroutines.launch import kotlin.math.min @@ -321,7 +322,7 @@ fun AppItemGridPopup( modifier = Modifier .fillMaxWidth() .scale( - 1 - (1 - 48.dp / 84.dp) * (1 - animationProgress), + 1 - (1 - LocalGridIconSize.current / 84.dp) * (1 - animationProgress), transformOrigin = TransformOrigin(1f, 0f) ) .offset( diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt index de4b8bed..0581a383 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt @@ -35,8 +35,10 @@ import de.mm20.launcher2.ui.launcher.search.files.FileItemGridPopup import de.mm20.launcher2.ui.launcher.search.shortcut.ShortcutItemGridPopup import de.mm20.launcher2.ui.launcher.search.website.WebsiteItemGridPopup import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaItemGridPopup +import de.mm20.launcher2.ui.locals.LocalGridIconSize import de.mm20.launcher2.ui.locals.LocalWindowPosition import kotlinx.coroutines.delay +import kotlin.math.pow @OptIn(ExperimentalFoundationApi::class) @@ -49,7 +51,7 @@ fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolea var bounds by remember { mutableStateOf(Rect.Zero) } Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { val badge by viewModel.badge.collectAsState(null) - val iconSize = 48.dp.toPixels() + val iconSize = LocalGridIconSize.current.toPixels() val icon by remember(item.key) { viewModel.getIcon(iconSize.toInt()) }.collectAsState(null) // If item is one of these types, try to launch them on click; show details otherwise @@ -61,7 +63,7 @@ fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolea .onGloballyPositioned { bounds = it.boundsInWindow() }, - size = 48.dp, + size = LocalGridIconSize.current, badge = badge, icon = icon, onClick = { diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/contacts/ContactItem.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/contacts/ContactItem.kt index 275f1783..1d9a39f8 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/contacts/ContactItem.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/contacts/ContactItem.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -34,6 +35,8 @@ import de.mm20.launcher2.ui.icons.WhatsApp import de.mm20.launcher2.ui.ktx.toDp import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled +import de.mm20.launcher2.ui.locals.LocalGridIconSize +import de.mm20.launcher2.ui.modifier.scale @OptIn(ExperimentalUnitApi::class) @Composable @@ -306,6 +309,10 @@ fun ContactItemGridPopup( ContactItem( modifier = Modifier .fillMaxWidth() + .scale( + 1 - (1 - LocalGridIconSize.current / 48.dp) * (1 - animationProgress), + transformOrigin = TransformOrigin(0f, 0f) + ) .offset( x = -16.dp * (1 - animationProgress), y = -16.dp * (1 - animationProgress) diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/files/FileItem.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/files/FileItem.kt index 3320da68..bca07a90 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/files/FileItem.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/files/FileItem.kt @@ -16,6 +16,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -31,6 +32,8 @@ import de.mm20.launcher2.ui.component.ToolbarAction import de.mm20.launcher2.ui.ktx.toDp import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled +import de.mm20.launcher2.ui.locals.LocalGridIconSize +import de.mm20.launcher2.ui.modifier.scale import java.text.DecimalFormat import kotlin.math.roundToInt @@ -279,6 +282,10 @@ fun FileItemGridPopup( FileItem( modifier = Modifier .fillMaxWidth() + .scale( + 1 - (1 - LocalGridIconSize.current / 48.dp) * (1 - animationProgress), + transformOrigin = TransformOrigin(1f, 0f) + ) .offset( x = 16.dp * (1 - animationProgress), y = -16.dp * (1 - animationProgress) diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItem.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItem.kt index db5a8a01..5200f8fb 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItem.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItem.kt @@ -30,6 +30,7 @@ import de.mm20.launcher2.ui.component.ToolbarAction import de.mm20.launcher2.ui.ktx.toDp import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled +import de.mm20.launcher2.ui.locals.LocalGridIconSize import de.mm20.launcher2.ui.modifier.scale import kotlin.math.pow import kotlin.math.roundToInt @@ -189,7 +190,7 @@ fun ShortcutItemGridPopup( modifier = Modifier .fillMaxWidth() .scale( - 1 - (1 - 48.dp / 84.dp) * (1 - animationProgress), + 1 - (1 - LocalGridIconSize.current / 84.dp) * (1 - animationProgress), transformOrigin = TransformOrigin(1f, 0f) ) .offset( diff --git a/ui/src/main/java/de/mm20/launcher2/ui/locals/CompositionLocals.kt b/ui/src/main/java/de/mm20/launcher2/ui/locals/CompositionLocals.kt index a2d9da68..1641b915 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/locals/CompositionLocals.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/locals/CompositionLocals.kt @@ -4,6 +4,7 @@ import android.appwidget.AppWidgetHost import androidx.compose.runtime.compositionLocalOf import androidx.compose.ui.geometry.Size import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import androidx.navigation.NavController import de.mm20.launcher2.preferences.Settings @@ -19,6 +20,8 @@ val LocalFavoritesEnabled = compositionLocalOf { true } val LocalGridColumns = compositionLocalOf { 5 } +val LocalGridIconSize = compositionLocalOf { 48.dp } + /** * Workaround a bug in Jetpack Compose which incorrectly places popups * that are nested inside other popups. diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt index 1cd4de43..764eda39 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt @@ -85,6 +85,17 @@ fun AppearanceSettingsScreen() { ) } PreferenceCategory(title = stringResource(R.string.preference_category_grid)) { + val iconSize by viewModel.iconSize.observeAsState(48) + SliderPreference( + title = stringResource(R.string.preference_grid_icon_size), + value = iconSize, + step = 8, + min = 32, + max = 64, + onValueChanged = { + viewModel.setIconSize(it) + } + ) val columnCount by viewModel.columnCount.observeAsState(5) SliderPreference( title = stringResource(R.string.preference_grid_column_count), diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt index f27e214d..e350235f 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt @@ -54,6 +54,17 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent { } } + val iconSize = dataStore.data.map { it.grid.iconSize }.asLiveData() + fun setIconSize(iconSize: Int) { + viewModelScope.launch { + dataStore.updateData { + it.toBuilder() + .setGrid(it.grid.toBuilder().setIconSize(iconSize)) + .build() + } + } + } + val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }.asLiveData() fun setDimWallpaper(dimWallpaper: Boolean) { viewModelScope.launch {