Skip to content

Commit 3b85e46

Browse files
authored
restore last selected Duck.ai input screen mode (#6304)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1208671518894266/task/1210658958592463 ### Description Persist the last used Input Screen mode and restore it when user opens the screen again. ### Steps to test this PR - [x] Open Input Screen, select Duck.ai - [x] Go back - [x] Reopen the screen and verify Duck.ai is selected
1 parent 850f1bf commit 3b85e46

File tree

5 files changed

+108
-5
lines changed

5 files changed

+108
-5
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,6 @@ class DuckChatOmnibarLayout @JvmOverloads constructor(
106106
configureInputBehavior()
107107
configureTabBehavior()
108108
applyModeSpecificInputBehaviour(isSearchTab = true)
109-
110-
onSearchSelected?.invoke()
111109
}
112110

113111
private fun configureClickListeners() {

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import com.duckduckgo.duckchat.api.DuckChat
3636
import com.duckduckgo.duckchat.impl.R
3737
import com.duckduckgo.duckchat.impl.databinding.FragmentSearchInterstitialBinding
3838
import com.duckduckgo.duckchat.impl.ui.inputscreen.Command
39+
import com.duckduckgo.duckchat.impl.ui.inputscreen.Command.SwitchModeToChat
40+
import com.duckduckgo.duckchat.impl.ui.inputscreen.Command.SwitchModeToSearch
3941
import com.duckduckgo.duckchat.impl.ui.inputscreen.Command.UserSubmittedQuery
4042
import com.duckduckgo.duckchat.impl.ui.inputscreen.InputScreenViewModel
4143
import com.duckduckgo.navigation.api.getActivityParams
@@ -121,8 +123,19 @@ class SearchInterstitialFragment : DuckDuckGoFragment(R.layout.fragment_search_i
121123
}
122124

123125
private fun processCommand(command: Command) {
124-
if (command is UserSubmittedQuery) {
125-
binding.duckChatOmnibar.submitMessage(command.query)
126+
when (command) {
127+
is UserSubmittedQuery -> binding.duckChatOmnibar.submitMessage(command.query)
128+
SwitchModeToSearch -> {
129+
binding.viewPager.setCurrentItem(0, false)
130+
}
131+
132+
SwitchModeToChat -> {
133+
binding.viewPager.setCurrentItem(1, false)
134+
}
135+
136+
else -> {
137+
// TODO handle other commands
138+
}
126139
}
127140
}
128141

@@ -134,7 +147,6 @@ class SearchInterstitialFragment : DuckDuckGoFragment(R.layout.fragment_search_i
134147

135148
private fun configureOmnibar() = with(binding.duckChatOmnibar) {
136149
setContentId(R.id.viewPager)
137-
selectTab(0)
138150

139151
onSearchSent = { query ->
140152
val data = Intent().putExtra(SearchInterstitialActivity.QUERY, query)
@@ -153,10 +165,12 @@ class SearchInterstitialFragment : DuckDuckGoFragment(R.layout.fragment_search_i
153165
onSearchSelected = {
154166
binding.actionSend.icon = AppCompatResources.getDrawable(context, com.duckduckgo.mobile.android.R.drawable.ic_find_search_24)
155167
binding.viewPager.setCurrentItem(0, true)
168+
viewModel.onSearchSelected()
156169
}
157170
onDuckChatSelected = {
158171
binding.actionSend.icon = AppCompatResources.getDrawable(context, R.drawable.ic_arrow_up_24)
159172
binding.viewPager.setCurrentItem(1, true)
173+
viewModel.onChatSelected()
160174
}
161175
onSendMessageAvailable = { isAvailable ->
162176
binding.actionSend.isVisible = isAvailable

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/inputscreen/Command.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ sealed class Command {
2424
data class SwitchToTab(val tabId: String) : Command()
2525
data class UserSubmittedQuery(val query: String) : Command()
2626
data class EditWithSelectedQuery(val query: String) : Command()
27+
data object SwitchModeToSearch : Command()
28+
data object SwitchModeToChat : Command()
2729
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2025 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.duckchat.impl.ui.inputscreen
18+
19+
import androidx.datastore.core.DataStore
20+
import androidx.datastore.preferences.core.Preferences
21+
import androidx.datastore.preferences.core.edit
22+
import androidx.datastore.preferences.core.stringPreferencesKey
23+
import com.duckduckgo.di.scopes.FragmentScope
24+
import com.duckduckgo.duckchat.impl.di.DuckChat
25+
import com.squareup.anvil.annotations.ContributesBinding
26+
import javax.inject.Inject
27+
import kotlinx.coroutines.flow.firstOrNull
28+
import kotlinx.coroutines.flow.map
29+
30+
interface InputScreenDataStore {
31+
suspend fun getLastUsedMode(): InputScreenMode?
32+
suspend fun setLastUsedMode(mode: InputScreenMode)
33+
}
34+
35+
enum class InputScreenMode {
36+
CHAT,
37+
SEARCH,
38+
;
39+
}
40+
41+
@ContributesBinding(FragmentScope::class)
42+
class InputScreenDataStoreImpl @Inject constructor(
43+
@DuckChat private val dataStore: DataStore<Preferences>,
44+
) : InputScreenDataStore {
45+
46+
private val lastUsedModeKey = stringPreferencesKey("duck.ai_input-screen_last-used-mode")
47+
48+
override suspend fun getLastUsedMode(): InputScreenMode? {
49+
return dataStore.data.map { preferences ->
50+
preferences[lastUsedModeKey]?.let { modeString ->
51+
try {
52+
InputScreenMode.valueOf(modeString)
53+
} catch (e: IllegalArgumentException) {
54+
null
55+
}
56+
}
57+
}.firstOrNull()
58+
}
59+
60+
override suspend fun setLastUsedMode(mode: InputScreenMode) {
61+
dataStore.edit { preferences ->
62+
preferences[lastUsedModeKey] = mode.name
63+
}
64+
}
65+
}

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/inputscreen/InputScreenViewModel.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class InputScreenViewModel @Inject constructor(
7070
private val history: NavigationHistory,
7171
savedSitesRepository: SavedSitesRepository,
7272
@AppCoroutineScope private val appCoroutineScope: CoroutineScope,
73+
private val inputScreenDataStore: InputScreenDataStore,
7374
) : ViewModel() {
7475

7576
private var hasUserSeenHistoryIAM = false
@@ -105,6 +106,17 @@ class InputScreenViewModel @Inject constructor(
105106
}
106107
}
107108
.launchIn(viewModelScope)
109+
110+
viewModelScope.launch {
111+
inputScreenDataStore.getLastUsedMode().let { mode ->
112+
command.value = when (mode) {
113+
null,
114+
InputScreenMode.SEARCH,
115+
-> Command.SwitchModeToSearch
116+
InputScreenMode.CHAT -> Command.SwitchModeToChat
117+
}
118+
}
119+
}
108120
}
109121

110122
@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
@@ -275,4 +287,16 @@ class InputScreenViewModel @Inject constructor(
275287
autoCompleteJob.cancel()
276288
}
277289
}
290+
291+
fun onSearchSelected() {
292+
viewModelScope.launch {
293+
inputScreenDataStore.setLastUsedMode(InputScreenMode.SEARCH)
294+
}
295+
}
296+
297+
fun onChatSelected() {
298+
viewModelScope.launch {
299+
inputScreenDataStore.setLastUsedMode(InputScreenMode.CHAT)
300+
}
301+
}
278302
}

0 commit comments

Comments
 (0)