Skip to content

Commit 07ea263

Browse files
maintain single Dax logo across Input Screen tabs (#6541)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1208671518894266/task/1210953046407347?focus=true ### Description Adds a single Dax logo container underneath Search and Chat mode pages, and swaps the icons as the page changes. Depends on #6539 and #6543. ### Steps to test this PR - [x] Clear favorites and open new tab. - [x] Open Input Screen. - [x] Verify you see Dax logo. - [x] Scroll/click to Chat Mode. - [x] Verify you see Dax AI logo and the transition was an instant swap. - [x] Go back to Search Mode and trigger autocomplete. - [x] Go to Chat Mode and verify there's no Dax. - [x] Go back to Search mode and verify you continue to see autocomplete suggestions and there was no blink of Dax logo while transitioning. - [x] Go to a page and add a favorite. - [x] Open Input Screen from a web page (not from SERP) or new tab page and verify you see the favorite icon and no Dax logo. - [x] Go to Chat Mode and verify that Dax AI logo fades in as the mode changes. - [x] Go back to Search Mode and verify you see a favorite and Dax logo is gone. --------- Co-authored-by: joshliebe <[email protected]>
1 parent f61a3f8 commit 07ea263

File tree

10 files changed

+285
-197
lines changed

10 files changed

+285
-197
lines changed

common/common-ui/src/main/res/drawable/logo_full.xml

Lines changed: 33 additions & 43 deletions
Large diffs are not rendered by default.

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,14 @@ class InputScreenFragment : DuckDuckGoFragment(R.layout.fragment_input_screen) {
160160
viewModel.inputFieldState.onEach { inputBoxState ->
161161
binding.inputModeWidget.canExpand = inputBoxState.canExpand
162162
}.launchIn(lifecycleScope)
163+
164+
viewModel.visibilityState.onEach {
165+
binding.ddgLogo.isVisible = if (binding.viewPager.currentItem == 0) {
166+
it.showSearchLogo
167+
} else {
168+
it.showChatLogo
169+
}
170+
}.launchIn(lifecycleScope)
163171
}
164172

165173
private fun processCommand(command: Command) {
@@ -197,11 +205,25 @@ class InputScreenFragment : DuckDuckGoFragment(R.layout.fragment_input_screen) {
197205
onSearchSelected = {
198206
binding.viewPager.setCurrentItem(0, true)
199207
viewModel.onSearchInputTextChanged(binding.inputModeWidget.text)
208+
binding.ddgLogo.apply {
209+
setImageResource(com.duckduckgo.mobile.android.R.drawable.logo_full)
210+
isVisible = viewModel.visibilityState.value.showSearchLogo
211+
}
200212
}
201213
onChatSelected = {
202214
binding.viewPager.setCurrentItem(1, true)
203215
viewModel.onChatSelected()
204216
viewModel.onChatInputTextChanged(binding.inputModeWidget.text)
217+
binding.ddgLogo.apply {
218+
setImageResource(R.drawable.logo_full_ai)
219+
val showChatLogo = viewModel.visibilityState.value.showChatLogo
220+
val showSearchLogo = viewModel.visibilityState.value.showSearchLogo
221+
isVisible = showChatLogo
222+
if (showChatLogo && !showSearchLogo) {
223+
alpha = 0f
224+
animate().alpha(1f).setDuration(200L).start()
225+
}
226+
}
205227
}
206228
onSubmitMessageAvailable = { isAvailable ->
207229
binding.actionSend.isVisible = isAvailable

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ data class InputScreenVisibilityState(
2020
val voiceInputButtonVisible: Boolean,
2121
val autoCompleteSuggestionsVisible: Boolean,
2222
val showChatLogo: Boolean,
23+
val showSearchLogo: Boolean,
2324
)

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

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,43 +16,10 @@
1616

1717
package com.duckduckgo.duckchat.impl.inputscreen.ui.tabs
1818

19-
import android.os.Bundle
20-
import android.view.View
21-
import androidx.core.view.isVisible
22-
import androidx.lifecycle.ViewModelProvider
23-
import androidx.lifecycle.lifecycleScope
2419
import com.duckduckgo.anvil.annotations.InjectWith
2520
import com.duckduckgo.common.ui.DuckDuckGoFragment
26-
import com.duckduckgo.common.ui.viewbinding.viewBinding
27-
import com.duckduckgo.common.utils.FragmentViewModelFactory
2821
import com.duckduckgo.di.scopes.FragmentScope
2922
import com.duckduckgo.duckchat.impl.R
30-
import com.duckduckgo.duckchat.impl.databinding.FragmentChatTabBinding
31-
import com.duckduckgo.duckchat.impl.inputscreen.ui.viewmodel.InputScreenViewModel
32-
import javax.inject.Inject
33-
import kotlinx.coroutines.flow.launchIn
34-
import kotlinx.coroutines.flow.onEach
3523

3624
@InjectWith(FragmentScope::class)
37-
class ChatTabFragment : DuckDuckGoFragment(R.layout.fragment_chat_tab) {
38-
39-
@Inject
40-
lateinit var viewModelFactory: FragmentViewModelFactory
41-
42-
private val viewModel: InputScreenViewModel by lazy {
43-
ViewModelProvider(requireParentFragment(), viewModelFactory)[InputScreenViewModel::class.java]
44-
}
45-
46-
private val binding: FragmentChatTabBinding by viewBinding()
47-
48-
override fun onViewCreated(
49-
view: View,
50-
savedInstanceState: Bundle?,
51-
) {
52-
super.onViewCreated(view, savedInstanceState)
53-
54-
viewModel.visibilityState.onEach {
55-
binding.ddgLogo.isVisible = it.showChatLogo
56-
}.launchIn(lifecycleScope)
57-
}
58-
}
25+
class ChatTabFragment : DuckDuckGoFragment(R.layout.fragment_chat_tab)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ class SearchTabFragment : DuckDuckGoFragment(R.layout.fragment_search_tab) {
102102
// TODO: fix favorites click source to "focused state" instead of "new tab page"
103103
lifecycleScope.launch {
104104
newTabPagePlugins.getPlugins().firstOrNull()?.let { plugin ->
105-
val newTabPageView = plugin.getView(requireContext())
105+
val newTabPageView = plugin.getView(requireContext(), showLogo = false) { hasContent ->
106+
viewModel.onNewTabPageContentChanged(hasContent)
107+
}
106108
binding.newTabContainerLayout.addView(newTabPageView)
107109
}
108110
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,15 @@ class InputScreenViewModel @AssistedInject constructor(
9494

9595
private var hasUserSeenHistoryIAM = false
9696

97+
private val newTabPageHasContent = MutableStateFlow(false)
9798
private val voiceServiceAvailable = MutableStateFlow(voiceSearchAvailability.isVoiceSearchAvailable)
9899
private val voiceInputAllowed = MutableStateFlow(true)
99100
private val _visibilityState = MutableStateFlow(
100101
InputScreenVisibilityState(
101102
voiceInputButtonVisible = voiceServiceAvailable.value && voiceInputAllowed.value,
102103
autoCompleteSuggestionsVisible = false,
103104
showChatLogo = true,
105+
showSearchLogo = true,
104106
),
105107
)
106108
val visibilityState: StateFlow<InputScreenVisibilityState> = _visibilityState.asStateFlow()
@@ -213,6 +215,14 @@ class InputScreenViewModel @AssistedInject constructor(
213215
it.copy(autoCompleteSuggestionsVisible = showAutoComplete)
214216
}
215217
}.launchIn(viewModelScope)
218+
219+
combine(newTabPageHasContent, shouldShowAutoComplete) { newTabPageHasContent, shouldShowAutoComplete ->
220+
!newTabPageHasContent && !shouldShowAutoComplete
221+
}.onEach { shouldShowSearchLogo ->
222+
_visibilityState.update {
223+
it.copy(showSearchLogo = shouldShowSearchLogo)
224+
}
225+
}.launchIn(viewModelScope)
216226
}
217227

218228
fun onActivityResume() {
@@ -377,6 +387,10 @@ class InputScreenViewModel @AssistedInject constructor(
377387
showKeyboard()
378388
}
379389

390+
fun onNewTabPageContentChanged(hasContent: Boolean) {
391+
newTabPageHasContent.value = hasContent
392+
}
393+
380394
private fun checkMovedBeyondInitialUrl(searchInput: String): Boolean {
381395
// check if user modified input or initial text wasn't a webpage URL
382396
val userHasModifiedInput = initialSearchInputText != searchInput

0 commit comments

Comments
 (0)