From 9f24b9b3ccbacfa2255432305157e44dba0e78eb Mon Sep 17 00:00:00 2001 From: Sad Ellie Date: Mon, 15 Jan 2024 18:23:15 +0300 Subject: [PATCH] Refactor TopLevelDestinations closes #160 closes #161 --- .../java/com/sadellie/unitto/UnittoApp.kt | 19 +-- .../unitto/core/base/TopLevelDestinations.kt | 134 ++---------------- .../ui/{Shortcuts.kt => ShortcutUtils.kt} | 66 ++++----- .../unitto/core/ui/common/UnittoDrawerItem.kt | 6 +- .../core/ui/common/UnittoNavigationDrawer.kt | 11 +- .../core/ui/common/UnittoSheetContent.kt | 23 ++- .../model/{DrawerItems.kt => DrawerItem.kt} | 84 ++++++++--- .../sadellie/unitto/core/ui/model/Shortcut.kt | 28 ++++ .../unitto/data/userprefs/PreferenceExt.kt | 2 +- .../feature/bodymass/navigation/Navigation.kt | 6 +- .../navigation/CalculatorNavigation.kt | 6 +- .../navigation/ConverterNavigation.kt | 6 +- .../navigation/DateCalculatorNavigation.kt | 6 +- .../settings/navigation/SettingsNavigation.kt | 8 +- .../startingscreen/StartingScreenScreen.kt | 59 +++----- .../timezone/navigation/TimeZoneNavigation.kt | 6 +- 16 files changed, 204 insertions(+), 266 deletions(-) rename core/ui/src/main/java/com/sadellie/unitto/core/ui/{Shortcuts.kt => ShortcutUtils.kt} (65%) rename core/ui/src/main/java/com/sadellie/unitto/core/ui/model/{DrawerItems.kt => DrawerItem.kt} (52%) create mode 100644 core/ui/src/main/java/com/sadellie/unitto/core/ui/model/Shortcut.kt diff --git a/app/src/main/java/com/sadellie/unitto/UnittoApp.kt b/app/src/main/java/com/sadellie/unitto/UnittoApp.kt index 2e7bb1de..27a6a1f1 100644 --- a/app/src/main/java/com/sadellie/unitto/UnittoApp.kt +++ b/app/src/main/java/com/sadellie/unitto/UnittoApp.kt @@ -35,11 +35,9 @@ import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.google.accompanist.systemuicontroller.rememberSystemUiController -import com.sadellie.unitto.core.base.Shortcut -import com.sadellie.unitto.core.base.TOP_LEVEL_START_ROUTES import com.sadellie.unitto.core.ui.common.UnittoNavigationDrawer import com.sadellie.unitto.core.ui.common.rememberDrawerState -import com.sadellie.unitto.core.ui.model.DrawerItems +import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.pushDynamicShortcut import com.sadellie.unitto.core.ui.theme.DarkThemeColors import com.sadellie.unitto.core.ui.theme.LightThemeColors @@ -67,7 +65,7 @@ internal fun UnittoApp(prefs: AppPreferences?) { val navBackStackEntry by navController.currentBackStackEntryAsState() val gesturesEnabled: Boolean by remember(navBackStackEntry?.destination) { derivedStateOf { - TOP_LEVEL_START_ROUTES.contains(navBackStackEntry?.destination?.route) + DrawerItem.startRoutes.contains(navBackStackEntry?.destination?.route) } } @@ -96,7 +94,7 @@ internal fun UnittoApp(prefs: AppPreferences?) { modifier = Modifier, state = drawerState, gesturesEnabled = gesturesEnabled, - tabs = DrawerItems.MAIN, + tabs = DrawerItem.main, currentDestination = navBackStackEntry?.destination?.route, onItemClick = { destination -> drawerScope.launch { drawerState.close() } @@ -109,16 +107,7 @@ internal fun UnittoApp(prefs: AppPreferences?) { restoreState = true } - shortcutsScope.launch { - destination.shortcut?.let { shortcut: Shortcut -> - mContext.pushDynamicShortcut( - destination.graph, - shortcut.shortcutShortLabel, - shortcut.shortcutLongLabel, - shortcut.shortcutDrawable - ) - } - } + shortcutsScope.launch { mContext.pushDynamicShortcut(destination) } }, content = { UnittoNavigation( diff --git a/core/base/src/main/java/com/sadellie/unitto/core/base/TopLevelDestinations.kt b/core/base/src/main/java/com/sadellie/unitto/core/base/TopLevelDestinations.kt index 5a12da5a..2ee31ccc 100644 --- a/core/base/src/main/java/com/sadellie/unitto/core/base/TopLevelDestinations.kt +++ b/core/base/src/main/java/com/sadellie/unitto/core/base/TopLevelDestinations.kt @@ -18,126 +18,18 @@ package com.sadellie.unitto.core.base -import android.os.Build -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes - // Don't touch, users have "..._route" in their settings -private const val CONVERTER_GRAPH = "converter_route" -private const val CONVERTER_START = "converter_start" - -private const val CALCULATOR_GRAPH = "calculator_route" -private const val CALCULATOR_START = "calculator_start" - -private const val DATE_CALCULATOR_GRAPH = "date_calculator_route" -private const val DATE_CALCULATOR_START = "date_calculator_start" - -private const val TIME_ZONE_GRAPH = "time_zone_route" -private const val TIME_ZONE_START = "time_zone_start" - -private const val BODY_MASS_GRAPH = "body_mass_route" -private const val BODY_MASS_START = "body_mass_start" - -private const val SETTINGS_GRAPH = "settings_route" -private const val SETTINGS_START = "settings_start" - -data class Shortcut( - @StringRes val shortcutShortLabel: Int, - @StringRes val shortcutLongLabel: Int, - @DrawableRes val shortcutDrawable: Int, -) - -sealed class TopLevelDestinations( - val graph: String, - val start: String = graph, - @StringRes val name: Int, - val shortcut: Shortcut? = null -) { - data object Converter : TopLevelDestinations( - graph = CONVERTER_GRAPH, - start = CONVERTER_START, - name = R.string.unit_converter_title, - shortcut = Shortcut( - R.string.unit_converter_title, - R.string.unit_converter_title, - R.drawable.ic_shortcut_unit_converter - ) - ) - - data object Calculator : TopLevelDestinations( - graph = CALCULATOR_GRAPH, - start = CALCULATOR_START, - name = R.string.calculator_title, - shortcut = Shortcut( - R.string.calculator_title, - R.string.calculator_title, - R.drawable.ic_shortcut_calculator - ) - ) - - data object DateCalculator : TopLevelDestinations( - graph = DATE_CALCULATOR_GRAPH, - start = DATE_CALCULATOR_START, - name = R.string.date_calculator_title, - shortcut = Shortcut( - R.string.date_calculator_title, - R.string.date_calculator_title, - R.drawable.ic_shortcut_date_calculator - ) - ) - - data object TimeZone : TopLevelDestinations( - graph = TIME_ZONE_GRAPH, - start = TIME_ZONE_START, - name = R.string.time_zone_title, - shortcut = Shortcut( - R.string.time_zone_title, - R.string.time_zone_title, - R.drawable.ic_shortcut_time_zone - ) - ) - - data object BodyMass : TopLevelDestinations( - graph = BODY_MASS_GRAPH, - start = BODY_MASS_START, - name = R.string.body_mass_title, - shortcut = Shortcut( - R.string.body_mass_title, - R.string.body_mass_title, - R.drawable.ic_shortcut_body_mass - ) - ) - - data object Settings : TopLevelDestinations( - graph = SETTINGS_GRAPH, - start = SETTINGS_START, - name = R.string.settings_title - ) -} - -// Shown in settings -val TOP_LEVEL_DESTINATIONS by lazy { - var all = listOf( - TopLevelDestinations.Calculator, - TopLevelDestinations.Converter, - TopLevelDestinations.DateCalculator, - TopLevelDestinations.TimeZone, - TopLevelDestinations.BodyMass, - ) - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - all = all - TopLevelDestinations.TimeZone - } - - all -} - -// Only routes, not graphs! -val TOP_LEVEL_START_ROUTES by lazy { - listOf( - CALCULATOR_START, - CONVERTER_START, - DATE_CALCULATOR_START, - TIME_ZONE_START, - ) +object TopLevelDestinations { + const val CONVERTER_GRAPH = "converter_route" + const val CONVERTER_START = "converter_start" + const val CALCULATOR_GRAPH = "calculator_route" + const val CALCULATOR_START = "calculator_start" + const val DATE_CALCULATOR_GRAPH = "date_calculator_route" + const val DATE_CALCULATOR_START = "date_calculator_start" + const val TIME_ZONE_GRAPH = "time_zone_route" + const val TIME_ZONE_START = "time_zone_start" + const val BODY_MASS_GRAPH = "body_mass_route" + const val BODY_MASS_START = "body_mass_start" + const val SETTINGS_GRAPH = "settings_route" + const val SETTINGS_START = "settings_start" } diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/Shortcuts.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/ShortcutUtils.kt similarity index 65% rename from core/ui/src/main/java/com/sadellie/unitto/core/ui/Shortcuts.kt rename to core/ui/src/main/java/com/sadellie/unitto/core/ui/ShortcutUtils.kt index 07cb0ed9..6d3fd141 100644 --- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/Shortcuts.kt +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/ShortcutUtils.kt @@ -23,61 +23,63 @@ import android.app.PendingIntent.FLAG_IMMUTABLE import android.content.Context import android.content.Intent import android.net.Uri -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes +import android.os.Build +import androidx.annotation.RequiresApi import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat +import com.sadellie.unitto.core.ui.model.DrawerItem +import com.sadellie.unitto.core.ui.model.Shortcut import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -// I think it makes sense to run in coroutine +/** + * Tries to push a dynamic shortcut. Does nothing if [DrawerItem.shortcut] is `null` + * + * @param drawerItem [DrawerItem] + */ suspend fun Context.pushDynamicShortcut( - route: String, - @StringRes shortLabel: Int, - @StringRes longLabel: Int, - @DrawableRes drawable: Int, + drawerItem: DrawerItem, ) = withContext(Dispatchers.IO) { - // Low chance that we WILL push the shortcut - if ((0..10).random() != 0) return@withContext - + val shortcut = drawerItem.shortcut ?: return@withContext + // Resource intensive method! val context = this@pushDynamicShortcut - val shortcut = shortcutInfoCompat( + val shortcutCompat = shortcutInfoCompat( context = context, - route = route, - shortLabel = shortLabel, - longLabel = longLabel, - drawable = drawable + route = drawerItem.graph, + shortcut = shortcut ) kotlin.runCatching { - ShortcutManagerCompat.pushDynamicShortcut(context, shortcut) + ShortcutManagerCompat.pushDynamicShortcut(context, shortcutCompat) } } +/** + * Tries to pin shortcut. Does nothing if [DrawerItem.shortcut] is `null` + * + * @param drawerItem [DrawerItem] + */ +@RequiresApi(Build.VERSION_CODES.N_MR1) fun Context.addShortcut( - route: String, - @StringRes shortLabel: Int, - @StringRes longLabel: Int, - @DrawableRes drawable: Int, + drawerItem: DrawerItem, ) { + val shortcut = drawerItem.shortcut ?: return val context = this@addShortcut - val shortcut = shortcutInfoCompat( + val shortcutCompat = shortcutInfoCompat( context = context, - route = route, - shortLabel = shortLabel, - longLabel = longLabel, - drawable = drawable + route = drawerItem.graph, + shortcut = shortcut ) - val shortCutIntent = ShortcutManagerCompat.createShortcutResultIntent(context, shortcut) + val shortCutIntent = ShortcutManagerCompat.createShortcutResultIntent(context, shortcutCompat) try { ShortcutManagerCompat.requestPinShortcut( context, - shortcut, + shortcutCompat, PendingIntent.getBroadcast(context, 0, shortCutIntent, FLAG_IMMUTABLE).intentSender ) } catch (e: Exception) { @@ -88,14 +90,12 @@ fun Context.addShortcut( private fun Context.shortcutInfoCompat( context: Context, route: String, - shortLabel: Int, - longLabel: Int, - drawable: Int, + shortcut: Shortcut, ): ShortcutInfoCompat { return ShortcutInfoCompat.Builder(context, route) - .setShortLabel(getString(shortLabel)) - .setLongLabel(getString(longLabel)) - .setIcon(IconCompat.createWithResource(context, drawable)) + .setShortLabel(getString(shortcut.shortcutShortLabel)) + .setLongLabel(getString(shortcut.shortcutLongLabel)) + .setIcon(IconCompat.createWithResource(context, shortcut.shortcutDrawable)) .setIntent( Intent( Intent.ACTION_VIEW, diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoDrawerItem.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoDrawerItem.kt index 15375324..784fd688 100644 --- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoDrawerItem.kt +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoDrawerItem.kt @@ -25,15 +25,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource -import com.sadellie.unitto.core.base.TopLevelDestinations +import com.sadellie.unitto.core.ui.model.DrawerItem @Composable internal fun UnittoDrawerItem( modifier: Modifier = Modifier, - destination: TopLevelDestinations, + destination: DrawerItem, icon: ImageVector, selected: Boolean, - onClick: (TopLevelDestinations) -> Unit + onClick: (DrawerItem) -> Unit ) { NavigationDrawerItem( modifier = modifier, diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoNavigationDrawer.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoNavigationDrawer.kt index 729c1f4b..50d24af3 100644 --- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoNavigationDrawer.kt +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoNavigationDrawer.kt @@ -58,10 +58,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.core.ui.LocalWindowSize import com.sadellie.unitto.core.ui.WindowWidthSizeClass -import com.sadellie.unitto.core.ui.model.DrawerItems +import com.sadellie.unitto.core.ui.model.DrawerItem import kotlinx.coroutines.launch import kotlin.math.roundToInt @@ -112,9 +111,9 @@ fun UnittoNavigationDrawer( modifier: Modifier, gesturesEnabled: Boolean, state: DrawerState = rememberDrawerState(), - tabs: List, + tabs: List, currentDestination: String?, - onItemClick: (TopLevelDestinations) -> Unit, + onItemClick: (DrawerItem) -> Unit, content: @Composable () -> Unit, ) { if (LocalWindowSize.current.widthSizeClass == WindowWidthSizeClass.Expanded) { @@ -280,8 +279,8 @@ private fun PreviewUnittoModalNavigationDrawerClose() { modifier = Modifier, state = drawerState, gesturesEnabled = true, - tabs = DrawerItems.MAIN, - currentDestination = DrawerItems.Calculator.destination.start, + tabs = DrawerItem.main, + currentDestination = DrawerItem.Calculator.start, onItemClick = {}, content = { Column { diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoSheetContent.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoSheetContent.kt index 7bc0c259..5a1af11f 100644 --- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoSheetContent.kt +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoSheetContent.kt @@ -39,18 +39,17 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.sadellie.unitto.core.base.R -import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.core.ui.LocalWindowSize import com.sadellie.unitto.core.ui.WindowHeightSizeClass -import com.sadellie.unitto.core.ui.model.DrawerItems +import com.sadellie.unitto.core.ui.model.DrawerItem import kotlinx.coroutines.delay @Suppress("UnusedReceiverParameter") @Composable internal fun ColumnScope.SheetContent( - tabs: List, + tabs: List, currentDestination: String?, - onItemClick: (TopLevelDestinations) -> Unit, + onItemClick: (DrawerItem) -> Unit, ) { var showHello by remember { mutableStateOf(false) } val interactionSource = remember { @@ -81,10 +80,10 @@ internal fun ColumnScope.SheetContent( } tabs.forEach { drawerItem -> - val selected = drawerItem.destination.start == currentDestination + val selected = drawerItem.start == currentDestination UnittoDrawerItem( modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding), - destination = drawerItem.destination, + destination = drawerItem, icon = if (selected) drawerItem.selectedIcon else drawerItem.defaultIcon, selected = selected, onClick = onItemClick @@ -97,8 +96,8 @@ internal fun ColumnScope.SheetContent( UnittoDrawerItem( modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding), - destination = DrawerItems.Settings.destination, - icon = DrawerItems.Settings.defaultIcon, + destination = DrawerItem.Settings, + icon = DrawerItem.Settings.defaultIcon, selected = false, onClick = onItemClick ) @@ -111,11 +110,11 @@ private fun PreviewUnittoDrawerSheet() { Column { SheetContent( tabs = listOf( - DrawerItems.Calculator, - DrawerItems.Calculator, - DrawerItems.Calculator, + DrawerItem.Calculator, + DrawerItem.Calculator, + DrawerItem.Calculator, ), - currentDestination = DrawerItems.Calculator.destination.start, + currentDestination = DrawerItem.Calculator.start, onItemClick = {} ) } diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/model/DrawerItems.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/model/DrawerItem.kt similarity index 52% rename from core/ui/src/main/java/com/sadellie/unitto/core/ui/model/DrawerItems.kt rename to core/ui/src/main/java/com/sadellie/unitto/core/ui/model/DrawerItem.kt index 5dfca5ab..3a15dc97 100644 --- a/core/ui/src/main/java/com/sadellie/unitto/core/ui/model/DrawerItems.kt +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/model/DrawerItem.kt @@ -19,15 +19,14 @@ package com.sadellie.unitto.core.ui.model import android.os.Build +import androidx.annotation.StringRes import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Accessibility import androidx.compose.material.icons.filled.AccessibilityNew import androidx.compose.material.icons.filled.Calculate import androidx.compose.material.icons.filled.Event import androidx.compose.material.icons.filled.Schedule import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.SwapHoriz -import androidx.compose.material.icons.outlined.Accessibility import androidx.compose.material.icons.outlined.AccessibilityNew import androidx.compose.material.icons.outlined.Calculate import androidx.compose.material.icons.outlined.Event @@ -35,60 +34,102 @@ import androidx.compose.material.icons.outlined.Schedule import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.SwapHoriz import androidx.compose.ui.graphics.vector.ImageVector +import com.sadellie.unitto.core.base.R import com.sadellie.unitto.core.base.TopLevelDestinations -sealed class DrawerItems( - val destination: TopLevelDestinations, +sealed class DrawerItem( + val graph: String, + val start: String, + @StringRes val name: Int, + val shortcut: Shortcut?, val selectedIcon: ImageVector, val defaultIcon: ImageVector ) { - data object Calculator : DrawerItems( - destination = TopLevelDestinations.Calculator, + data object Calculator : DrawerItem( + graph = TopLevelDestinations.CALCULATOR_GRAPH, + start = TopLevelDestinations.CALCULATOR_START, + name = R.string.calculator_title, + shortcut = Shortcut( + R.string.calculator_title, + R.string.calculator_title, + R.drawable.ic_shortcut_calculator + ), selectedIcon = Icons.Filled.Calculate, defaultIcon = Icons.Outlined.Calculate ) - data object Converter : DrawerItems( - destination = TopLevelDestinations.Converter, + data object Converter : DrawerItem( + graph = TopLevelDestinations.CONVERTER_GRAPH, + start = TopLevelDestinations.CONVERTER_START, + name = R.string.unit_converter_title, + shortcut = Shortcut( + R.string.unit_converter_title, + R.string.unit_converter_title, + R.drawable.ic_shortcut_unit_converter + ), selectedIcon = Icons.Filled.SwapHoriz, defaultIcon = Icons.Outlined.SwapHoriz ) - data object DateDifference : DrawerItems( - destination = TopLevelDestinations.DateCalculator, + data object DateCalculator : DrawerItem( + graph = TopLevelDestinations.DATE_CALCULATOR_GRAPH, + start = TopLevelDestinations.DATE_CALCULATOR_START, + name = R.string.date_calculator_title, + shortcut = Shortcut( + R.string.date_calculator_title, + R.string.date_calculator_title, + R.drawable.ic_shortcut_date_calculator + ), selectedIcon = Icons.Filled.Event, defaultIcon = Icons.Outlined.Event ) - data object TimeZones : DrawerItems( - destination = TopLevelDestinations.TimeZone, + data object TimeZones : DrawerItem( + graph = TopLevelDestinations.TIME_ZONE_GRAPH, + start = TopLevelDestinations.TIME_ZONE_START, + name = R.string.time_zone_title, + shortcut = Shortcut( + R.string.time_zone_title, + R.string.time_zone_title, + R.drawable.ic_shortcut_time_zone + ), selectedIcon = Icons.Filled.Schedule, defaultIcon = Icons.Outlined.Schedule ) - data object BodyMass : DrawerItems( - destination = TopLevelDestinations.BodyMass, + data object BodyMass : DrawerItem( + graph = TopLevelDestinations.BODY_MASS_GRAPH, + start = TopLevelDestinations.BODY_MASS_START, + name = R.string.body_mass_title, + shortcut = Shortcut( + R.string.body_mass_title, + R.string.body_mass_title, + R.drawable.ic_shortcut_body_mass + ), selectedIcon = Icons.Filled.AccessibilityNew, defaultIcon = Icons.Outlined.AccessibilityNew ) - data object Settings : DrawerItems( - destination = TopLevelDestinations.Settings, + data object Settings : DrawerItem( + graph = TopLevelDestinations.SETTINGS_GRAPH, + start = TopLevelDestinations.SETTINGS_START, + name = R.string.settings_title, + shortcut = null, selectedIcon = Icons.Filled.Settings, defaultIcon = Icons.Outlined.Settings ) companion object { /** - * Excluding Settings tab since it appears only for expanded layout + * Except for [Settings] */ - val MAIN by lazy { + val main by lazy { var all = listOf( Calculator, Converter, - DateDifference, + DateCalculator, TimeZones, - BodyMass + BodyMass, ) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { @@ -97,5 +138,8 @@ sealed class DrawerItems( all } + + // Only routes, not graphs! + val startRoutes by lazy { main.map { it.start } } } } diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/model/Shortcut.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/model/Shortcut.kt new file mode 100644 index 00000000..cc343bce --- /dev/null +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/model/Shortcut.kt @@ -0,0 +1,28 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2024 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.core.ui.model + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes + +data class Shortcut( + @StringRes val shortcutShortLabel: Int, + @StringRes val shortcutLongLabel: Int, + @DrawableRes val shortcutDrawable: Int, +) diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt index b5e1c751..3b12a7c7 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/PreferenceExt.kt @@ -48,7 +48,7 @@ fun Preferences.getMonetMode(): String { } fun Preferences.getStartingScreen(): String { - return this[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.Calculator.graph + return this[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.CALCULATOR_GRAPH } fun Preferences.getEnableToolsExperiment(): Boolean { diff --git a/feature/bodymass/src/main/java/com/sadellie/unitto/feature/bodymass/navigation/Navigation.kt b/feature/bodymass/src/main/java/com/sadellie/unitto/feature/bodymass/navigation/Navigation.kt index 660e6064..67dade91 100644 --- a/feature/bodymass/src/main/java/com/sadellie/unitto/feature/bodymass/navigation/Navigation.kt +++ b/feature/bodymass/src/main/java/com/sadellie/unitto/feature/bodymass/navigation/Navigation.kt @@ -20,13 +20,13 @@ package com.sadellie.unitto.feature.bodymass.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.navDeepLink -import com.sadellie.unitto.core.base.TopLevelDestinations +import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.unittoComposable import com.sadellie.unitto.core.ui.unittoNavigation import com.sadellie.unitto.feature.bodymass.BodyMassRoute -private val graph = TopLevelDestinations.BodyMass.graph -private val start = TopLevelDestinations.BodyMass.start +private val graph = DrawerItem.BodyMass.graph +private val start = DrawerItem.BodyMass.start fun NavGraphBuilder.bodyMassGraph( openDrawer: () -> Unit, diff --git a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt index fbabfcc5..e66822b9 100644 --- a/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt +++ b/feature/calculator/src/main/java/com/sadellie/unitto/feature/calculator/navigation/CalculatorNavigation.kt @@ -20,14 +20,14 @@ package com.sadellie.unitto.feature.calculator.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.navDeepLink -import com.sadellie.unitto.core.base.TopLevelDestinations +import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.unittoComposable import com.sadellie.unitto.core.ui.unittoNavigation import com.sadellie.unitto.feature.calculator.CalculatorRoute import com.sadellie.unitto.feature.calculator.RPNCalculatorRoute -private val graph = TopLevelDestinations.Calculator.graph -private val start = TopLevelDestinations.Calculator.start +private val graph = DrawerItem.Calculator.graph +private val start = DrawerItem.Calculator.start fun NavGraphBuilder.calculatorGraph( rpnMode: Boolean, diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/navigation/ConverterNavigation.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/navigation/ConverterNavigation.kt index 9a6904b1..a90c77e1 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/navigation/ConverterNavigation.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/navigation/ConverterNavigation.kt @@ -23,7 +23,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.navDeepLink -import com.sadellie.unitto.core.base.TopLevelDestinations +import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.unittoComposable import com.sadellie.unitto.core.ui.unittoNavigation import com.sadellie.unitto.feature.converter.ConverterRoute @@ -31,8 +31,8 @@ import com.sadellie.unitto.feature.converter.ConverterViewModel import com.sadellie.unitto.feature.converter.LeftSideRoute import com.sadellie.unitto.feature.converter.RightSideRoute -private val graph = TopLevelDestinations.Converter.graph -private val start = TopLevelDestinations.Converter.start +private val graph = DrawerItem.Converter.graph +private val start = DrawerItem.Converter.start private const val LEFT = "left" private const val RIGHT = "right" diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/navigation/DateCalculatorNavigation.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/navigation/DateCalculatorNavigation.kt index 3db5e215..2cf43b54 100644 --- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/navigation/DateCalculatorNavigation.kt +++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/navigation/DateCalculatorNavigation.kt @@ -20,13 +20,13 @@ package com.sadellie.unitto.feature.datecalculator.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.navDeepLink -import com.sadellie.unitto.core.base.TopLevelDestinations +import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.unittoComposable import com.sadellie.unitto.core.ui.unittoNavigation import com.sadellie.unitto.feature.datecalculator.DateCalculatorRoute -private val graph = TopLevelDestinations.DateCalculator.graph -private val start = TopLevelDestinations.DateCalculator.start +private val graph = DrawerItem.DateCalculator.graph +private val start = DrawerItem.DateCalculator.start fun NavGraphBuilder.dateCalculatorGraph( navigateToMenu: () -> Unit, diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt index 4d3d702d..bb7deed7 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/navigation/SettingsNavigation.kt @@ -22,7 +22,7 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.navDeepLink -import com.sadellie.unitto.core.base.TopLevelDestinations +import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.unittoNavigation import com.sadellie.unitto.core.ui.unittoStackedComposable import com.sadellie.unitto.feature.settings.SettingsRoute @@ -37,8 +37,8 @@ import com.sadellie.unitto.feature.settings.thirdparty.ThirdPartyLicensesScreen import com.sadellie.unitto.feature.settings.unitgroups.UnitGroupsScreen import io.github.sadellie.themmo.ThemmoController -private val graph = TopLevelDestinations.Settings.graph -private val start = TopLevelDestinations.Settings.start +private val graph = DrawerItem.Settings.graph +private val start = DrawerItem.Settings.start internal const val displayRoute = "display_route" internal const val languageRoute = "language_route" internal const val startingScreenRoute = "starting_screen_route" @@ -50,7 +50,7 @@ internal const val calculatorSettingsRoute = "calculator_settings_route" internal const val converterSettingsRoute = "converter_settings_route" fun NavController.navigateToSettings() { - navigate(TopLevelDestinations.Settings.start) + navigate(DrawerItem.Settings.start) } fun NavController.navigateToUnitGroups() { diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/startingscreen/StartingScreenScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/startingscreen/StartingScreenScreen.kt index 0dbb9b28..183d76ef 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/startingscreen/StartingScreenScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/startingscreen/StartingScreenScreen.kt @@ -21,6 +21,7 @@ package com.sadellie.unitto.feature.settings.startingscreen import android.os.Build import androidx.compose.foundation.clickable import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AppShortcut import androidx.compose.material3.Icon @@ -35,14 +36,12 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.sadellie.unitto.core.base.R -import com.sadellie.unitto.core.base.Shortcut -import com.sadellie.unitto.core.base.TOP_LEVEL_DESTINATIONS -import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.core.ui.addShortcut import com.sadellie.unitto.core.ui.common.NavigateUpButton import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen import com.sadellie.unitto.core.ui.common.UnittoListItem import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar +import com.sadellie.unitto.core.ui.model.DrawerItem @Composable internal fun StartingScreenRoute( @@ -74,40 +73,28 @@ private fun StartingScreenScreen( navigationIcon = { NavigateUpButton(navigateUp) } ) { padding -> LazyColumn(contentPadding = padding) { + items(DrawerItem.main, { it.graph }) { destination -> + UnittoListItem( + modifier = Modifier.clickable { updateStartingScreen(destination.graph) }, + headlineContent = { + Text(stringResource(destination.name)) + }, + leadingContent = { + RadioButton( + selected = destination.graph == startingScreen, + onClick = { updateStartingScreen(destination.graph) } + ) + }, + trailingContent = trail@{ + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return@trail - TOP_LEVEL_DESTINATIONS.forEach { destination -> - item { - UnittoListItem( - modifier = Modifier.clickable { updateStartingScreen(destination.graph) }, - headlineContent = { - Text(stringResource(destination.name)) - }, - leadingContent = { - RadioButton( - selected = destination.graph == startingScreen, - onClick = { updateStartingScreen(destination.graph) } - ) - }, - trailingContent = { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - IconButton( - onClick = { - destination.shortcut?.let { shortcut: Shortcut -> - mContext.addShortcut( - destination.graph, - shortcut.shortcutShortLabel, - shortcut.shortcutLongLabel, - shortcut.shortcutDrawable - ) - } - } - ) { - Icon(Icons.Default.AppShortcut, null) - } - } + IconButton( + onClick = { mContext.addShortcut(destination) } + ) { + Icon(Icons.Default.AppShortcut, null) } - ) - } + } + ) } } } @@ -117,7 +104,7 @@ private fun StartingScreenScreen( @Composable private fun StartingScreenPreview() { StartingScreenScreen( - startingScreen = TopLevelDestinations.Converter.graph, + startingScreen = DrawerItem.Converter.graph, updateStartingScreen = {}, navigateUp = {} ) diff --git a/feature/timezone/src/main/java/com/sadellie/unitto/feature/timezone/navigation/TimeZoneNavigation.kt b/feature/timezone/src/main/java/com/sadellie/unitto/feature/timezone/navigation/TimeZoneNavigation.kt index 0d15f5d1..f0cb340c 100644 --- a/feature/timezone/src/main/java/com/sadellie/unitto/feature/timezone/navigation/TimeZoneNavigation.kt +++ b/feature/timezone/src/main/java/com/sadellie/unitto/feature/timezone/navigation/TimeZoneNavigation.kt @@ -25,8 +25,8 @@ import androidx.navigation.NavHostController import androidx.navigation.NavType import androidx.navigation.navArgument import androidx.navigation.navDeepLink -import com.sadellie.unitto.core.base.TopLevelDestinations import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen +import com.sadellie.unitto.core.ui.model.DrawerItem import com.sadellie.unitto.core.ui.unittoComposable import com.sadellie.unitto.core.ui.unittoNavigation import com.sadellie.unitto.feature.timezone.AddTimeZoneRoute @@ -34,8 +34,8 @@ import com.sadellie.unitto.feature.timezone.TimeZoneRoute import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -private val graph = TopLevelDestinations.TimeZone.graph -private val start = TopLevelDestinations.TimeZone.start +private val graph = DrawerItem.TimeZones.graph +private val start = DrawerItem.TimeZones.start private const val ADD_TIME_ZONE_ROUTE = "ADD_TIME_ZONE_ROUTE" private const val USER_TIME_ARG = "USER_TIME_ARG"