Skip to content

Commit f4d0082

Browse files
committed
add new internal toggle for fullscreen
1 parent 79ee649 commit f4d0082

File tree

7 files changed

+97
-1
lines changed

7 files changed

+97
-1
lines changed

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/RealDuckChat.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ interface DuckChatInternal : DuckChat {
8888
*/
8989
suspend fun setShowInAddressBarUserSetting(showDuckChat: Boolean)
9090

91+
/**
92+
* Set user setting to determine whether DuckChat should be shown in fullscreen mode.
93+
*/
94+
suspend fun setFullScreenModeUserSetting(enabled: Boolean)
95+
9196
/**
9297
* Observes whether DuckChat is user enabled or disabled.
9398
*/
@@ -108,6 +113,11 @@ interface DuckChatInternal : DuckChat {
108113
*/
109114
fun observeShowInAddressBarUserSetting(): Flow<Boolean>
110115

116+
/**
117+
* Observes whether Duck.ai full screen mode is enabled or disabled.
118+
*/
119+
fun observeFullscreenModeUserSetting(): Flow<Boolean>
120+
111121
/**
112122
* Opens DuckChat settings.
113123
*/
@@ -166,6 +176,11 @@ interface DuckChatInternal : DuckChat {
166176
*/
167177
fun isInputScreenFeatureAvailable(): Boolean
168178

179+
/**
180+
* Returns whether dedicated Duck.ai full screen mode feature is available (its feature flag is enabled).
181+
*/
182+
fun isDuckChatFullScreenModeFeatureAvailable(): Boolean
183+
169184
/**
170185
* Checks whether DuckChat is enabled based on remote config flag.
171186
*/
@@ -257,6 +272,7 @@ class RealDuckChat @Inject constructor(
257272
private val _showNewAddressBarOptionChoiceScreen = MutableStateFlow(false)
258273
private val _showClearDuckAIChatHistory = MutableStateFlow(true)
259274
private val _showMainButtonsInInputScreen = MutableStateFlow(false)
275+
private val _fullscreenModeEnabled = MutableStateFlow(false)
260276

261277
private val _chatState = MutableStateFlow(ChatState.HIDE)
262278
private val keepSession = MutableStateFlow(false)
@@ -281,6 +297,7 @@ class RealDuckChat @Inject constructor(
281297
private var clearChatHistory: Boolean = true
282298
private var inputScreenMainButtonsEnabled = false
283299
private var showInputScreenOnSystemSearchLaunchEnabled: Boolean = true
300+
private var isFullscreenModeEnabled: Boolean = false
284301

285302
init {
286303
if (isMainProcess) {
@@ -314,12 +331,21 @@ class RealDuckChat @Inject constructor(
314331
cacheUserSettings()
315332
}
316333

334+
override suspend fun setFullScreenModeUserSetting(enabled: Boolean) {
335+
withContext(dispatchers.io()) {
336+
duckChatFeatureRepository.setFullScreenModeUserSetting(enabled)
337+
cacheUserSettings()
338+
}
339+
}
340+
317341
override fun isEnabled(): Boolean = isDuckChatFeatureEnabled && isDuckChatUserEnabled
318342

319343
override fun isInputScreenFeatureAvailable(): Boolean = duckAiInputScreen
320344

321345
override fun isDuckChatFeatureEnabled(): Boolean = isDuckChatFeatureEnabled
322346

347+
override fun isDuckChatFullScreenModeFeatureAvailable(): Boolean = duckChatFeature.fullscreenMode().isEnabled()
348+
323349
override fun observeEnableDuckChatUserSetting(): Flow<Boolean> = duckChatFeatureRepository.observeDuckChatUserEnabled()
324350

325351
override fun observeInputScreenUserSettingEnabled(): Flow<Boolean> = duckChatFeatureRepository.observeInputScreenUserSettingEnabled()
@@ -328,6 +354,8 @@ class RealDuckChat @Inject constructor(
328354

329355
override fun observeShowInAddressBarUserSetting(): Flow<Boolean> = duckChatFeatureRepository.observeShowInAddressBar()
330356

357+
override fun observeFullscreenModeUserSetting(): Flow<Boolean> = duckChatFeatureRepository.observeFullscreenModeEnabled()
358+
331359
override fun openDuckChatSettings() {
332360
val intent = globalActivityStarter.startIntent(context, DuckChatSettingsNoParams)
333361
intent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@@ -607,6 +635,8 @@ class RealDuckChat @Inject constructor(
607635
showInputScreenOnSystemSearchLaunchEnabled = duckChatFeature.showInputScreenOnSystemSearchLaunch().isEnabled()
608636
inputScreenMainButtonsEnabled = duckChatFeature.showMainButtonsInInputScreen().isEnabled()
609637

638+
isFullscreenModeEnabled = duckChatFeature.fullscreenMode().isEnabled()
639+
610640
val showMainButtons = duckChatFeature.showMainButtonsInInputScreen().isEnabled()
611641
_showMainButtonsInInputScreen.emit(showMainButtons)
612642

@@ -666,6 +696,9 @@ class RealDuckChat @Inject constructor(
666696

667697
val showClearChatHistory = clearChatHistory
668698
_showClearDuckAIChatHistory.emit(showClearChatHistory)
699+
700+
val fullscreenModeEnabled = isFullscreenModeEnabled
701+
_fullscreenModeEnabled.emit(fullscreenModeEnabled)
669702
}
670703

671704
companion object {

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/repository/DuckChatFeatureRepository.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ interface DuckChatFeatureRepository {
3535

3636
suspend fun setShowInAddressBar(showDuckChat: Boolean)
3737

38+
suspend fun setFullScreenModeUserSetting(enabled: Boolean)
39+
3840
fun observeDuckChatUserEnabled(): Flow<Boolean>
3941

4042
fun observeInputScreenUserSettingEnabled(): Flow<Boolean>
@@ -43,6 +45,8 @@ interface DuckChatFeatureRepository {
4345

4446
fun observeShowInAddressBar(): Flow<Boolean>
4547

48+
fun observeFullscreenModeEnabled(): Flow<Boolean>
49+
4650
suspend fun isDuckChatUserEnabled(): Boolean
4751

4852
suspend fun isInputScreenUserSettingEnabled(): Boolean
@@ -51,6 +55,8 @@ interface DuckChatFeatureRepository {
5155

5256
suspend fun shouldShowInAddressBar(): Boolean
5357

58+
suspend fun isFullScreenModeUserSettingEnabled(): Boolean
59+
5460
suspend fun registerOpened()
5561

5662
suspend fun wasOpenedBefore(): Boolean
@@ -82,6 +88,10 @@ class RealDuckChatFeatureRepository @Inject constructor(
8288
duckChatDataStore.setShowInAddressBar(showDuckChat)
8389
}
8490

91+
override suspend fun setFullScreenModeUserSetting(enabled: Boolean) {
92+
duckChatDataStore.setFullScreenModeUserSetting(enabled)
93+
}
94+
8595
override fun observeDuckChatUserEnabled(): Flow<Boolean> = duckChatDataStore.observeDuckChatUserEnabled()
8696

8797
override fun observeInputScreenUserSettingEnabled(): Flow<Boolean> = duckChatDataStore.observeInputScreenUserSettingEnabled()
@@ -90,6 +100,8 @@ class RealDuckChatFeatureRepository @Inject constructor(
90100

91101
override fun observeShowInAddressBar(): Flow<Boolean> = duckChatDataStore.observeShowInAddressBar()
92102

103+
override fun observeFullscreenModeEnabled(): Flow<Boolean> = duckChatDataStore.observeFullscreenMode()
104+
93105
override suspend fun isDuckChatUserEnabled(): Boolean = duckChatDataStore.isDuckChatUserEnabled()
94106

95107
override suspend fun isInputScreenUserSettingEnabled(): Boolean = duckChatDataStore.isInputScreenUserSettingEnabled()
@@ -98,6 +110,8 @@ class RealDuckChatFeatureRepository @Inject constructor(
98110

99111
override suspend fun shouldShowInAddressBar(): Boolean = duckChatDataStore.getShowInAddressBar()
100112

113+
override suspend fun isFullScreenModeUserSettingEnabled(): Boolean = duckChatDataStore.isFullScreenUserSettingEnabled()
114+
101115
override suspend fun registerOpened() {
102116
if (!duckChatDataStore.wasOpenedBefore()) {
103117
updateWidgets()

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/store/DuckChatDataStore.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import com.duckduckgo.common.utils.DispatcherProvider
2828
import com.duckduckgo.di.scopes.AppScope
2929
import com.duckduckgo.duckchat.impl.di.DuckChat
3030
import com.duckduckgo.duckchat.impl.store.SharedPreferencesDuckChatDataStore.Keys.DUCK_AI_INPUT_SCREEN_USER_SETTING
31+
import com.duckduckgo.duckchat.impl.store.SharedPreferencesDuckChatDataStore.Keys.DUCK_CHAT_FULLSCREEN_MODE_SETTING
3132
import com.duckduckgo.duckchat.impl.store.SharedPreferencesDuckChatDataStore.Keys.DUCK_CHAT_LAST_SESSION_TIMESTAMP
3233
import com.duckduckgo.duckchat.impl.store.SharedPreferencesDuckChatDataStore.Keys.DUCK_CHAT_OPENED
3334
import com.duckduckgo.duckchat.impl.store.SharedPreferencesDuckChatDataStore.Keys.DUCK_CHAT_SESSION_DELTA_TIMESTAMP
@@ -57,6 +58,8 @@ interface DuckChatDataStore {
5758

5859
suspend fun setShowInAddressBar(showDuckChat: Boolean)
5960

61+
suspend fun setFullScreenModeUserSetting(enabled: Boolean)
62+
6063
fun observeDuckChatUserEnabled(): Flow<Boolean>
6164

6265
fun observeInputScreenUserSettingEnabled(): Flow<Boolean>
@@ -65,6 +68,8 @@ interface DuckChatDataStore {
6568

6669
fun observeShowInAddressBar(): Flow<Boolean>
6770

71+
fun observeFullscreenMode(): Flow<Boolean>
72+
6873
suspend fun isDuckChatUserEnabled(): Boolean
6974

7075
suspend fun isInputScreenUserSettingEnabled(): Boolean
@@ -73,6 +78,8 @@ interface DuckChatDataStore {
7378

7479
suspend fun getShowInAddressBar(): Boolean
7580

81+
suspend fun isFullScreenUserSettingEnabled(): Boolean
82+
7683
suspend fun fetchAndClearUserPreferences(): String?
7784

7885
suspend fun updateUserPreferences(userPreferences: String?)
@@ -103,6 +110,7 @@ class SharedPreferencesDuckChatDataStore @Inject constructor(
103110
val DUCK_CHAT_USER_PREFERENCES = stringPreferencesKey("DUCK_CHAT_USER_PREFERENCES")
104111
val DUCK_CHAT_LAST_SESSION_TIMESTAMP = longPreferencesKey(name = "DUCK_CHAT_LAST_SESSION_TIMESTAMP")
105112
val DUCK_CHAT_SESSION_DELTA_TIMESTAMP = longPreferencesKey(name = "DUCK_CHAT_SESSION_DELTA_TIMESTAMP")
113+
val DUCK_CHAT_FULLSCREEN_MODE_SETTING = booleanPreferencesKey(name = "DUCK_CHAT_FULLSCREEN_MODE_SETTING")
106114
}
107115

108116
private fun Preferences.defaultShowInAddressBar(): Boolean =
@@ -158,6 +166,10 @@ class SharedPreferencesDuckChatDataStore @Inject constructor(
158166
store.edit { prefs -> prefs[DUCK_AI_INPUT_SCREEN_USER_SETTING] = enabled }
159167
}
160168

169+
override suspend fun setFullScreenModeUserSetting(enabled: Boolean) {
170+
store.edit { prefs -> prefs[DUCK_CHAT_FULLSCREEN_MODE_SETTING] = enabled }
171+
}
172+
161173
override suspend fun setShowInBrowserMenu(showDuckChat: Boolean) {
162174
store.edit { prefs -> prefs[DUCK_CHAT_SHOW_IN_MENU] = showDuckChat }
163175
}
@@ -174,6 +186,8 @@ class SharedPreferencesDuckChatDataStore @Inject constructor(
174186

175187
override fun observeShowInAddressBar(): Flow<Boolean> = duckChatShowInAddressBar
176188

189+
override fun observeFullscreenMode(): Flow<Boolean> = store.data.map { it[DUCK_CHAT_FULLSCREEN_MODE_SETTING] ?: false }
190+
177191
override suspend fun isDuckChatUserEnabled(): Boolean = store.data.firstOrNull()?.let { it[DUCK_CHAT_USER_ENABLED] } ?: true
178192

179193
override suspend fun isInputScreenUserSettingEnabled(): Boolean = store.data.firstOrNull()?.let { it[DUCK_AI_INPUT_SCREEN_USER_SETTING] } ?: false
@@ -182,6 +196,8 @@ class SharedPreferencesDuckChatDataStore @Inject constructor(
182196

183197
override suspend fun getShowInAddressBar(): Boolean = store.data.firstOrNull()?.defaultShowInAddressBar() ?: true
184198

199+
override suspend fun isFullScreenUserSettingEnabled(): Boolean = store.data.firstOrNull()?.let { it[DUCK_CHAT_FULLSCREEN_MODE_SETTING] } ?: false
200+
185201
override suspend fun fetchAndClearUserPreferences(): String? {
186202
val userPreferences = store.data.map { it[DUCK_CHAT_USER_PREFERENCES] }.firstOrNull()
187203
store.edit { prefs -> prefs.remove(DUCK_CHAT_USER_PREFERENCES) }

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class DuckChatSettingsActivity : DuckDuckGoActivity() {
6767
updateWidgets()
6868
}
6969

70+
private val userEnabledDuckChatFullScreenModeListener =
71+
CompoundButton.OnCheckedChangeListener { _, isChecked ->
72+
viewModel.onDuckChatFullscreenModeToggled(isChecked)
73+
}
74+
7075
@Inject
7176
lateinit var globalActivityStarter: GlobalActivityStarter
7277

@@ -190,6 +195,10 @@ class DuckChatSettingsActivity : DuckDuckGoActivity() {
190195
binding.duckAiInputScreenWithAiContainer.setOnClickListener {
191196
viewModel.onDuckAiInputScreenWithAiSelected()
192197
}
198+
199+
binding.duckAiFullScreenMode.isVisible = viewState.shouldShowFullScreenModeToggle
200+
binding.duckAiFullScreenMode.updatePadding(left = offset)
201+
binding.duckAiFullScreenMode.quietlySetIsChecked(viewState.isFullScreenModeEnabled, userEnabledDuckChatFullScreenModeListener)
193202
}
194203

195204
private fun processCommand(command: DuckChatSettingsViewModel.Command) {

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,25 @@ class DuckChatSettingsViewModel @Inject constructor(
5959
val shouldShowShortcuts: Boolean = false,
6060
val shouldShowInputScreenToggle: Boolean = false,
6161
val isHideGeneratedImagesOptionVisible: Boolean = false,
62+
val shouldShowFullScreenModeToggle: Boolean = false,
63+
val isFullScreenModeEnabled: Boolean = false,
6264
)
6365

6466
val viewState =
6567
combine(
6668
duckChat.observeEnableDuckChatUserSetting(),
6769
duckChat.observeInputScreenUserSettingEnabled(),
70+
duckChat.observeFullscreenModeUserSetting(),
6871
flowOf(settingsPageFeature.hideAiGeneratedImagesOption().isEnabled()).flowOn(dispatcherProvider.io()),
69-
) { isDuckChatUserEnabled, isInputScreenEnabled, isHideAiGeneratedImagesOptionVisible ->
72+
) { isDuckChatUserEnabled, isInputScreenEnabled, isFullScreenModeEnabled, isHideAiGeneratedImagesOptionVisible ->
7073
ViewState(
7174
isDuckChatUserEnabled = isDuckChatUserEnabled,
7275
isInputScreenEnabled = isInputScreenEnabled,
7376
shouldShowShortcuts = isDuckChatUserEnabled,
7477
shouldShowInputScreenToggle = isDuckChatUserEnabled && duckChat.isInputScreenFeatureAvailable(),
7578
isHideGeneratedImagesOptionVisible = isHideAiGeneratedImagesOptionVisible,
79+
shouldShowFullScreenModeToggle = duckChat.isDuckChatFeatureEnabled(),
80+
isFullScreenModeEnabled = isFullScreenModeEnabled,
7681
)
7782
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), ViewState())
7883

@@ -190,6 +195,12 @@ class DuckChatSettingsViewModel @Inject constructor(
190195
}
191196
}
192197

198+
fun onDuckChatFullscreenModeToggled(checked: Boolean) {
199+
viewModelScope.launch {
200+
duckChat.setFullScreenModeUserSetting(checked)
201+
}
202+
}
203+
193204
companion object {
194205
const val DUCK_CHAT_LEARN_MORE_LINK = "https://duckduckgo.com/duckduckgo-help-pages/aichat/"
195206
const val DUCK_CHAT_SEARCH_AI_SETTINGS_LINK = "https://duckduckgo.com/settings?ko=-1#aifeatures"

duckchat/duckchat-impl/src/main/res/layout/activity_duck_chat_settings.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@
194194
app:textType="secondary"
195195
app:typography="body2" />
196196

197+
<com.duckduckgo.common.ui.view.listitem.TwoLineListItem
198+
android:id="@+id/duckAiFullScreenMode"
199+
android:layout_width="match_parent"
200+
android:layout_height="wrap_content"
201+
android:visibility="gone"
202+
app:showSwitch="true"
203+
app:primaryText="@string/duckAiFullScreenModeTitle"
204+
app:secondaryText="@string/duckAiFullScreenModeDescription" />
205+
197206
<com.duckduckgo.common.ui.view.listitem.TwoLineListItem
198207
android:id="@+id/duckAiShortcuts"
199208
android:layout_width="match_parent"

duckchat/duckchat-impl/src/main/res/values/donottranslate.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@
2424
<!-- Duck AI Hide Generated Images Settings Option -->
2525
<string name="duckAiHideAiGeneratedImagesTitle">Hide AI-Generated Images</string>
2626
<string name="duckAiHideAiGeneratedImagesDescription">Filters out AI-generated images from image search results</string>
27+
28+
<!-- Duck AI Fullscreen Mode -->
29+
<string name="duckAiFullScreenModeTitle">Full Screen Mode</string>
30+
<string name="duckAiFullScreenModeDescription">Internal setting for O-J work</string>
2731
</resources>

0 commit comments

Comments
 (0)