Dynamic random shortcuts

This commit is contained in:
sadellie 2023-08-03 13:13:50 +03:00
parent 7ca5274e2e
commit a0c0997c50
11 changed files with 252 additions and 12 deletions

View File

@ -0,0 +1,59 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
// I think it makes sense to run in coroutine
suspend fun Context.pushDynamicShortcut(
route: String,
@StringRes shortLabel: Int,
@StringRes longLabel: Int,
@DrawableRes drawable: Int,
) = withContext(Dispatchers.IO) {
// Low chance that we WILL push the shortcut
if ((0..10).random() != 0) return@withContext
val context = this@pushDynamicShortcut
val shortcut = ShortcutInfoCompat.Builder(context, route)
.setShortLabel(getString(shortLabel))
.setLongLabel(getString(longLabel))
.setIcon(IconCompat.createWithResource(context, drawable))
.setIntent(
Intent(
Intent.ACTION_VIEW,
Uri.parse("app://com.sadellie.unitto/$route"),
context,
this.javaClass
)
)
.build()
ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
}

View File

@ -32,10 +32,12 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.platform.LocalContext
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.UnittoDrawerSheet
import com.sadellie.unitto.core.ui.common.UnittoModalNavigationDrawer
@ -56,6 +58,7 @@ import kotlinx.coroutines.launch
@Composable
internal fun UnittoApp(uiPrefs: UIPreferences) {
val mContext = LocalContext.current
val themmoController = rememberThemmoController(
lightColorScheme = LightThemeColors,
darkColorScheme = DarkThemeColors,
@ -71,6 +74,9 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
// Navigation drawer stuff
val drawerState = rememberUnittoDrawerState()
val drawerScope = rememberCoroutineScope()
val shortcutsScope = rememberCoroutineScope()
val mainTabs by remember(uiPrefs.enableToolsExperiment) {
derivedStateOf {
if (uiPrefs.enableToolsExperiment) {
@ -110,15 +116,27 @@ internal fun UnittoApp(uiPrefs: UIPreferences) {
mainTabs = mainTabs,
additionalTabs = additionalTabs,
currentDestination = navBackStackEntry?.destination?.route
) {
) { destination ->
drawerScope.launch { drawerState.close() }
navController.navigate(it) {
navController.navigate(destination.graph) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
shortcutsScope.launch {
destination.shortcut?.let { shortcut: Shortcut ->
mContext.pushDynamicShortcut(
destination.graph,
shortcut.shortcutShortLabel,
shortcut.shortcutLongLabel,
shortcut.shortcutDrawable
)
}
}
}
},
modifier = Modifier,

View File

@ -18,6 +18,7 @@
package com.sadellie.unitto.core.base
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
// Don't touch, users have "..._route" in their settings
@ -36,33 +37,60 @@ private const val TIME_ZONE_START = "time_zone_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
name = R.string.unit_converter,
shortcut = Shortcut(
R.string.unit_converter,
R.string.unit_converter,
R.drawable.unit_converter_shortcut
)
)
data object Calculator : TopLevelDestinations(
graph = CALCULATOR_GRAPH,
start = CALCULATOR_START,
name = R.string.calculator
name = R.string.calculator,
shortcut = Shortcut(
R.string.calculator,
R.string.calculator,
R.drawable.calculator_shortcut
)
)
data object DateCalculator : TopLevelDestinations(
graph = DATE_CALCULATOR_GRAPH,
start = DATE_CALCULATOR_START,
name = R.string.date_calculator
name = R.string.date_calculator,
shortcut = Shortcut(
R.string.date_calculator,
R.string.date_calculator,
R.drawable.date_calculator_shortcut
)
)
data object TimeZone : TopLevelDestinations(
graph = TIME_ZONE_GRAPH,
start = TIME_ZONE_START,
name = R.string.time_zone_screen
name = R.string.time_zone_screen,
shortcut = Shortcut(
R.string.time_zone_screen,
R.string.time_zone_screen,
R.drawable.time_zone_shortcut
)
)
data object Settings : TopLevelDestinations(

View File

@ -0,0 +1,31 @@
<!--
~ Unitto is a unit converter for Android
~ Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="49dp"
android:viewportWidth="48"
android:viewportHeight="49">
<group>
<clip-path
android:pathData="M0,0.268h48v48h-48z"/>
<path
android:pathData="M16,36.268H19V32.268H23V29.268H19V25.268H16V29.268H12V32.268H16V36.268ZM26,34.768H36V31.768H26V34.768ZM26,29.768H36V26.768H26V29.768ZM28.2,22.168L31,19.368L33.8,22.168L35.9,20.068L33.1,17.168L35.9,14.368L33.8,12.268L31,15.068L28.2,12.268L26.1,14.368L28.9,17.168L26.1,20.068L28.2,22.168ZM12.5,18.668H22.5V15.668H12.5V18.668ZM10,42.268C8.9,42.268 7.958,41.877 7.175,41.093C6.392,40.31 6,39.368 6,38.268V10.268C6,9.168 6.392,8.227 7.175,7.443C7.958,6.66 8.9,6.268 10,6.268H38C39.1,6.268 40.042,6.66 40.825,7.443C41.608,8.227 42,9.168 42,10.268V38.268C42,39.368 41.608,40.31 40.825,41.093C40.042,41.877 39.1,42.268 38,42.268H10ZM10,38.268H38V10.268H10V38.268Z"
android:fillColor="#378648"/>
</group>
</vector>

View File

@ -0,0 +1,31 @@
<!--
~ Unitto is a unit converter for Android
~ Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="49dp"
android:viewportWidth="48"
android:viewportHeight="49">
<group>
<clip-path
android:pathData="M0,0.268h48v48h-48z"/>
<path
android:pathData="M29,36.268C27.6,36.268 26.417,35.785 25.45,34.818C24.483,33.852 24,32.668 24,31.268C24,29.868 24.483,28.685 25.45,27.718C26.417,26.752 27.6,26.268 29,26.268C30.4,26.268 31.583,26.752 32.55,27.718C33.517,28.685 34,29.868 34,31.268C34,32.668 33.517,33.852 32.55,34.818C31.583,35.785 30.4,36.268 29,36.268ZM10,44.268C8.9,44.268 7.958,43.877 7.175,43.093C6.392,42.31 6,41.368 6,40.268V12.268C6,11.168 6.392,10.227 7.175,9.443C7.958,8.66 8.9,8.268 10,8.268H12V4.268H16V8.268H32V4.268H36V8.268H38C39.1,8.268 40.042,8.66 40.825,9.443C41.608,10.227 42,11.168 42,12.268V40.268C42,41.368 41.608,42.31 40.825,43.093C40.042,43.877 39.1,44.268 38,44.268H10ZM10,40.268H38V20.268H10V40.268ZM10,16.268H38V12.268H10V16.268Z"
android:fillColor="#378648"/>
</group>
</vector>

View File

@ -0,0 +1,31 @@
<!--
~ Unitto is a unit converter for Android
~ Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="49dp"
android:viewportWidth="48"
android:viewportHeight="49">
<group>
<clip-path
android:pathData="M0,0.268h48v48h-48z"/>
<path
android:pathData="M24,44.269C21.5,44.269 19.159,43.793 16.975,42.843C14.792,41.894 12.892,40.61 11.275,38.993C9.659,37.377 8.375,35.477 7.425,33.293C6.475,31.11 6,28.768 6,26.268C6,23.768 6.475,21.427 7.425,19.243C8.375,17.06 9.659,15.16 11.275,13.543C12.892,11.927 14.792,10.644 16.975,9.694C19.159,8.744 21.5,8.269 24,8.269C26.5,8.269 28.842,8.744 31.025,9.694C33.208,10.644 35.109,11.927 36.725,13.543C38.342,15.16 39.625,17.06 40.575,19.243C41.525,21.427 42,23.768 42,26.268C42,28.768 41.525,31.11 40.575,33.293C39.625,35.477 38.342,37.377 36.725,38.993C35.109,40.61 33.208,41.894 31.025,42.843C28.842,43.793 26.5,44.269 24,44.269ZM29.6,34.668L32.4,31.868L26,25.469V16.268H22V27.069L29.6,34.668ZM11.2,4.969L14,7.769L5.5,16.268L2.7,13.469L11.2,4.969ZM36.8,4.969L45.3,13.469L42.5,16.268L34,7.769L36.8,4.969ZM24,40.269C27.9,40.269 31.208,38.91 33.925,36.194C36.642,33.477 38,30.169 38,26.268C38,22.368 36.642,19.06 33.925,16.344C31.208,13.627 27.9,12.269 24,12.269C20.1,12.269 16.792,13.627 14.075,16.344C11.358,19.06 10,22.368 10,26.268C10,30.169 11.358,33.477 14.075,36.194C16.792,38.91 20.1,40.269 24,40.269Z"
android:fillColor="#378648"/>
</group>
</vector>

View File

@ -0,0 +1,31 @@
<!--
~ Unitto is a unit converter for Android
~ Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="49dp"
android:viewportWidth="48"
android:viewportHeight="49">
<group>
<clip-path
android:pathData="M0,0.268h48v48h-48z"/>
<path
android:pathData="M14,40.268L4,30.268L14,20.268L16.8,23.118L11.65,28.268H26V32.268H11.65L16.8,37.418L14,40.268ZM34,28.268L31.2,25.418L36.35,20.268H22V16.268H36.35L31.2,11.118L34,8.268L44,18.268L34,28.268Z"
android:fillColor="#378648"/>
</group>
</vector>

View File

@ -33,13 +33,13 @@ internal fun UnittoDrawerItem(
destination: TopLevelDestinations,
icon: ImageVector,
selected: Boolean,
onClick: (String) -> Unit
onClick: (TopLevelDestinations) -> Unit
) {
NavigationDrawerItem(
modifier = modifier,
label = { Text(stringResource(destination.name)) },
icon = { Icon(icon, stringResource(destination.name)) },
selected = selected,
onClick = { onClick(destination.graph) }
onClick = { onClick(destination) }
)
}

View File

@ -32,6 +32,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.core.ui.model.DrawerItems
@Composable
@ -40,7 +41,7 @@ fun UnittoDrawerSheet(
mainTabs: List<DrawerItems>,
additionalTabs: List<DrawerItems>,
currentDestination: String?,
onItemClick: (String) -> Unit
onItemClick: (TopLevelDestinations) -> Unit
) {
ModalDrawerSheet(
modifier = modifier

View File

@ -20,6 +20,7 @@ package com.sadellie.unitto.feature.converter.navigation
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink
import androidx.navigation.navigation
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.feature.converter.ConverterRoute
@ -36,7 +37,12 @@ fun NavGraphBuilder.converterGraph(
viewModel: ConverterViewModel
) {
navigation(start, graph) {
composable(start) {
composable(
route = start,
deepLinks = listOf(
navDeepLink { uriPattern = "app://com.sadellie.unitto/$start" }
)
) {
ConverterRoute(
viewModel = viewModel,
navigateToLeftScreen = navigateToLeftScreen,

View File

@ -55,9 +55,13 @@ fun NavGraphBuilder.timeZoneGraph(
navigation(
startDestination = start,
route = graph,
deepLinks = listOf(navDeepLink { uriPattern = "app://com.sadellie.unitto/$start" })
) {
composable(start) {
composable(
route = start,
deepLinks = listOf(
navDeepLink { uriPattern = "app://com.sadellie.unitto/$start" }
)
) {
TimeZoneRoute(
navigateToMenu = navigateToMenu,
navigateToSettings = navigateToSettings,