Skip to content

Commit a5a96b2

Browse files
committed
refactor find in page feature for FadeOmnibarLayout
1 parent c0e2247 commit a5a96b2

File tree

12 files changed

+375
-61
lines changed

12 files changed

+375
-61
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.app.browser.omnibar
18+
19+
import android.view.ViewGroup
20+
import android.widget.EditText
21+
import android.widget.ImageView
22+
import com.duckduckgo.app.browser.databinding.IncludeFadeOmnibarFindInPageBinding
23+
import com.duckduckgo.app.browser.databinding.IncludeFindInPageBinding
24+
import com.duckduckgo.common.ui.view.text.DaxTextView
25+
26+
/**
27+
* Compatibility interface for accessing [IncludeFindInPageBinding] or [IncludeFadeOmnibarFindInPageBinding], depending on which omnibar is used.
28+
*/
29+
interface FindInPage {
30+
val findInPageContainer: ViewGroup
31+
val findInPageInput: EditText
32+
val findInPageMatches: DaxTextView
33+
val previousSearchTermButton: ImageView
34+
val nextSearchTermButton: ImageView
35+
val closeFindInPagePanel: ImageView
36+
}
37+
38+
class FindInPageImpl(
39+
override val findInPageContainer: ViewGroup,
40+
override val findInPageInput: EditText,
41+
override val findInPageMatches: DaxTextView,
42+
override val previousSearchTermButton: ImageView,
43+
override val nextSearchTermButton: ImageView,
44+
override val closeFindInPagePanel: ImageView,
45+
) : FindInPage {
46+
47+
constructor(binding: IncludeFindInPageBinding) : this(
48+
findInPageContainer = binding.findInPageContainer,
49+
findInPageInput = binding.findInPageInput,
50+
findInPageMatches = binding.findInPageMatches,
51+
previousSearchTermButton = binding.previousSearchTermButton,
52+
nextSearchTermButton = binding.nextSearchTermButton,
53+
closeFindInPagePanel = binding.closeFindInPagePanel,
54+
)
55+
56+
constructor(binding: IncludeFadeOmnibarFindInPageBinding) : this(
57+
findInPageContainer = binding.findInPageContainer,
58+
findInPageInput = binding.findInPageInput,
59+
findInPageMatches = binding.findInPageMatches,
60+
previousSearchTermButton = binding.previousSearchTermButton,
61+
nextSearchTermButton = binding.nextSearchTermButton,
62+
closeFindInPagePanel = binding.closeFindInPagePanel,
63+
)
64+
}

app/src/main/java/com/duckduckgo/app/browser/omnibar/Omnibar.kt

+5-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import com.airbnb.lottie.LottieAnimationView
2828
import com.duckduckgo.app.browser.BrowserTabFragment.Companion.KEYBOARD_DELAY
2929
import com.duckduckgo.app.browser.R
3030
import com.duckduckgo.app.browser.databinding.FragmentBrowserTabBinding
31-
import com.duckduckgo.app.browser.databinding.IncludeFindInPageBinding
3231
import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView
3332
import com.duckduckgo.app.browser.omnibar.Omnibar.ViewMode.CustomTab
3433
import com.duckduckgo.app.browser.omnibar.Omnibar.ViewMode.Error
@@ -62,8 +61,6 @@ import com.duckduckgo.common.ui.view.showKeyboard
6261
import com.duckduckgo.common.utils.extensions.replaceTextChangedListener
6362
import com.duckduckgo.common.utils.extractDomain
6463
import com.duckduckgo.common.utils.text.TextChangedWatcher
65-
import com.google.android.material.appbar.AppBarLayout.GONE
66-
import com.google.android.material.appbar.AppBarLayout.VISIBLE
6764
import kotlinx.coroutines.flow.distinctUntilChanged
6865
import timber.log.Timber
6966

@@ -208,7 +205,7 @@ class Omnibar(
208205
}
209206
}
210207

211-
private val findInPage: IncludeFindInPageBinding by lazy {
208+
private val findInPage: FindInPage by lazy {
212209
newOmnibar.findInPage
213210
}
214211

@@ -325,17 +322,17 @@ class Omnibar(
325322
}
326323

327324
fun hideFindInPage() {
328-
if (findInPage.findInPageContainer.visibility != GONE) {
325+
if (newOmnibar.isFindInPageVisible()) {
329326
binding.focusDummy.requestFocus()
330-
findInPage.findInPageContainer.gone()
327+
newOmnibar.hideFindInPage()
331328
findInPage.findInPageInput.hideKeyboard()
332329
findInPage.findInPageInput.text.clear()
333330
}
334331
}
335332

336333
fun showFindInPageView(viewState: FindInPageViewState) {
337-
if (findInPage.findInPageContainer.visibility != VISIBLE) {
338-
findInPage.findInPageContainer.show()
334+
if (!newOmnibar.isFindInPageVisible()) {
335+
newOmnibar.showFindInPage()
339336
findInPage.findInPageInput.postDelayed(KEYBOARD_DELAY) {
340337
findInPage.findInPageInput.showKeyboard()
341338
}

app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarLayout.kt

+18-7
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.HighlightOmni
5757
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.LaunchCookiesAnimation
5858
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.LaunchTrackersAnimation
5959
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.Mode
60-
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.Outline
6160
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.PrivacyShieldChanged
6261
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.QueueCookiesAnimation
6362
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command
@@ -125,7 +124,6 @@ open class OmnibarLayout @JvmOverloads constructor(
125124
val privacyShield: Boolean,
126125
) : Decoration()
127126

128-
data class Outline(val enabled: Boolean) : Decoration()
129127
data class DisableVoiceSearch(val url: String) : Decoration()
130128
}
131129

@@ -167,7 +165,9 @@ open class OmnibarLayout @JvmOverloads constructor(
167165
private var lastViewMode: Mode? = null
168166
private var stateBuffer: MutableList<StateChange> = mutableListOf()
169167

170-
internal val findInPage by lazy { IncludeFindInPageBinding.bind(findViewById(R.id.findInPage)) }
168+
internal open val findInPage: FindInPage by lazy {
169+
FindInPageImpl(IncludeFindInPageBinding.bind(findViewById(R.id.findInPage)))
170+
}
171171
internal val omnibarTextInput: KeyboardAwareEditText by lazy { findViewById(R.id.omnibarTextInput) }
172172
internal val tabsMenu: TabSwitcherButton by lazy { findViewById(R.id.tabsMenu) }
173173
internal val fireIconMenu: FrameLayout by lazy { findViewById(R.id.fireIconMenu) }
@@ -440,6 +440,7 @@ open class OmnibarLayout @JvmOverloads constructor(
440440
lastSeenPrivacyShield = null
441441
}
442442
renderButtons(viewState)
443+
renderFindInPage(viewState)
443444
}
444445

445446
open fun processCommand(command: OmnibarLayoutViewModel.Command) {
@@ -613,10 +614,6 @@ open class OmnibarLayout @JvmOverloads constructor(
613614
viewModel.onPrivacyShieldChanged(decoration.privacyShield)
614615
}
615616

616-
is Outline -> {
617-
viewModel.onOutlineEnabled(decoration.enabled)
618-
}
619-
620617
Decoration.CancelAnimations -> {
621618
cancelTrackersAnimation()
622619
}
@@ -656,6 +653,20 @@ open class OmnibarLayout @JvmOverloads constructor(
656653
}
657654
}
658655

656+
private fun renderFindInPage(viewState: ViewState) {
657+
findInPage.findInPageContainer.isVisible = viewState.findInPageVisible
658+
}
659+
660+
fun isFindInPageVisible(): Boolean = viewModel.viewState.value.findInPageVisible
661+
662+
fun showFindInPage() {
663+
viewModel.showFindInPage()
664+
}
665+
666+
fun hideFindInPage() {
667+
viewModel.hideFindInPage()
668+
}
669+
659670
private fun reduceDeferred(stateChange: StateChange) {
660671
viewModel.onExternalStateChange(stateChange)
661672
}

app/src/main/java/com/duckduckgo/app/browser/omnibar/OmnibarLayoutViewModel.kt

+16-9
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,11 @@ class OmnibarLayoutViewModel @Inject constructor(
145145
val experimentalIconsEnabled: Boolean = false,
146146
val trackersBlocked: Int = 0,
147147
val previouslyTrackersBlocked: Int = 0,
148+
val findInPageVisible: Boolean = false,
148149
) {
150+
151+
val outlineVisible: Boolean = hasFocus || findInPageVisible
152+
149153
fun shouldUpdateOmnibarText(): Boolean {
150154
return this.viewMode is Browser || this.viewMode is MaliciousSiteWarning
151155
}
@@ -374,15 +378,6 @@ class OmnibarLayoutViewModel @Inject constructor(
374378
}
375379
}
376380

377-
fun onOutlineEnabled(enabled: Boolean) {
378-
Timber.d("Omnibar: onOutlineEnabled")
379-
_viewState.update {
380-
it.copy(
381-
hasFocus = enabled,
382-
)
383-
}
384-
}
385-
386381
fun onClearTextButtonPressed() {
387382
Timber.d("Omnibar: onClearTextButtonPressed")
388383
firePixelBasedOnCurrentUrl(
@@ -707,4 +702,16 @@ class OmnibarLayoutViewModel @Inject constructor(
707702
}
708703
}
709704
}
705+
706+
fun showFindInPage() {
707+
_viewState.update {
708+
it.copy(findInPageVisible = true)
709+
}
710+
}
711+
712+
fun hideFindInPage() {
713+
_viewState.update {
714+
it.copy(findInPageVisible = false)
715+
}
716+
}
710717
}

app/src/main/java/com/duckduckgo/app/browser/omnibar/experiments/FadeOmnibarLayout.kt

+15-7
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ import androidx.core.view.marginTop
3232
import androidx.core.view.updatePadding
3333
import com.duckduckgo.anvil.annotations.InjectWith
3434
import com.duckduckgo.app.browser.R
35+
import com.duckduckgo.app.browser.databinding.IncludeFadeOmnibarFindInPageBinding
3536
import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView
37+
import com.duckduckgo.app.browser.omnibar.FindInPage
38+
import com.duckduckgo.app.browser.omnibar.FindInPageImpl
3639
import com.duckduckgo.app.browser.omnibar.Omnibar.ViewMode
3740
import com.duckduckgo.app.browser.omnibar.OmnibarLayout
3841
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.ViewState
@@ -57,6 +60,10 @@ class FadeOmnibarLayout @JvmOverloads constructor(
5760
private val omniBarContentContainer: View by lazy { findViewById(R.id.omniBarContentContainer) }
5861
private val backIcon: ImageView by lazy { findViewById(R.id.backIcon) }
5962

63+
override val findInPage: FindInPage by lazy {
64+
FindInPageImpl(IncludeFadeOmnibarFindInPageBinding.bind(findViewById(R.id.findInPage)))
65+
}
66+
6067
/**
6168
* Returns the [BrowserNavigationBarView] reference if it's embedded inside of this omnibar layout, otherwise, returns null.
6269
*/
@@ -158,8 +165,9 @@ class FadeOmnibarLayout @JvmOverloads constructor(
158165
backIcon.gone()
159166
}
160167

161-
omniBarContainer.isPressed = viewState.hasFocus
162-
if (viewState.hasFocus) {
168+
omniBarContentContainer.isVisible = !viewState.findInPageVisible
169+
170+
if (viewState.outlineVisible) {
163171
animateOmnibarFocusedState(focused = true)
164172
} else {
165173
animateOmnibarFocusedState(focused = false)
@@ -182,10 +190,10 @@ class FadeOmnibarLayout @JvmOverloads constructor(
182190
val startCardMarginBottom = omnibarCard.marginBottom
183191
val startCardMarginStart = omnibarCard.marginStart
184192
val startCardMarginEnd = omnibarCard.marginEnd
185-
val startContentPaddingTop = omniBarContentContainer.paddingTop
186-
val startContentPaddingBottom = omniBarContentContainer.paddingBottom
187-
val startContentPaddingStart = omniBarContentContainer.paddingStart
188-
val startContentPaddingEnd = omniBarContentContainer.paddingEnd
193+
val startContentPaddingTop = omnibarCard.contentPaddingTop
194+
val startContentPaddingBottom = omnibarCard.contentPaddingBottom
195+
val startContentPaddingStart = omnibarCard.contentPaddingLeft
196+
val startContentPaddingEnd = omnibarCard.contentPaddingRight
189197
val startCardStrokeWidth = omnibarCard.strokeWidth
190198

191199
val endCardMarginTop: Int
@@ -243,7 +251,7 @@ class FadeOmnibarLayout @JvmOverloads constructor(
243251
params.bottomMargin = animatedCardMarginBottom
244252
omnibarCard.setLayoutParams(params)
245253

246-
omniBarContentContainer.setPadding(
254+
omnibarCard.setContentPadding(
247255
animatedContentPaddingStart,
248256
animatedContentPaddingTop,
249257
animatedContentPaddingEnd,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
18+
android:width="24dp"
19+
android:height="24dp"
20+
android:viewportWidth="24"
21+
android:viewportHeight="24">
22+
<path
23+
android:pathData="M3.22,8.22C2.927,8.513 2.927,8.987 3.22,9.28L10.232,16.293C11.208,17.269 12.792,17.269 13.768,16.293L20.905,9.155C21.198,8.862 21.198,8.388 20.905,8.095C20.612,7.802 20.138,7.802 19.845,8.095L12.707,15.232C12.317,15.623 11.683,15.623 11.293,15.232L4.28,8.22C3.987,7.927 3.513,7.927 3.22,8.22Z"
24+
android:fillColor="?attr/daxColorSecondaryIcon"
25+
android:fillType="evenOdd"/>
26+
</vector>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
18+
android:width="24dp"
19+
android:height="24dp"
20+
android:viewportWidth="24"
21+
android:viewportHeight="24">
22+
<path
23+
android:pathData="M3.22,15.78C2.927,15.487 2.927,15.013 3.22,14.72L10.232,7.707C11.208,6.731 12.792,6.731 13.768,7.707L20.905,14.845C21.198,15.138 21.198,15.612 20.905,15.905C20.612,16.198 20.138,16.198 19.845,15.905L12.707,8.768C12.317,8.377 11.683,8.377 11.293,8.768L4.28,15.78C3.987,16.073 3.513,16.073 3.22,15.78Z"
24+
android:fillColor="?attr/daxColorSecondaryIcon"
25+
android:fillType="evenOdd"/>
26+
</vector>
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
18+
android:width="24dp"
19+
android:height="24dp"
20+
android:viewportWidth="24"
21+
android:viewportHeight="24">
22+
<path
23+
android:pathData="M18.78,5.22C19.073,5.513 19.073,5.987 18.78,6.28L6.28,18.78C5.987,19.073 5.513,19.073 5.22,18.78C4.927,18.487 4.927,18.013 5.22,17.72L17.72,5.22C18.013,4.927 18.487,4.927 18.78,5.22Z"
24+
android:fillColor="?attr/daxColorPrimaryIcon"
25+
android:fillType="evenOdd"/>
26+
<path
27+
android:pathData="M5.22,5.22C5.513,4.927 5.987,4.927 6.28,5.22L18.78,17.72C19.073,18.013 19.073,18.487 18.78,18.78C18.487,19.073 18.013,19.073 17.72,18.78L5.22,6.28C4.927,5.987 4.927,5.513 5.22,5.22Z"
28+
android:fillColor="?attr/daxColorPrimaryIcon"
29+
android:fillType="evenOdd"/>
30+
</vector>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
18+
android:width="24dp"
19+
android:height="24dp"
20+
android:viewportWidth="24"
21+
android:viewportHeight="24">
22+
<path
23+
android:pathData="M8,1.969C5.221,1.969 2.969,4.221 2.969,7V17C2.969,19.779 5.221,22.031 8,22.031H15C15.089,22.031 15.179,22.032 15.269,22.032C15.95,22.038 16.223,21.192 15.752,20.699C15.609,20.549 15.411,20.469 15.203,20.469H8C6.084,20.469 4.531,18.916 4.531,17V7C4.531,5.084 6.084,3.531 8,3.531H16C17.916,3.531 19.469,5.084 19.469,7V15.947C19.469,16.159 19.552,16.361 19.704,16.508C20.204,16.989 21.031,16.693 21.031,16V7C21.031,4.221 18.779,1.969 16,1.969H8Z"
24+
android:fillColor="?attr/daxColorPrimaryIcon"/>
25+
<path
26+
android:pathData="M16.119,15.889C16.694,15.072 17.031,14.075 17.031,13C17.031,10.221 14.779,7.969 12,7.969C9.221,7.969 6.969,10.221 6.969,13C6.969,15.779 9.221,18.031 12,18.031C13.139,18.031 14.191,17.652 15.034,17.014L18.166,20.146C18.471,20.451 18.966,20.451 19.271,20.146C19.576,19.841 19.576,19.346 19.271,19.041L16.119,15.889ZM8.531,13C8.531,11.084 10.084,9.531 12,9.531C13.916,9.531 15.469,11.084 15.469,13C15.469,14.916 13.916,16.469 12,16.469C10.084,16.469 8.531,14.916 8.531,13Z"
27+
android:fillColor="?attr/daxColorPrimaryIcon"
28+
android:fillType="evenOdd"/>
29+
</vector>

0 commit comments

Comments
 (0)