Skip to content

Commit a64924f

Browse files
authored
always show full URL when focusing input screen (#6385)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1208671518894266/task/1210672287029312?focus=true ### Description Ensures that Input Screen is pre-filled with full URL even if the option to show full URL in an unfocused omnibar is disabled. ### Steps to test this PR - [x] Disable Settings -> Appearance -> Show Full Site Address - [x] NTP - [x] Go to NTP - [x] Open input screen - [x] Type anything - [x] Go back without submitting - [x] Open input screen again - [x] Verify your draft text is pre-filled - [x] SERP - [x] Search for anything - [x] Open input screen - [x] Verify your search query is pre-filled - [x] Website - [x] Go to a website, the URL should only show the domain (without protocol, path, query params, etc) - [x] Open input screen - [x] Verify that the full URL with path and query params is pre-filled
1 parent 0b3cc8c commit a64924f

File tree

9 files changed

+110
-33
lines changed

9 files changed

+110
-33
lines changed

app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,14 +1050,14 @@ class BrowserTabFragment :
10501050
configureItemPressedListener()
10511051
configureCustomTab()
10521052
configureEditModeChangeDetection()
1053-
configureClickCatcher()
1053+
configureInputScreenLauncher()
10541054
}
10551055

1056-
private fun configureClickCatcher() {
1057-
omnibar.omniBarClickCatcher?.setOnClickListener {
1056+
private fun configureInputScreenLauncher() {
1057+
omnibar.configureInputScreenLaunchListener { query ->
10581058
val intent = globalActivityStarter.startIntent(
10591059
requireContext(),
1060-
InputScreenActivityParams(query = omnibar.getText()),
1060+
InputScreenActivityParams(query = query),
10611061
)
10621062
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
10631063
requireActivity(),

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ class Omnibar(
158158
fun onTrackersCountFinished()
159159
}
160160

161+
fun interface InputScreenLaunchListener {
162+
fun launchInputScreen(
163+
query: String,
164+
)
165+
}
166+
161167
data class OmnibarTextState(
162168
val text: String,
163169
val hasFocus: Boolean,
@@ -231,13 +237,6 @@ class Omnibar(
231237
newOmnibar.omniBarContainer
232238
}
233239

234-
val omniBarClickCatcher: View? by lazy {
235-
when (omnibarType) {
236-
SINGLE -> (newOmnibar as? SingleOmnibarLayout)?.omniBarClickCatcher
237-
else -> null
238-
}
239-
}
240-
241240
val toolbar: Toolbar by lazy {
242241
newOmnibar.toolbar
243242
}
@@ -305,6 +304,10 @@ class Omnibar(
305304
}
306305
}
307306

307+
fun configureInputScreenLaunchListener(listener: InputScreenLaunchListener) {
308+
newOmnibar.setInputScreenLaunchListener(listener)
309+
}
310+
308311
fun addTextListener(listener: TextListener) {
309312
newOmnibar.setOmnibarTextListener(listener)
310313
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.NewTabScrolli
6767
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.PrivacyShieldChanged
6868
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.QueueCookiesAnimation
6969
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command
70+
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command.LaunchInputScreen
7071
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command.MoveCaretToFront
7172
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command.StartCookiesAnimation
7273
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command.StartExperimentVariant1Animation
@@ -199,6 +200,7 @@ open class OmnibarLayout @JvmOverloads constructor(
199200

200201
private var omnibarTextListener: Omnibar.TextListener? = null
201202
private var omnibarItemPressedListener: Omnibar.ItemPressedListener? = null
203+
private var omnibarInputScreenLaunchListener: Omnibar.InputScreenLaunchListener? = null
202204

203205
private var decoration: Decoration? = null
204206
private var lastViewMode: Mode? = null
@@ -262,6 +264,7 @@ open class OmnibarLayout @JvmOverloads constructor(
262264
)
263265
}
264266
}
267+
private val omnibarTextInputClickCatcher: View by lazy { findViewById(R.id.omnibarTextInputClickCatcher) }
265268

266269
internal fun omnibarViews(): List<View> = listOf(
267270
clearTextButton,
@@ -549,6 +552,10 @@ open class OmnibarLayout @JvmOverloads constructor(
549552
is StartExperimentVariant2OrVariant3Animation -> {
550553
startExperimentVariant2OrVariant3Animation(command.entities)
551554
}
555+
556+
is LaunchInputScreen -> {
557+
omnibarInputScreenLaunchListener?.launchInputScreen(query = command.query)
558+
}
552559
}
553560
}
554561

@@ -668,6 +675,8 @@ open class OmnibarLayout @JvmOverloads constructor(
668675
}
669676

670677
previousTransitionState = newTransitionState
678+
679+
enableTextInputClickCatcher(viewState.showTextInputClickCatcher)
671680
}
672681

673682
private fun renderBrowserMode(viewState: ViewState) {
@@ -1028,6 +1037,23 @@ open class OmnibarLayout @JvmOverloads constructor(
10281037
fun setDraftTextIfNtp(query: String) {
10291038
viewModel.setDraftTextIfNtp(query)
10301039
}
1040+
1041+
private fun enableTextInputClickCatcher(enabled: Boolean) {
1042+
omnibarTextInputClickCatcher.isVisible = enabled
1043+
1044+
omnibarTextInput.apply {
1045+
isEnabled = !enabled
1046+
isFocusable = !enabled
1047+
isFocusableInTouchMode = !enabled
1048+
}
1049+
}
1050+
1051+
fun setInputScreenLaunchListener(listener: Omnibar.InputScreenLaunchListener) {
1052+
omnibarInputScreenLaunchListener = listener
1053+
omnibarTextInputClickCatcher.setOnClickListener {
1054+
viewModel.onTextInputClickCatcherClicked()
1055+
}
1056+
}
10311057
}
10321058

10331059
interface OmnibarItemPressedListener {

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class OmnibarLayoutViewModel @Inject constructor(
174174
val trackersBlocked: Int = 0,
175175
val previouslyTrackersBlocked: Int = 0,
176176
val showShadows: Boolean = false,
177-
val showClickCatcher: Boolean = false,
177+
val showTextInputClickCatcher: Boolean = false,
178178
val showFindInPage: Boolean = false,
179179
) {
180180
fun shouldUpdateOmnibarText(isFullUrlEnabled: Boolean): Boolean {
@@ -190,6 +190,7 @@ class OmnibarLayoutViewModel @Inject constructor(
190190
data object StartExperimentVariant1Animation : Command()
191191
data class StartExperimentVariant2OrVariant3Animation(val entities: List<Entity>?) : Command()
192192
data object MoveCaretToFront : Command()
193+
data class LaunchInputScreen(val query: String) : Command()
193194
}
194195

195196
enum class LeadingIconState {
@@ -205,7 +206,7 @@ class OmnibarLayoutViewModel @Inject constructor(
205206
duckAiFeatureState.showInputScreen.onEach { inputScreenEnabled ->
206207
_viewState.update {
207208
it.copy(
208-
showClickCatcher = inputScreenEnabled,
209+
showTextInputClickCatcher = inputScreenEnabled,
209210
)
210211
}
211212
}.launchIn(viewModelScope)
@@ -850,4 +851,18 @@ class OmnibarLayoutViewModel @Inject constructor(
850851
}
851852
}
852853
}
854+
855+
fun onTextInputClickCatcherClicked() {
856+
viewModelScope.launch {
857+
val omnibarText = viewState.value.omnibarText
858+
val url = viewState.value.url
859+
val isDuckDuckGoQueryUrl = duckDuckGoUrlDetector.isDuckDuckGoQueryUrl(url)
860+
val textToPreFill = if (omnibarText.isNotEmpty() && url.isNotEmpty() && !isDuckDuckGoQueryUrl) {
861+
url
862+
} else {
863+
omnibarText
864+
}
865+
command.send(Command.LaunchInputScreen(query = textToPreFill))
866+
}
867+
}
853868
}

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

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ class FadeOmnibarLayout @JvmOverloads constructor(
7575
private val omniBarContentContainer: View by lazy { findViewById(R.id.omniBarContentContainer) }
7676
private val backIcon: ImageView by lazy { findViewById(R.id.backIcon) }
7777
private val customTabToolbarContainerWrapper: ViewGroup by lazy { findViewById(R.id.customTabToolbarContainerWrapper) }
78-
val omniBarClickCatcher: View by lazy { findViewById(R.id.omnibarClickCatcher) }
7978

8079
override val findInPage: FindInPage by lazy {
8180
FindInPageImpl(IncludeFadeOmnibarFindInPageBinding.bind(findViewById(R.id.findInPage)))
@@ -225,18 +224,6 @@ class FadeOmnibarLayout @JvmOverloads constructor(
225224
} else {
226225
backIcon.gone()
227226
}
228-
229-
enableClickCatcher(viewState.showClickCatcher)
230-
}
231-
232-
private fun enableClickCatcher(enabled: Boolean) {
233-
omniBarClickCatcher.isVisible = enabled
234-
235-
omnibarTextInput.apply {
236-
isEnabled = !enabled
237-
isFocusable = !enabled
238-
isFocusableInTouchMode = !enabled
239-
}
240227
}
241228

242229
/**

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ class SingleOmnibarLayout @JvmOverloads constructor(
6565
private val omniBarContentContainer: View by lazy { findViewById(R.id.omniBarContentContainer) }
6666
private val backIcon: ImageView by lazy { findViewById(R.id.backIcon) }
6767
private val customTabToolbarContainerWrapper: ViewGroup by lazy { findViewById(R.id.customTabToolbarContainerWrapper) }
68-
val omniBarClickCatcher: View by lazy { findViewById(R.id.omnibarClickCatcher) }
6968

7069
override val findInPage: FindInPage by lazy {
7170
FindInPageImpl(IncludeFadeOmnibarFindInPageBinding.bind(findViewById(R.id.findInPage)))
@@ -174,8 +173,6 @@ class SingleOmnibarLayout @JvmOverloads constructor(
174173
} else {
175174
backIcon.hide()
176175
}
177-
178-
omniBarClickCatcher.isVisible = viewState.showClickCatcher
179176
}
180177

181178
private fun animateOmnibarFocusedState(focused: Boolean) {

app/src/main/res/layout/view_fade_omnibar.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@
317317
</androidx.constraintlayout.widget.ConstraintLayout>
318318

319319
<View
320-
android:id="@+id/omnibarClickCatcher"
320+
android:id="@+id/omnibarTextInputClickCatcher"
321321
android:layout_width="0dp"
322322
android:layout_height="0dp"
323323
android:background="@android:color/transparent"

app/src/main/res/layout/view_single_omnibar.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@
325325
</androidx.constraintlayout.widget.ConstraintLayout>
326326

327327
<View
328-
android:id="@+id/omnibarClickCatcher"
328+
android:id="@+id/omnibarTextInputClickCatcher"
329329
android:layout_width="0dp"
330330
android:layout_height="0dp"
331331
android:background="@android:color/transparent"

app/src/test/java/com/duckduckgo/app/browser/omnibar/OmnibarLayoutViewModelTest.kt

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration
1313
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.Decoration.ChangeCustomTabTitle
1414
import com.duckduckgo.app.browser.omnibar.OmnibarLayout.StateChange
1515
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command
16+
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.Command.LaunchInputScreen
1617
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.LeadingIconState
1718
import com.duckduckgo.app.browser.omnibar.OmnibarLayoutViewModel.LeadingIconState.SEARCH
1819
import com.duckduckgo.app.browser.senseofprotection.SenseOfProtectionExperiment
@@ -1338,7 +1339,7 @@ class OmnibarLayoutViewModelTest {
13381339

13391340
testee.viewState.test {
13401341
val viewState = expectMostRecentItem()
1341-
assertTrue(viewState.showClickCatcher)
1342+
assertTrue(viewState.showTextInputClickCatcher)
13421343
cancelAndIgnoreRemainingEvents()
13431344
}
13441345
}
@@ -1349,7 +1350,55 @@ class OmnibarLayoutViewModelTest {
13491350

13501351
testee.viewState.test {
13511352
val viewState = expectMostRecentItem()
1352-
assertFalse(viewState.showClickCatcher)
1353+
assertFalse(viewState.showTextInputClickCatcher)
1354+
cancelAndIgnoreRemainingEvents()
1355+
}
1356+
}
1357+
1358+
@Test
1359+
fun `when input text click catcher clicked and no URL then input screen launched with draft query`() = runTest {
1360+
testee.onInputStateChanged(query = "draft", hasFocus = false, clearQuery = false, deleteLastCharacter = false)
1361+
1362+
testee.onTextInputClickCatcherClicked()
1363+
1364+
testee.commands().test {
1365+
val command = awaitItem()
1366+
assertTrue(command is LaunchInputScreen)
1367+
assertEquals("draft", (command as LaunchInputScreen).query)
1368+
cancelAndIgnoreRemainingEvents()
1369+
}
1370+
}
1371+
1372+
@Test
1373+
fun `when input text click catcher clicked and DDG URL then input screen launched with search query`() = runTest {
1374+
givenSiteLoaded(SERP_URL)
1375+
val omnibarViewState = OmnibarViewState(omnibarText = "test", queryOrFullUrl = "test", isEditing = false)
1376+
testee.onExternalStateChange(StateChange.OmnibarStateChange(omnibarViewState))
1377+
1378+
testee.onTextInputClickCatcherClicked()
1379+
1380+
testee.commands().test {
1381+
val command = awaitItem()
1382+
assertTrue(command is LaunchInputScreen)
1383+
assertEquals("test", (command as LaunchInputScreen).query)
1384+
cancelAndIgnoreRemainingEvents()
1385+
}
1386+
}
1387+
1388+
@Test
1389+
fun `when input text click catcher clicked and random URL then input screen launched with full URL`() = runTest {
1390+
whenever(settingsDataStore.isFullUrlEnabled).thenReturn(false)
1391+
initializeViewModel()
1392+
val omnibarViewState = OmnibarViewState(omnibarText = "test", queryOrFullUrl = "test", isEditing = false)
1393+
testee.onExternalStateChange(StateChange.OmnibarStateChange(omnibarViewState))
1394+
givenSiteLoaded(RANDOM_URL)
1395+
1396+
testee.onTextInputClickCatcherClicked()
1397+
1398+
testee.commands().test {
1399+
val command = awaitItem()
1400+
assertTrue(command is LaunchInputScreen)
1401+
assertEquals(RANDOM_URL, (command as LaunchInputScreen).query)
13531402
cancelAndIgnoreRemainingEvents()
13541403
}
13551404
}

0 commit comments

Comments
 (0)