From 5c36520b3545383f1f50ca0e7d875d0dde02d982 Mon Sep 17 00:00:00 2001 From: Roman Makeev <57789105+makeevrserg@users.noreply.github.com> Date: Mon, 28 Oct 2024 07:35:07 -0700 Subject: [PATCH] Open tools tab one time after start (#978) **Background** To show users new infrared-remotes feature we should navigate them somehow into tools tab. This pr changes some proto settings so Tools tab will be the first after app is intalled/open after update **Changes** - Change proto files to open tools tab first **Test plan** - Open non-updated app on not-tools tab - Update up - Open app and see you are on tools tab - Reinstall app, and see the first tab is now tools --- CHANGELOG.md | 1 + .../src/main/kotlin/commonKspConfiguration.kt | 4 +- .../kotlin/flipper.android-app.gradle.kts | 2 +- .../kotlin/flipper.android-lib.gradle.kts | 2 +- .../kotlin/flipper.multiplatform.gradle.kts | 2 +- .../api/BottomBarDecomposeComponentImpl.kt | 13 ++++- .../impl/model/BottomBarTabConfig.kt | 18 +----- .../impl/viewmodel/SelectedTabViewModel.kt | 56 +++++++++++++++++++ .../src/commonMain/proto/settings.proto | 1 + 9 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/viewmodel/SelectedTabViewModel.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cc5396c30..665e98df0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Attention: don't forget to add the flag for F-Droid before release - [Feature] New File Manager search - [Feature] Add illustrations, search, hold to dispatch into RemoteControls - [Feature] Add metrics to infrared remotes +- [Feature] One-time open tools tab - [Refactor] Load RemoteControls from flipper, emulating animation - [Refactor] Update to Kotlin 2.0 - [Refactor] Replace Ktorfit with Ktor requests in remote-controls diff --git a/build-logic/plugins/convention/src/main/kotlin/commonKspConfiguration.kt b/build-logic/plugins/convention/src/main/kotlin/commonKspConfiguration.kt index b96b960f74..093d161488 100644 --- a/build-logic/plugins/convention/src/main/kotlin/commonKspConfiguration.kt +++ b/build-logic/plugins/convention/src/main/kotlin/commonKspConfiguration.kt @@ -1,3 +1,5 @@ +@file:Suppress("Filename") + import org.gradle.api.Project fun Project.includeCommonKspConfigurationTo( @@ -9,4 +11,4 @@ fun Project.includeCommonKspConfigurationTo( configurations.getByName(configurationName).extendsFrom(commonKsp) } } -} \ No newline at end of file +} diff --git a/build-logic/plugins/convention/src/main/kotlin/flipper.android-app.gradle.kts b/build-logic/plugins/convention/src/main/kotlin/flipper.android-app.gradle.kts index 54b0c6a6b4..c7f4cdd381 100644 --- a/build-logic/plugins/convention/src/main/kotlin/flipper.android-app.gradle.kts +++ b/build-logic/plugins/convention/src/main/kotlin/flipper.android-app.gradle.kts @@ -54,4 +54,4 @@ configure { autoInstallation.enabled.set(false) } -includeCommonKspConfigurationTo("ksp") \ No newline at end of file +includeCommonKspConfigurationTo("ksp") diff --git a/build-logic/plugins/convention/src/main/kotlin/flipper.android-lib.gradle.kts b/build-logic/plugins/convention/src/main/kotlin/flipper.android-lib.gradle.kts index c6a3162764..de869be58c 100644 --- a/build-logic/plugins/convention/src/main/kotlin/flipper.android-lib.gradle.kts +++ b/build-logic/plugins/convention/src/main/kotlin/flipper.android-lib.gradle.kts @@ -10,4 +10,4 @@ configure { commonAndroid(project) } -includeCommonKspConfigurationTo("ksp") \ No newline at end of file +includeCommonKspConfigurationTo("ksp") diff --git a/build-logic/plugins/convention/src/main/kotlin/flipper.multiplatform.gradle.kts b/build-logic/plugins/convention/src/main/kotlin/flipper.multiplatform.gradle.kts index 0287c33864..11ee2e8fb5 100644 --- a/build-logic/plugins/convention/src/main/kotlin/flipper.multiplatform.gradle.kts +++ b/build-logic/plugins/convention/src/main/kotlin/flipper.multiplatform.gradle.kts @@ -31,4 +31,4 @@ kotlin { } } -includeCommonKspConfigurationTo("kspAndroid", "kspDesktop") \ No newline at end of file +includeCommonKspConfigurationTo("kspAndroid", "kspDesktop") diff --git a/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/api/BottomBarDecomposeComponentImpl.kt b/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/api/BottomBarDecomposeComponentImpl.kt index 41a35a2897..d1dfd2f00a 100644 --- a/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/api/BottomBarDecomposeComponentImpl.kt +++ b/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/api/BottomBarDecomposeComponentImpl.kt @@ -14,6 +14,7 @@ import com.arkivanov.decompose.router.stack.bringToFront import com.arkivanov.decompose.router.stack.childStack import com.arkivanov.decompose.value.Value import com.arkivanov.essenty.backhandler.BackCallback +import com.arkivanov.essenty.instancekeeper.getOrCreate import com.flipperdevices.archive.api.ArchiveDecomposeComponent import com.flipperdevices.bottombar.api.BottomBarDecomposeComponent import com.flipperdevices.bottombar.handlers.ResetTabDecomposeHandler @@ -24,6 +25,7 @@ import com.flipperdevices.bottombar.impl.model.toBottomBarTabEnum import com.flipperdevices.bottombar.impl.model.toConfig import com.flipperdevices.bottombar.impl.viewmodel.BottomBarViewModel import com.flipperdevices.bottombar.impl.viewmodel.InAppNotificationViewModel +import com.flipperdevices.bottombar.impl.viewmodel.SelectedTabViewModel import com.flipperdevices.connection.api.ConnectionApi import com.flipperdevices.core.di.AppGraph import com.flipperdevices.core.preference.pb.Settings @@ -63,13 +65,22 @@ class BottomBarDecomposeComponentImpl @AssistedInject constructor( private val unhandledExceptionRendererApi: UnhandledExceptionRenderApi, private val appNotificationApi: FlipperAppNotificationDialogApi, private val bottomBarViewModelProvider: Provider, + private val selectedTabViewModelProvider: Provider, private val inAppNotificationViewModelFactory: InAppNotificationViewModel.Factory ) : BottomBarDecomposeComponent(), ComponentContext by componentContext { + override val stack: Value> = childStack( source = navigation, serializer = BottomBarTabConfig.serializer(), - initialConfiguration = BottomBarTabConfig.getInitialConfig(settingsDataStore, deeplink), + initialConfiguration = BottomBarTabConfig.getInitialConfig( + getSavedTab = { + instanceKeeper.getOrCreate("bbdc_st_vm") { + selectedTabViewModelProvider.get() + }.getSelectedTab() + }, + deeplink = deeplink + ), childFactory = ::child, ) diff --git a/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/model/BottomBarTabConfig.kt b/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/model/BottomBarTabConfig.kt index e51eaaa06b..7416004dd3 100644 --- a/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/model/BottomBarTabConfig.kt +++ b/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/model/BottomBarTabConfig.kt @@ -1,11 +1,6 @@ package com.flipperdevices.bottombar.impl.model -import androidx.datastore.core.DataStore -import com.flipperdevices.core.preference.pb.SelectedTab -import com.flipperdevices.core.preference.pb.Settings import com.flipperdevices.deeplink.model.Deeplink -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking import kotlinx.serialization.Serializable @Serializable @@ -42,7 +37,7 @@ sealed interface BottomBarTabConfig { companion object { fun getInitialConfig( - dataStore: DataStore, + getSavedTab: () -> BottomBarTabConfig, deeplink: Deeplink.BottomBar? ): BottomBarTabConfig { if (deeplink != null) { @@ -55,16 +50,7 @@ sealed interface BottomBarTabConfig { .toConfig() } } - return runBlocking { - when (dataStore.data.first().selected_tab) { - SelectedTab.DEVICE, - is SelectedTab.Unrecognized -> Device(null) - - SelectedTab.ARCHIVE -> Archive(null) - SelectedTab.APPS -> Apps(null) - SelectedTab.TOOLS -> Tools(null) - } - } + return getSavedTab.invoke() } } } diff --git a/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/viewmodel/SelectedTabViewModel.kt b/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/viewmodel/SelectedTabViewModel.kt new file mode 100644 index 0000000000..eb09c00f28 --- /dev/null +++ b/components/bottombar/impl/src/main/java/com/flipperdevices/bottombar/impl/viewmodel/SelectedTabViewModel.kt @@ -0,0 +1,56 @@ +package com.flipperdevices.bottombar.impl.viewmodel + +import androidx.datastore.core.DataStore +import com.flipperdevices.bottombar.impl.model.BottomBarTabConfig +import com.flipperdevices.bottombar.impl.model.BottomBarTabConfig.Apps +import com.flipperdevices.bottombar.impl.model.BottomBarTabConfig.Archive +import com.flipperdevices.bottombar.impl.model.BottomBarTabConfig.Device +import com.flipperdevices.bottombar.impl.model.BottomBarTabConfig.Tools +import com.flipperdevices.core.preference.pb.SelectedTab +import com.flipperdevices.core.preference.pb.Settings +import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import javax.inject.Inject + +/** + * Needs to promote infrared remotes feature + * On first update (not first launch) will return tools tab only one time + */ +class SelectedTabViewModel @Inject constructor( + private val settingsDataStore: DataStore, +) : DecomposeViewModel() { + + private fun toConfig(selectedTab: SelectedTab): BottomBarTabConfig { + return when (selectedTab) { + SelectedTab.DEVICE, + is SelectedTab.Unrecognized -> Device(null) + + SelectedTab.ARCHIVE -> Archive(null) + SelectedTab.APPS -> Apps(null) + SelectedTab.TOOLS -> Tools(null) + } + } + + private fun setRemoteFeaturePromoted() { + viewModelScope.launch { + settingsDataStore.updateData { it.copy(infrared_remotes_tab_shown = true) } + } + } + + fun getSelectedTab(): BottomBarTabConfig { + val settings = runBlocking { settingsDataStore.data.first() } + if (settings.infrared_remotes_tab_shown) { + return toConfig(settings.selected_tab) + } + // wasStartDialogShown indicates that flipper was already connected at least one time + val wasStartDialogShown = settings.notification_dialog_shown + if (!wasStartDialogShown) { + setRemoteFeaturePromoted() + return toConfig(settings.selected_tab) + } + setRemoteFeaturePromoted() + return Tools(null) + } +} diff --git a/components/core/preference/src/commonMain/proto/settings.proto b/components/core/preference/src/commonMain/proto/settings.proto index c1ba899ae6..c91df32e0d 100644 --- a/components/core/preference/src/commonMain/proto/settings.proto +++ b/components/core/preference/src/commonMain/proto/settings.proto @@ -75,4 +75,5 @@ message Settings { FileManagerSort file_manager_sort = 31; bool show_hidden_files_on_flipper = 32; bool disabled_vibration = 33; + bool infrared_remotes_tab_shown = 34; } \ No newline at end of file