Skip to content

Commit dad094b

Browse files
authored
Fix AppTP scrolling behavior on the Input Screen (#6632)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1208671518894266/task/1210986778088959?focus=true ### Description Fixes an issue where the AppTP banner wouldn't scroll on the Input Screen until bounds of the scrolling container where reached. Also adds a dev tool to create/clear favorites and improves the existing one that adds bookmarks so that it doesn't generate duplicates. ### Steps to test this PR - [ ] Add enough favorites to cover the whole Input Screen - You can use a new option to generate favorites under Settings -> Developer Settings -> Tabs and Saved Sites - [ ] Enable AppTP - [ ] Open the Input Screen and verify that scrolling immediately scrolls the AppTP banner as well ### UI changes _Before_ https://github.com/user-attachments/assets/701b81e1-7476-46b7-a19b-e2c08e45737c _After_ https://github.com/user-attachments/assets/a87c5e10-fda2-4aa5-94ce-4a7aed558c1d
1 parent bb9abea commit dad094b

File tree

5 files changed

+185
-8
lines changed

5 files changed

+185
-8
lines changed

app/src/internal/java/com/duckduckgo/app/dev/settings/tabs/DevTabsActivity.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ import androidx.lifecycle.lifecycleScope
2525
import com.duckduckgo.anvil.annotations.InjectWith
2626
import com.duckduckgo.app.browser.R
2727
import com.duckduckgo.app.browser.databinding.ActivityDevTabsBinding
28+
import com.duckduckgo.app.dev.settings.tabs.DevTabsViewModel.Command
29+
import com.duckduckgo.app.dev.settings.tabs.DevTabsViewModel.Command.NoMoreCandidatesForBookmarks
30+
import com.duckduckgo.app.dev.settings.tabs.DevTabsViewModel.Command.NoMoreCandidatesForFavorites
2831
import com.duckduckgo.app.dev.settings.tabs.DevTabsViewModel.ViewState
2932
import com.duckduckgo.app.notification.NotificationFactory
3033
import com.duckduckgo.common.ui.DuckDuckGoActivity
3134
import com.duckduckgo.common.ui.viewbinding.viewBinding
3235
import com.duckduckgo.di.scopes.ActivityScope
36+
import com.google.android.material.snackbar.Snackbar
3337
import javax.inject.Inject
3438
import kotlinx.coroutines.flow.launchIn
3539
import kotlinx.coroutines.flow.onEach
@@ -66,17 +70,43 @@ class DevTabsActivity : DuckDuckGoActivity() {
6670
viewModel.clearBookmarks()
6771
}
6872

73+
binding.addFavoritesButton.setOnClickListener {
74+
viewModel.addFavorites(binding.favoritesCount.text.toInt())
75+
}
76+
77+
binding.clearFavoritesButton.setOnClickListener {
78+
viewModel.clearFavorites()
79+
}
80+
6981
observeViewState()
82+
observeCommands()
7083
}
7184

7285
private fun observeViewState() {
7386
viewModel.viewState.flowWithLifecycle(lifecycle, STARTED).onEach { render(it) }
7487
.launchIn(lifecycleScope)
7588
}
7689

90+
private fun observeCommands() {
91+
viewModel.commands.flowWithLifecycle(lifecycle, STARTED).onEach { processCommand(it) }
92+
.launchIn(lifecycleScope)
93+
}
94+
7795
private fun render(viewState: ViewState) {
7896
binding.tabCountHeader.text = getString(R.string.devSettingsTabsScreenHeader, viewState.tabCount)
7997
binding.bookmarksCountHeader.text = getString(R.string.devSettingsTabsBookmarksScreenHeader, viewState.bookmarkCount)
98+
binding.favoritesCountHeader.text = getString(R.string.devSettingsTabsFavoritesScreenHeader, viewState.favoritesCount)
99+
}
100+
101+
private fun processCommand(command: Command) {
102+
when (command) {
103+
NoMoreCandidatesForBookmarks -> {
104+
Snackbar.make(binding.root, "No more bookmark candidates", Snackbar.LENGTH_LONG).show()
105+
}
106+
NoMoreCandidatesForFavorites -> {
107+
Snackbar.make(binding.root, "No more favorite candidates", Snackbar.LENGTH_LONG).show()
108+
}
109+
}
80110
}
81111

82112
companion object {

app/src/internal/java/com/duckduckgo/app/dev/settings/tabs/DevTabsViewModel.kt

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,22 @@ package com.duckduckgo.app.dev.settings.tabs
1919
import androidx.lifecycle.ViewModel
2020
import androidx.lifecycle.viewModelScope
2121
import com.duckduckgo.anvil.annotations.ContributesViewModel
22+
import com.duckduckgo.app.dev.settings.tabs.DevTabsViewModel.Command.NoMoreCandidatesForBookmarks
23+
import com.duckduckgo.app.dev.settings.tabs.DevTabsViewModel.Command.NoMoreCandidatesForFavorites
2224
import com.duckduckgo.app.tabs.model.TabDataRepository
2325
import com.duckduckgo.common.utils.DispatcherProvider
2426
import com.duckduckgo.di.scopes.ActivityScope
2527
import com.duckduckgo.savedsites.api.SavedSitesRepository
2628
import javax.inject.Inject
29+
import kotlinx.coroutines.channels.Channel
30+
import kotlinx.coroutines.flow.Flow
2731
import kotlinx.coroutines.flow.MutableStateFlow
2832
import kotlinx.coroutines.flow.asStateFlow
33+
import kotlinx.coroutines.flow.firstOrNull
2934
import kotlinx.coroutines.flow.flowOn
3035
import kotlinx.coroutines.flow.launchIn
3136
import kotlinx.coroutines.flow.onEach
37+
import kotlinx.coroutines.flow.receiveAsFlow
3238
import kotlinx.coroutines.flow.update
3339
import kotlinx.coroutines.launch
3440

@@ -53,6 +59,16 @@ private val randomUrls = listOf(
5359
"https://debian.org",
5460
"https://ubuntu.com",
5561
"https://openbsd.org",
62+
"https://letsencrypt.org",
63+
"https://wikimedia.org",
64+
"https://creativecommons.org",
65+
"https://openstreetmap.org",
66+
"https://kde.org",
67+
"https://gnome.org",
68+
"https://blender.org",
69+
"https://python.org",
70+
"https://matrix.org",
71+
"https://github.com/duckduckgo/Android",
5672
)
5773

5874
@ContributesViewModel(ActivityScope::class)
@@ -65,11 +81,15 @@ class DevTabsViewModel @Inject constructor(
6581
data class ViewState(
6682
val tabCount: Int = 0,
6783
val bookmarkCount: Int = 0,
84+
val favoritesCount: Int = 0,
6885
)
6986

7087
private val _viewState = MutableStateFlow(ViewState())
7188
val viewState = _viewState.asStateFlow()
7289

90+
private val _commands = Channel<Command>(capacity = Channel.CONFLATED)
91+
val commands: Flow<Command> = _commands.receiveAsFlow()
92+
7393
init {
7494
tabDataRepository.flowTabs
7595
.onEach { tabs ->
@@ -84,6 +104,13 @@ class DevTabsViewModel @Inject constructor(
84104
}
85105
.flowOn(dispatcher.io())
86106
.launchIn(viewModelScope)
107+
108+
savedSitesRepository.getFavorites()
109+
.onEach { favorites ->
110+
_viewState.update { it.copy(favoritesCount = favorites.count()) }
111+
}
112+
.flowOn(dispatcher.io())
113+
.launchIn(viewModelScope)
87114
}
88115

89116
fun addTabs(count: Int) {
@@ -105,12 +132,21 @@ class DevTabsViewModel @Inject constructor(
105132

106133
fun addBookmarks(count: Int) {
107134
viewModelScope.launch(dispatcher.io()) {
135+
val candidates = randomUrls.filter {
136+
savedSitesRepository.getBookmark(url = it) == null
137+
}.toMutableSet()
108138
repeat(count) {
109-
val randomIndex = randomUrls.indices.random()
110-
savedSitesRepository.insertBookmark(
111-
title = "",
112-
url = randomUrls[randomIndex],
113-
)
139+
if (candidates.size > 0) {
140+
val candidate = candidates.random()
141+
savedSitesRepository.insertBookmark(
142+
title = "",
143+
url = candidate,
144+
)
145+
candidates.remove(candidate)
146+
} else {
147+
_commands.trySend(NoMoreCandidatesForBookmarks)
148+
return@repeat
149+
}
114150
}
115151
}
116152
}
@@ -120,4 +156,38 @@ class DevTabsViewModel @Inject constructor(
120156
savedSitesRepository.deleteAll()
121157
}
122158
}
159+
160+
fun addFavorites(count: Int) {
161+
viewModelScope.launch(dispatcher.io()) {
162+
val candidates = randomUrls.filter {
163+
savedSitesRepository.getFavorite(url = it) == null
164+
}.toMutableSet()
165+
repeat(count) {
166+
if (candidates.size > 0) {
167+
val candidate = candidates.random()
168+
savedSitesRepository.insertFavorite(
169+
title = "",
170+
url = candidate,
171+
)
172+
candidates.remove(candidate)
173+
} else {
174+
_commands.trySend(NoMoreCandidatesForFavorites)
175+
return@repeat
176+
}
177+
}
178+
}
179+
}
180+
181+
fun clearFavorites() {
182+
viewModelScope.launch(dispatcher.io()) {
183+
savedSitesRepository.getFavorites().firstOrNull()?.forEach {
184+
savedSitesRepository.delete(it)
185+
}
186+
}
187+
}
188+
189+
sealed class Command {
190+
data object NoMoreCandidatesForBookmarks : Command()
191+
data object NoMoreCandidatesForFavorites : Command()
192+
}
123193
}

app/src/internal/res/layout/activity_dev_tabs.xml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,5 +173,78 @@
173173

174174
</androidx.constraintlayout.widget.ConstraintLayout>
175175

176+
<Space
177+
android:layout_width="match_parent"
178+
android:layout_height="8dp" />
179+
180+
<com.duckduckgo.common.ui.view.text.DaxTextView
181+
android:id="@+id/favoritesCountHeader"
182+
android:layout_width="match_parent"
183+
android:layout_height="48dp"
184+
android:gravity="center"
185+
android:text="@string/devSettingsTabsFavoritesScreenHeader"
186+
app:typography="caption_allCaps" />
187+
188+
<Space
189+
android:layout_width="match_parent"
190+
android:layout_height="8dp" />
191+
192+
<androidx.constraintlayout.widget.ConstraintLayout
193+
android:layout_width="match_parent"
194+
android:layout_height="wrap_content">
195+
196+
<com.duckduckgo.common.ui.view.listitem.OneLineListItem
197+
android:id="@+id/generateFavoritesItem"
198+
android:layout_width="0dp"
199+
android:layout_height="wrap_content"
200+
app:layout_constraintEnd_toStartOf="@id/favoritesCount"
201+
app:layout_constraintStart_toStartOf="parent"
202+
app:layout_constraintTop_toTopOf="parent"
203+
app:primaryText="@string/devSettingsTabsScreenFavoritesToAdd" />
204+
205+
<com.duckduckgo.common.ui.view.text.DaxTextInput
206+
android:id="@+id/favoritesCount"
207+
style="@style/Widget.DuckDuckGo.TextInput"
208+
android:layout_width="72dp"
209+
android:layout_height="wrap_content"
210+
android:layout_marginEnd="@dimen/keyline_4"
211+
android:gravity="center"
212+
android:inputType="number"
213+
android:text="25"
214+
app:layout_constraintBottom_toBottomOf="@id/generateFavoritesItem"
215+
app:layout_constraintEnd_toEndOf="parent"
216+
app:layout_constraintStart_toEndOf="@id/generateFavoritesItem"
217+
app:layout_constraintTop_toTopOf="@id/generateFavoritesItem"
218+
app:type="single_line"
219+
tools:ignore="HardcodedText" />
220+
221+
<com.duckduckgo.common.ui.view.button.DaxButtonPrimary
222+
android:id="@+id/addFavoritesButton"
223+
android:layout_width="wrap_content"
224+
android:layout_height="wrap_content"
225+
android:layout_marginTop="@dimen/keyline_4"
226+
android:text="@string/devSettingsTabsScreenAddFavoritesButtonText"
227+
app:daxButtonSize="large" />
228+
229+
<com.duckduckgo.common.ui.view.button.DaxButtonPrimary
230+
android:id="@+id/clearFavoritesButton"
231+
android:layout_width="wrap_content"
232+
android:layout_height="wrap_content"
233+
android:layout_marginTop="@dimen/keyline_4"
234+
android:text="@string/devSettingsTabsScreenClearFavoritesButtonText"
235+
app:daxButtonSize="large" />
236+
237+
<androidx.constraintlayout.helper.widget.Flow
238+
android:id="@+id/favoritesFlowView"
239+
android:layout_width="match_parent"
240+
android:layout_height="0dp"
241+
android:layout_marginTop="@dimen/keyline_4"
242+
app:constraint_referenced_ids="addFavoritesButton,clearFavoritesButton"
243+
app:flow_horizontalStyle="spread"
244+
app:flow_wrapMode="chain"
245+
app:layout_constraintTop_toBottomOf="@id/generateFavoritesItem" />
246+
247+
</androidx.constraintlayout.widget.ConstraintLayout>
248+
176249
</LinearLayout>
177250
</LinearLayout>

app/src/internal/res/values/donottranslate.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,13 @@
5454
<string name="devSettingsTabsScreenAddTabsButtonText">Add Tabs</string>
5555
<string name="devSettingsTabsScreenClearTabsButtonText">Clear Tabs</string>
5656
<string name="devSettingsTabsBookmarksScreenHeader" instruction="Not translated">Current bookmarks count: %1$d</string>
57+
<string name="devSettingsTabsFavoritesScreenHeader" instruction="Not translated">Current favorites count: %1$d</string>
5758
<string name="devSettingsTabsScreenBookmarksToAdd">Bookmarks to add</string>
59+
<string name="devSettingsTabsScreenFavoritesToAdd">Favorites to add</string>
5860
<string name="devSettingsTabsScreenAddBookmarksButtonText">Add Bookmarks</string>
61+
<string name="devSettingsTabsScreenAddFavoritesButtonText">Add Favorites</string>
5962
<string name="devSettingsTabsScreenClearBookmarksButtonText">Clear Bookmarks</string>
63+
<string name="devSettingsTabsScreenClearFavoritesButtonText">Clear Favorites</string>
6064

6165
<!-- Privacy Audit settings -->
6266
<string name="auditSettingsTitle">Audit Settings</string>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@
2222
android:layout_width="match_parent"
2323
android:layout_height="match_parent">
2424

25-
<ScrollView
25+
<androidx.core.widget.NestedScrollView
2626
android:id="@+id/newTabContainerScrollView"
2727
android:layout_width="match_parent"
2828
android:layout_height="match_parent">
2929

3030
<FrameLayout
3131
android:id="@+id/newTabContainerLayout"
3232
android:layout_width="match_parent"
33-
android:layout_height="wrap_content" />
33+
android:layout_height="match_parent" />
3434

35-
</ScrollView>
35+
</androidx.core.widget.NestedScrollView>
3636

3737
<FrameLayout
3838
android:id="@+id/bottomFadeContainer"

0 commit comments

Comments
 (0)