Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.duckduckgo.app.browser.newaddressbaroption
import android.app.Activity
import com.duckduckgo.app.browser.omnibar.OmnibarType
import com.duckduckgo.app.onboarding.store.AppStage
import com.duckduckgo.app.onboarding.store.OnboardingStore
import com.duckduckgo.app.onboarding.store.UserStageStore
import com.duckduckgo.app.settings.db.SettingsDataStore
import com.duckduckgo.common.ui.DuckDuckGoActivity
Expand Down Expand Up @@ -55,6 +56,7 @@ class RealNewAddressBarOptionManager @Inject constructor(
private val remoteMessagingRepository: RemoteMessagingRepository,
private val newAddressBarOptionDataStore: NewAddressBarOptionDataStore,
private val settingsDataStore: SettingsDataStore,
private val onboardingStore: OnboardingStore,
private val dispatchers: DispatcherProvider = DefaultDispatcherProvider(),
) : NewAddressBarOptionManager {
private val showChoiceScreenMutex = Mutex()
Expand Down Expand Up @@ -97,7 +99,8 @@ class RealNewAddressBarOptionManager @Inject constructor(
hasNotInteractedWithSearchAndDuckAiRMF() &&
isNewAddressBarOptionChoiceScreenEnabled() &&
isNotLaunchedFromExternal(isLaunchedFromExternal) &&
isSubsequentLaunch()
isSubsequentLaunch() &&
hasNoInputScreenSelection()
}

private fun isActivityValid(activity: Activity): Boolean =
Expand Down Expand Up @@ -130,6 +133,11 @@ class RealNewAddressBarOptionManager @Inject constructor(
logcat(DEBUG) { "NewAddressBarOptionManager: $it isInputScreenDisabled" }
}

private fun hasNoInputScreenSelection(): Boolean =
(onboardingStore.getInputScreenSelection() == null).also {
logcat(DEBUG) { "NewAddressBarOptionManager: $it hasNoInputScreenSelection" }
}

private fun isBottomAddressBarDisabled(): Boolean =
(settingsDataStore.omnibarType != OmnibarType.SINGLE_BOTTOM).also {
logcat(DEBUG) { "NewAddressBarOptionManager: $it isBottomAddressBarDisabled" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2025 DuckDuckGo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.duckduckgo.app.onboarding

import com.duckduckgo.app.di.AppCoroutineScope
import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver
import com.duckduckgo.app.onboarding.store.AppStage
import com.duckduckgo.app.onboarding.store.OnboardingStore
import com.duckduckgo.app.onboarding.store.UserStageStore
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.duckchat.api.DuckChat
import com.squareup.anvil.annotations.ContributesMultibinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject

@ContributesMultibinding(
scope = AppScope::class,
boundType = MainProcessLifecycleObserver::class,
)
class OnboardingInputScreenSelectionObserver @Inject constructor(
@AppCoroutineScope private val appCoroutineScope: CoroutineScope,
private val dispatchers: DispatcherProvider,
private val userStageStore: UserStageStore,
private val onboardingStore: OnboardingStore,
private val duckChat: DuckChat,
) : MainProcessLifecycleObserver {

init {
observeInputScreenSetting()
setSelectionWhenEstablished()
}

private fun observeInputScreenSetting() {
duckChat.observeInputScreenUserSettingEnabled()
.distinctUntilChanged()
.drop(1)
.onEach {
if (userStageStore.getUserAppStage() != AppStage.ESTABLISHED && onboardingStore.getInputScreenSelection() != null) {
onboardingStore.setInputScreenSelectionOverriddenByUser()
}
}
.flowOn(dispatchers.io())
.launchIn(appCoroutineScope)
}

private fun setSelectionWhenEstablished() {
userStageStore.userAppStageFlow()
.distinctUntilChanged()
.filter { it == AppStage.ESTABLISHED }
.onEach {
val selection = onboardingStore.getInputScreenSelection()
if (!onboardingStore.isInputScreenSelectionOverriddenByUser() && selection != null) {
duckChat.setInputScreenUserSetting(selection)
}
}
.flowOn(dispatchers.io())
.launchIn(appCoroutineScope)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ interface OnboardingStore {

fun getSearchOptions(): List<DaxDialogIntroOption>
fun getSitesOptions(): List<DaxDialogIntroOption>
fun storeInputScreenSelection(selected: Boolean)
fun getInputScreenSelection(): Boolean?
fun isInputScreenSelectionOverriddenByUser(): Boolean
fun setInputScreenSelectionOverriddenByUser()
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,30 @@ class OnboardingStoreImpl @Inject constructor(
)
}

override fun storeInputScreenSelection(selected: Boolean) {
preferences.edit { putBoolean(KEY_INPUT_SCREEN_SELECTION, selected) }
}

override fun getInputScreenSelection(): Boolean? {
return if (preferences.contains(KEY_INPUT_SCREEN_SELECTION)) {
preferences.getBoolean(KEY_INPUT_SCREEN_SELECTION, false)
} else {
null
}
}

override fun isInputScreenSelectionOverriddenByUser(): Boolean {
return preferences.getBoolean(KEY_INPUT_SCREEN_SELECTION_OVERRIDDEN_BY_USER, false)
}

override fun setInputScreenSelectionOverriddenByUser() {
preferences.edit { putBoolean(KEY_INPUT_SCREEN_SELECTION_OVERRIDDEN_BY_USER, true) }
}

companion object {
const val FILENAME = "com.duckduckgo.app.onboarding.settings"
const val ONBOARDING_JOURNEY = "onboardingJourney"
private const val KEY_INPUT_SCREEN_SELECTION = "inputScreenSelection"
private const val KEY_INPUT_SCREEN_SELECTION_OVERRIDDEN_BY_USER = "inputScreenSelectionOverriddenByUser"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.ADDRESS_BAR
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.COMPARISON_CHART
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.INITIAL
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.INITIAL_REINSTALL_USER
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.INPUT_SCREEN
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.SKIP_ONBOARDING_OPTION
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.*
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.ShowInputScreenDialog
import com.duckduckgo.appbuildconfig.api.AppBuildConfig
import com.duckduckgo.common.ui.store.AppTheme
import com.duckduckgo.common.ui.view.TypeAnimationTextView
Expand Down Expand Up @@ -116,6 +118,7 @@ class BbWelcomePage : OnboardingPageFragment(R.layout.content_onboarding_welcome
is ShowSkipOnboardingOption -> configureDaxCta(SKIP_ONBOARDING_OPTION)
is ShowDefaultBrowserDialog -> showDefaultBrowserDialog(it.intent)
is ShowAddressBarPositionDialog -> configureDaxCta(ADDRESS_BAR_POSITION)
is ShowInputScreenDialog -> onContinuePressed()
is Finish -> onContinuePressed()
is OnboardingSkipped -> onSkipPressed()
is SetAddressBarPositionOptions -> setAddressBarPositionOptions(it.defaultOption)
Expand Down Expand Up @@ -436,6 +439,10 @@ class BbWelcomePage : OnboardingPageFragment(R.layout.content_onboarding_welcome
scheduleTypingAnimation(binding.daxDialogCta.addressBarPosition.dialogTitle, titleText) { afterTypingAnimation() }
backgroundSceneManager?.transitionToNextTile(expectedTile = TILE_04)
}

INPUT_SCREEN -> {
// Ignored
}
}
backgroundSceneManager?.setBackgroundClickListener(afterTypingAnimation)
binding.daxDialogCta.cardContainer.setOnClickListener { afterTypingAnimation() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.ADDRESS_BAR
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.COMPARISON_CHART
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.INITIAL
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.INITIAL_REINSTALL_USER
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.INPUT_SCREEN
import com.duckduckgo.app.onboarding.ui.page.PreOnboardingDialogType.SKIP_ONBOARDING_OPTION
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.Finish
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.OnboardingSkipped
Expand All @@ -62,6 +63,7 @@ import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.ShowCo
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.ShowDefaultBrowserDialog
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.ShowInitialDialog
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.ShowInitialReinstallUserDialog
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.ShowInputScreenDialog
import com.duckduckgo.app.onboarding.ui.page.WelcomePageViewModel.Command.ShowSkipOnboardingOption
import com.duckduckgo.appbuildconfig.api.AppBuildConfig
import com.duckduckgo.common.ui.store.AppTheme
Expand Down Expand Up @@ -116,6 +118,7 @@ class BuckWelcomePage : OnboardingPageFragment(R.layout.content_onboarding_welco
is ShowSkipOnboardingOption -> configureDaxCta(SKIP_ONBOARDING_OPTION)
is ShowDefaultBrowserDialog -> showDefaultBrowserDialog(it.intent)
is ShowAddressBarPositionDialog -> configureDaxCta(ADDRESS_BAR_POSITION)
is ShowInputScreenDialog -> onContinuePressed()
is Finish -> onContinuePressed()
is OnboardingSkipped -> onSkipPressed()
is SetAddressBarPositionOptions -> setAddressBarPositionOptions(it.defaultOption)
Expand Down Expand Up @@ -395,6 +398,10 @@ class BuckWelcomePage : OnboardingPageFragment(R.layout.content_onboarding_welco
},
)
}

INPUT_SCREEN -> {
// Ignored
}
}
binding.sceneBg.setOnClickListener { afterTypingAnimation() }
binding.daxDialogCta.cardContainer.setOnClickListener { afterTypingAnimation() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ enum class PreOnboardingDialogType {
SKIP_ONBOARDING_OPTION,
COMPARISON_CHART,
ADDRESS_BAR_POSITION,
INPUT_SCREEN,
}
Loading
Loading