Skip to content

Commit cead15b

Browse files
authored
SERP Settings Sync: Hide SERP duck.ai toggle (#7153)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1207908166761516/task/1211992919877851?focus=true ### Description This PR adds a url parameter to hide the "Duck.ai" toggle when opening SERP settings from Native Settings. https://github.com/user-attachments/assets/ec3f4e8c-7131-4350-9433-f3e1315ae148 ### Steps to test this PR Apply the patch found [here](https://app.asana.com/1/137249556945/task/1211992919877854?focus=true): _SERP Duck.ai toggle hidden_ - [x] Enable the `hideAiGeneratedImagesOption` feature flag - [x] Open "AI Features" in Native Settings - [x] Click "Search Assist Settings" - [x] Scroll up - [x] The SERP Duck.ai toggle should **not** be visible - [x] Press back - [x] Click "Hide AI generated Images" - [x] Scroll up - [x] The SERP Duck.ai toggle should **not** be visible _Feature Flag off behaviour_ - [x] Remove the patch - [x] Disable the `hideAiGeneratedImagesOption` feature flag (you may need to remove @InternalAlwaysEnabled from the feature toggle in code) ``` Index: settings/settings-api/src/main/java/com/duckduckgo/settings/api/SettingsPageFeature.kt IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/settings/settings-api/src/main/java/com/duckduckgo/settings/api/SettingsPageFeature.kt b/settings/settings-api/src/main/java/com/duckduckgo/settings/api/SettingsPageFeature.kt --- a/settings/settings-api/src/main/java/com/duckduckgo/settings/api/SettingsPageFeature.kt (revision 5244965) +++ b/settings/settings-api/src/main/java/com/duckduckgo/settings/api/SettingsPageFeature.kt (date 1763588843129) @@ -32,7 +32,6 @@ fun embeddedSettingsWebView(): Toggle @Toggle.DefaultValue(DefaultFeatureValue.FALSE) - @Toggle.InternalAlwaysEnabled fun hideAiGeneratedImagesOption(): Toggle @Toggle.DefaultValue(DefaultFeatureValue.FALSE) ``` - [x] Open "AI Features" in Native Settings - [x] Click "Search Assist Settings" - [x] The SERP Duck.ai toggle **should** be visible ### UI changes No UI changes, only backend URL and logic updates.
1 parent 252a109 commit cead15b

File tree

2 files changed

+71
-7
lines changed

2 files changed

+71
-7
lines changed

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModel.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@ import kotlinx.coroutines.flow.flowOn
4444
import kotlinx.coroutines.flow.receiveAsFlow
4545
import kotlinx.coroutines.flow.stateIn
4646
import kotlinx.coroutines.launch
47+
import kotlinx.coroutines.withContext
4748

4849
class DuckChatSettingsViewModel @AssistedInject constructor(
4950
@Assisted duckChatActivityParams: GlobalActivityStarter.ActivityParams,
5051
private val duckChat: DuckChatInternal,
5152
private val pixel: Pixel,
5253
private val inputScreenDiscoveryFunnel: InputScreenDiscoveryFunnel,
5354
private val settingsPageFeature: SettingsPageFeature,
54-
dispatcherProvider: DispatcherProvider,
55+
private val dispatcherProvider: DispatcherProvider,
5556
) : ViewModel() {
5657
private val commandChannel = Channel<Command>(capacity = 1, onBufferOverflow = DROP_OLDEST)
5758
val commands = commandChannel.receiveAsFlow()
@@ -142,11 +143,19 @@ class DuckChatSettingsViewModel @AssistedInject constructor(
142143

143144
fun duckChatSearchAISettingsClicked() {
144145
viewModelScope.launch {
146+
val hideAiGeneratedImagesOptionEnabled = withContext(dispatcherProvider.io()) {
147+
settingsPageFeature.hideAiGeneratedImagesOption().isEnabled()
148+
}
149+
145150
if (settingsPageFeature.embeddedSettingsWebView().isEnabled()) {
146151
commandChannel.send(
147152
OpenLink(
148-
link = DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED,
149-
titleRes = if (settingsPageFeature.hideAiGeneratedImagesOption().isEnabled()) {
153+
link = if (hideAiGeneratedImagesOptionEnabled) {
154+
DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED
155+
} else {
156+
LEGACY_DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED
157+
},
158+
titleRes = if (hideAiGeneratedImagesOptionEnabled) {
150159
R.string.duckAiSerpSettingsTitle
151160
} else {
152161
R.string.duck_chat_assist_settings_title
@@ -220,7 +229,10 @@ class DuckChatSettingsViewModel @AssistedInject constructor(
220229
companion object {
221230
const val DUCK_CHAT_LEARN_MORE_LINK = "https://duckduckgo.com/duckduckgo-help-pages/aichat/"
222231
const val DUCK_CHAT_SEARCH_AI_SETTINGS_LINK = "https://duckduckgo.com/settings?ko=-1#aifeatures"
223-
const val DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED = "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbe#aifeatures"
224-
const val DUCK_CHAT_HIDE_GENERATED_IMAGES_LINK_EMBEDDED = "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbj#aifeatures"
232+
const val LEGACY_DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED = "https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbe#aifeatures"
233+
const val DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED =
234+
"https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbe&hideduckai=1#aifeatures"
235+
const val DUCK_CHAT_HIDE_GENERATED_IMAGES_LINK_EMBEDDED =
236+
"https://duckduckgo.com/settings?ko=-1&embedded=1&highlight=kbj&hideduckai=1#aifeatures"
225237
}
226238
}

duckchat/duckchat-impl/src/test/kotlin/com/duckduckgo/duckchat/impl/ui/settings/DuckChatSettingsViewModelTest.kt

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,12 @@ class DuckChatSettingsViewModelTest {
285285
}
286286

287287
@Test
288-
fun whenDuckChatSearchAISettingsClickedAndSaveAndExitEnabledThenOpenSettingsLinkWithReturnParamEmitted() =
288+
fun whenDuckChatSearchAISettingsClickedAndEmbeddedEnabledAndHideAiGeneratedImagesDisabledThenOpenSettingsLinkWithLegacyLink() =
289289
runTest {
290290
@Suppress("DenyListedApi")
291291
settingsPageFeature.embeddedSettingsWebView().setRawStoredState(State(enable = true))
292+
@Suppress("DenyListedApi")
293+
settingsPageFeature.hideAiGeneratedImagesOption().setRawStoredState(State(enable = false))
292294

293295
testee.duckChatSearchAISettingsClicked()
294296

@@ -297,14 +299,46 @@ class DuckChatSettingsViewModelTest {
297299
assertTrue(command is OpenLink)
298300
command as OpenLink
299301
assertEquals(
300-
DuckChatSettingsViewModel.DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED,
302+
DuckChatSettingsViewModel.LEGACY_DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED,
301303
command.link,
302304
)
303305
assertEquals(R.string.duck_chat_assist_settings_title, command.titleRes)
304306
cancelAndIgnoreRemainingEvents()
305307
}
306308
}
307309

310+
@Test
311+
fun whenDuckChatSearchAISettingsClickedAndEmbeddedEnabledAndHideAiGeneratedImagesEnabledThenOpenSettingsLinkWithNewLink() =
312+
runTest {
313+
@Suppress("DenyListedApi")
314+
settingsPageFeature.embeddedSettingsWebView().setRawStoredState(State(enable = true))
315+
@Suppress("DenyListedApi")
316+
settingsPageFeature.hideAiGeneratedImagesOption().setRawStoredState(State(enable = true))
317+
318+
testee = DuckChatSettingsViewModel(
319+
duckChatActivityParams = DuckChatSettingsNoParams,
320+
duckChat = duckChat,
321+
pixel = mockPixel,
322+
inputScreenDiscoveryFunnel = mockInputScreenDiscoveryFunnel,
323+
settingsPageFeature = settingsPageFeature,
324+
dispatcherProvider = coroutineRule.testDispatcherProvider,
325+
)
326+
327+
testee.duckChatSearchAISettingsClicked()
328+
329+
testee.commands.test {
330+
val command = awaitItem()
331+
assertTrue(command is OpenLink)
332+
command as OpenLink
333+
assertEquals(
334+
DuckChatSettingsViewModel.DUCK_CHAT_SEARCH_AI_SETTINGS_LINK_EMBEDDED,
335+
command.link,
336+
)
337+
assertEquals(R.string.duckAiSerpSettingsTitle, command.titleRes)
338+
cancelAndIgnoreRemainingEvents()
339+
}
340+
}
341+
308342
@Test
309343
fun `when onDuckChatUserEnabledToggled true then enabled pixel fired`() =
310344
runTest {
@@ -557,4 +591,22 @@ class DuckChatSettingsViewModelTest {
557591
testee.onDuckAiHideAiGeneratedImagesClicked()
558592
verify(mockPixel).fire(DuckChatPixelName.SERP_SETTINGS_OPEN_HIDE_AI_GENERATED_IMAGES)
559593
}
594+
595+
@Test
596+
fun `when onDuckAiHideAiGeneratedImagesClicked then OpenLink command with correct link is emitted`() =
597+
runTest {
598+
testee.onDuckAiHideAiGeneratedImagesClicked()
599+
600+
testee.commands.test {
601+
val command = awaitItem()
602+
assertTrue(command is OpenLink)
603+
command as OpenLink
604+
assertEquals(
605+
DuckChatSettingsViewModel.DUCK_CHAT_HIDE_GENERATED_IMAGES_LINK_EMBEDDED,
606+
command.link,
607+
)
608+
assertEquals(R.string.duckAiSerpSettingsTitle, command.titleRes)
609+
cancelAndIgnoreRemainingEvents()
610+
}
611+
}
560612
}

0 commit comments

Comments
 (0)