diff --git a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModel.kt b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModel.kt index 86be6aaa43aa..aadf338bfe67 100644 --- a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModel.kt +++ b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModel.kt @@ -44,6 +44,7 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class DuckChatSettingsViewModel @AssistedInject constructor( @Assisted duckChatActivityParams: GlobalActivityStarter.ActivityParams, @@ -51,7 +52,7 @@ class DuckChatSettingsViewModel @AssistedInject constructor( private val pixel: Pixel, private val inputScreenDiscoveryFunnel: InputScreenDiscoveryFunnel, private val settingsPageFeature: SettingsPageFeature, - dispatcherProvider: DispatcherProvider, + private val dispatcherProvider: DispatcherProvider, ) : ViewModel() { private val commandChannel = Channel(capacity = 1, onBufferOverflow = DROP_OLDEST) val commands = commandChannel.receiveAsFlow() @@ -142,11 +143,19 @@ class DuckChatSettingsViewModel @AssistedInject constructor( fun duckChatSearchAISettingsClicked() { viewModelScope.launch { + val hideAiGeneratedImagesOptionEnabled = withContext(dispatcherProvider.io()) { + settingsPageFeature.hideAiGeneratedImagesOption().isEnabled() + } + if (settingsPageFeature.embeddedSettingsWebView().isEnabled()) { commandChannel.send( OpenLink( - link = DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED, - titleRes = if (settingsPageFeature.hideAiGeneratedImagesOption().isEnabled()) { + link = if (hideAiGeneratedImagesOptionEnabled) { + DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED + } else { + LEGACY_DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED + }, + titleRes = if (hideAiGeneratedImagesOptionEnabled) { R.string.duckAiSerpSettingsTitle } else { R.string.duck_chat_assist_settings_title @@ -220,7 +229,10 @@ class DuckChatSettingsViewModel @AssistedInject constructor( companion object { const val DUCK_CHAT_LEARN_MORE_LINK = "https://duckduckgo.com/duckduckgo-help-pages/aichat/" const val DUCK_CHAT_SEARCH_AI_SETTINGS_LINK = "https://duckduckgo.com/settings?ko=-1#aifeatures" - const val DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED = "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbe#aifeatures" - const val DUCK_CHAT_HIDE_GENERATED_IMAGES_LINK_EMBEDDED = "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbj#aifeatures" + const val LEGACY_DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED = "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbe#aifeatures" + const val DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED = + "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbe&hideduckai=1#aifeatures" + const val DUCK_CHAT_HIDE_GENERATED_IMAGES_LINK_EMBEDDED = + "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbj&hideduckai=1#aifeatures" } } diff --git a/duckchat/duckchat-impl/src/test/kotlin/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModelTest.kt b/duckchat/duckchat-impl/src/test/kotlin/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModelTest.kt index 487f91f6b52e..8e3a44f447a7 100644 --- a/duckchat/duckchat-impl/src/test/kotlin/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModelTest.kt +++ b/duckchat/duckchat-impl/src/test/kotlin/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModelTest.kt @@ -285,10 +285,12 @@ class DuckChatSettingsViewModelTest { } @Test - fun whenDuckChatSearchAISettingsClickedAndSaveAndExitEnabledThenOpenSettingsLinkWithReturnParamEmitted() = + fun whenDuckChatSearchAISettingsClickedAndEmbeddedEnabledAndHideAiGeneratedImagesDisabledThenOpenSettingsLinkWithLegacyLink() = runTest { @Suppress("DenyListedApi") settingsPageFeature.embeddedSettingsWebView().setRawStoredState(State(enable = true)) + @Suppress("DenyListedApi") + settingsPageFeature.hideAiGeneratedImagesOption().setRawStoredState(State(enable = false)) testee.duckChatSearchAISettingsClicked() @@ -297,7 +299,7 @@ class DuckChatSettingsViewModelTest { assertTrue(command is OpenLink) command as OpenLink assertEquals( - DuckChatSettingsViewModel.DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED, + DuckChatSettingsViewModel.LEGACY_DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED, command.link, ) assertEquals(R.string.duck_chat_assist_settings_title, command.titleRes) @@ -305,6 +307,38 @@ class DuckChatSettingsViewModelTest { } } + @Test + fun whenDuckChatSearchAISettingsClickedAndEmbeddedEnabledAndHideAiGeneratedImagesEnabledThenOpenSettingsLinkWithNewLink() = + runTest { + @Suppress("DenyListedApi") + settingsPageFeature.embeddedSettingsWebView().setRawStoredState(State(enable = true)) + @Suppress("DenyListedApi") + settingsPageFeature.hideAiGeneratedImagesOption().setRawStoredState(State(enable = true)) + + testee = DuckChatSettingsViewModel( + duckChatActivityParams = DuckChatSettingsNoParams, + duckChat = duckChat, + pixel = mockPixel, + inputScreenDiscoveryFunnel = mockInputScreenDiscoveryFunnel, + settingsPageFeature = settingsPageFeature, + dispatcherProvider = coroutineRule.testDispatcherProvider, + ) + + testee.duckChatSearchAISettingsClicked() + + testee.commands.test { + val command = awaitItem() + assertTrue(command is OpenLink) + command as OpenLink + assertEquals( + DuckChatSettingsViewModel.DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED, + command.link, + ) + assertEquals(R.string.duckAiSerpSettingsTitle, command.titleRes) + cancelAndIgnoreRemainingEvents() + } + } + @Test fun `when onDuckChatUserEnabledToggled true then enabled pixel fired`() = runTest { @@ -557,4 +591,22 @@ class DuckChatSettingsViewModelTest { testee.onDuckAiHideAiGeneratedImagesClicked() verify(mockPixel).fire(DuckChatPixelName.SERP_SETTINGS_OPEN_HIDE_AI_GENERATED_IMAGES) } + + @Test + fun `when onDuckAiHideAiGeneratedImagesClicked then OpenLink command with correct link is emitted`() = + runTest { + testee.onDuckAiHideAiGeneratedImagesClicked() + + testee.commands.test { + val command = awaitItem() + assertTrue(command is OpenLink) + command as OpenLink + assertEquals( + DuckChatSettingsViewModel.DUCK_CHAT_HIDE_GENERATED_IMAGES_LINK_EMBEDDED, + command.link, + ) + assertEquals(R.string.duckAiSerpSettingsTitle, command.titleRes) + cancelAndIgnoreRemainingEvents() + } + } }