Skip to content

Commit a8ed9bb

Browse files
authored
Fix: Custom tab layout with new design (#6352)
Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1210726417568688?focus=true ### Description This PR fixes the custom tab layout for thew new design. ### Steps to test this PR - [ ] Go to Settings -> Developer Settings -> Custom Tabs - [ ] Make sure DDG is the default browser - [ ] Enter a website and launch a custom tab - [ ] Verify the custom tab looks as expected ### UI changes | Before | After | | ------ | ----- | ![image](https://github.com/user-attachments/assets/013882dc-616a-40ad-8842-946f70d70358)|![image](https://github.com/user-attachments/assets/1d5b7d08-a2dc-40b2-8bd8-716b7c70e41b)|
1 parent 76c3a11 commit a8ed9bb

File tree

7 files changed

+168
-19
lines changed

7 files changed

+168
-19
lines changed

app/src/androidTest/java/com/duckduckgo/app/browser/omnibar/animations/LottiePrivacyShieldAnimationHelperTest.kt

Lines changed: 152 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.duckduckgo.app.browser.omnibar.animations
1919
import android.annotation.SuppressLint
2020
import com.airbnb.lottie.LottieAnimationView
2121
import com.duckduckgo.app.browser.R
22+
import com.duckduckgo.app.browser.omnibar.Omnibar
2223
import com.duckduckgo.app.browser.senseofprotection.SenseOfProtectionExperiment
2324
import com.duckduckgo.app.global.model.PrivacyShield.MALICIOUS
2425
import com.duckduckgo.app.global.model.PrivacyShield.PROTECTED
@@ -40,6 +41,9 @@ class LottiePrivacyShieldAnimationHelperTest {
4041
private val enabledVisualExperimentStateFlow = MutableStateFlow(true)
4142
private val disabledVisualExperimentStateFlow = MutableStateFlow(false)
4243

44+
private val browserViewMode = Omnibar.ViewMode.Browser("cnn.com")
45+
private val customTabViewMode = Omnibar.ViewMode.CustomTab(0, "cnn.com", "cnn.com")
46+
4347
@Before
4448
fun setup() {
4549
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
@@ -56,7 +60,7 @@ class LottiePrivacyShieldAnimationHelperTest {
5660
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
5761
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
5862

59-
testee.setAnimationView(holder, PROTECTED)
63+
testee.setAnimationView(holder, PROTECTED, browserViewMode)
6064

6165
verify(holder).setAnimation(R.raw.protected_shield)
6266
}
@@ -70,7 +74,7 @@ class LottiePrivacyShieldAnimationHelperTest {
7074
whenever(appTheme.isLightModeEnabled()).thenReturn(false)
7175
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
7276

73-
testee.setAnimationView(holder, PROTECTED)
77+
testee.setAnimationView(holder, PROTECTED, browserViewMode)
7478

7579
verify(holder).setAnimation(R.raw.dark_protected_shield)
7680
}
@@ -84,7 +88,7 @@ class LottiePrivacyShieldAnimationHelperTest {
8488
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
8589
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
8690

87-
testee.setAnimationView(holder, UNPROTECTED)
91+
testee.setAnimationView(holder, UNPROTECTED, browserViewMode)
8892

8993
verify(holder).setAnimation(R.raw.unprotected_shield)
9094
verify(holder).progress = 1.0f
@@ -99,7 +103,7 @@ class LottiePrivacyShieldAnimationHelperTest {
99103
whenever(appTheme.isLightModeEnabled()).thenReturn(false)
100104
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
101105

102-
testee.setAnimationView(holder, UNPROTECTED)
106+
testee.setAnimationView(holder, UNPROTECTED, browserViewMode)
103107

104108
verify(holder).setAnimation(R.raw.dark_unprotected_shield)
105109
verify(holder).progress = 1.0f
@@ -114,7 +118,7 @@ class LottiePrivacyShieldAnimationHelperTest {
114118
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
115119
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
116120

117-
testee.setAnimationView(holder, MALICIOUS)
121+
testee.setAnimationView(holder, MALICIOUS, browserViewMode)
118122

119123
verify(holder).setAnimation(R.raw.alert_red)
120124
verify(holder).progress = 0.0f
@@ -129,7 +133,7 @@ class LottiePrivacyShieldAnimationHelperTest {
129133
whenever(appTheme.isLightModeEnabled()).thenReturn(false)
130134
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
131135

132-
testee.setAnimationView(holder, MALICIOUS)
136+
testee.setAnimationView(holder, MALICIOUS, browserViewMode)
133137

134138
verify(holder).setAnimation(R.raw.alert_red_dark)
135139
verify(holder).progress = 0.0f
@@ -146,7 +150,7 @@ class LottiePrivacyShieldAnimationHelperTest {
146150

147151
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
148152

149-
testee.setAnimationView(holder, PROTECTED)
153+
testee.setAnimationView(holder, PROTECTED, browserViewMode)
150154

151155
verify(holder).setAnimation(R.raw.protected_shield_experiment)
152156
}
@@ -162,7 +166,7 @@ class LottiePrivacyShieldAnimationHelperTest {
162166

163167
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
164168

165-
testee.setAnimationView(holder, UNPROTECTED)
169+
testee.setAnimationView(holder, UNPROTECTED, browserViewMode)
166170

167171
verify(holder).setAnimation(R.raw.unprotected_shield_experiment)
168172
}
@@ -178,7 +182,7 @@ class LottiePrivacyShieldAnimationHelperTest {
178182

179183
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
180184

181-
testee.setAnimationView(holder, PROTECTED)
185+
testee.setAnimationView(holder, PROTECTED, browserViewMode)
182186

183187
verify(holder).setAnimation(R.raw.protected_shield_experiment)
184188
}
@@ -194,7 +198,7 @@ class LottiePrivacyShieldAnimationHelperTest {
194198

195199
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
196200

197-
testee.setAnimationView(holder, UNPROTECTED)
201+
testee.setAnimationView(holder, UNPROTECTED, browserViewMode)
198202

199203
verify(holder).setAnimation(R.raw.unprotected_shield_experiment_dark)
200204
}
@@ -211,7 +215,7 @@ class LottiePrivacyShieldAnimationHelperTest {
211215

212216
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
213217

214-
testee.setAnimationView(holder, PROTECTED)
218+
testee.setAnimationView(holder, PROTECTED, browserViewMode)
215219

216220
verify(holder).setAnimation(R.raw.protected_shield)
217221
}
@@ -230,7 +234,7 @@ class LottiePrivacyShieldAnimationHelperTest {
230234

231235
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
232236

233-
testee.setAnimationView(holder, PROTECTED)
237+
testee.setAnimationView(holder, PROTECTED, browserViewMode)
234238

235239
verify(holder).setAnimation(R.raw.protected_shield_new_design)
236240
}
@@ -249,7 +253,7 @@ class LottiePrivacyShieldAnimationHelperTest {
249253

250254
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
251255

252-
testee.setAnimationView(holder, UNPROTECTED)
256+
testee.setAnimationView(holder, UNPROTECTED, browserViewMode)
253257

254258
verify(holder).setAnimation(R.raw.unprotected_shield_visual_updates)
255259
}
@@ -268,7 +272,7 @@ class LottiePrivacyShieldAnimationHelperTest {
268272

269273
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
270274

271-
testee.setAnimationView(holder, PROTECTED)
275+
testee.setAnimationView(holder, PROTECTED, browserViewMode)
272276

273277
verify(holder).setAnimation(R.raw.dark_protected_shield_new_design)
274278
}
@@ -287,8 +291,141 @@ class LottiePrivacyShieldAnimationHelperTest {
287291

288292
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
289293

290-
testee.setAnimationView(holder, UNPROTECTED)
294+
testee.setAnimationView(holder, UNPROTECTED, browserViewMode)
291295

292296
verify(holder).setAnimation(R.raw.dark_unprotected_shield_visual_updates)
293297
}
298+
299+
@SuppressLint("DenyListedApi")
300+
@Test
301+
fun whenLightModeAndProtectedAndNewSingleOmnibarDesignEnabledAndCustomTabViewModeThenUseCustomTabAssets() = runTest {
302+
whenever(senseOfProtectionExperiment.shouldShowNewPrivacyShield()).thenReturn(false)
303+
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
304+
enabledVisualExperimentStateFlow,
305+
)
306+
307+
val holder: LottieAnimationView = mock()
308+
val appTheme: AppTheme = mock()
309+
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
310+
311+
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
312+
313+
testee.setAnimationView(holder, PROTECTED, customTabViewMode)
314+
315+
verify(holder).setAnimation(R.raw.protected_shield_custom_tab)
316+
}
317+
318+
@SuppressLint("DenyListedApi")
319+
@Test
320+
fun whenDarkModeAndProtectedAndNewSingleOmnibarDesignEnabledAndCustomTabViewModeThenUseCustomTabAssets() = runTest {
321+
whenever(senseOfProtectionExperiment.shouldShowNewPrivacyShield()).thenReturn(false)
322+
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
323+
enabledVisualExperimentStateFlow,
324+
)
325+
326+
val holder: LottieAnimationView = mock()
327+
val appTheme: AppTheme = mock()
328+
whenever(appTheme.isLightModeEnabled()).thenReturn(false)
329+
330+
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
331+
332+
testee.setAnimationView(holder, PROTECTED, customTabViewMode)
333+
334+
verify(holder).setAnimation(R.raw.dark_protected_shield_custom_tab)
335+
}
336+
337+
@SuppressLint("DenyListedApi")
338+
@Test
339+
fun whenLightModeAndUnprotectedAndNewSingleOmnibarDesignEnabledAndCustomTabViewModeThenUseVisualUpdatesAssets() = runTest {
340+
whenever(senseOfProtectionExperiment.shouldShowNewPrivacyShield()).thenReturn(false)
341+
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
342+
enabledVisualExperimentStateFlow,
343+
)
344+
345+
val holder: LottieAnimationView = mock()
346+
val appTheme: AppTheme = mock()
347+
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
348+
349+
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
350+
351+
testee.setAnimationView(holder, UNPROTECTED, customTabViewMode)
352+
353+
verify(holder).setAnimation(R.raw.unprotected_shield_visual_updates)
354+
}
355+
356+
@SuppressLint("DenyListedApi")
357+
@Test
358+
fun whenDarkModeAndUnprotectedAndNewSingleOmnibarDesignEnabledAndCustomTabViewModeAndExperimentDisabledThenUseDefaultAssets() = runTest {
359+
whenever(senseOfProtectionExperiment.shouldShowNewPrivacyShield()).thenReturn(false)
360+
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
361+
disabledVisualExperimentStateFlow,
362+
)
363+
364+
val holder: LottieAnimationView = mock()
365+
val appTheme: AppTheme = mock()
366+
whenever(appTheme.isLightModeEnabled()).thenReturn(false)
367+
368+
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
369+
370+
testee.setAnimationView(holder, UNPROTECTED, customTabViewMode)
371+
372+
verify(holder).setAnimation(R.raw.dark_unprotected_shield)
373+
}
374+
375+
@SuppressLint("DenyListedApi")
376+
@Test
377+
fun whenLightModeAndProtectedAndNewSingleOmnibarDesignEnabledAndCustomTabViewModeAndExperimentDisabledThenUseDefaultAssets() = runTest {
378+
whenever(senseOfProtectionExperiment.shouldShowNewPrivacyShield()).thenReturn(false)
379+
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
380+
disabledVisualExperimentStateFlow,
381+
)
382+
383+
val holder: LottieAnimationView = mock()
384+
val appTheme: AppTheme = mock()
385+
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
386+
387+
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
388+
389+
testee.setAnimationView(holder, PROTECTED, customTabViewMode)
390+
391+
verify(holder).setAnimation(R.raw.protected_shield)
392+
}
393+
394+
@SuppressLint("DenyListedApi")
395+
@Test
396+
fun whenDarkModeAndProtectedAndNewSingleOmnibarDesignEnabledAndCustomTabViewModeAndExperimentDisabledThenUseDefaultAssets() = runTest {
397+
whenever(senseOfProtectionExperiment.shouldShowNewPrivacyShield()).thenReturn(false)
398+
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
399+
disabledVisualExperimentStateFlow,
400+
)
401+
402+
val holder: LottieAnimationView = mock()
403+
val appTheme: AppTheme = mock()
404+
whenever(appTheme.isLightModeEnabled()).thenReturn(false)
405+
406+
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
407+
408+
testee.setAnimationView(holder, PROTECTED, customTabViewMode)
409+
410+
verify(holder).setAnimation(R.raw.dark_protected_shield)
411+
}
412+
413+
@SuppressLint("DenyListedApi")
414+
@Test
415+
fun whenLightModeAndUnprotectedAndNewSingleOmnibarDesignEnabledAndCustomTabViewModeAndExperimentDisabledThenUseDefaultAssets() = runTest {
416+
whenever(senseOfProtectionExperiment.shouldShowNewPrivacyShield()).thenReturn(false)
417+
whenever(experimentalThemingDataStore.isSingleOmnibarEnabled).thenReturn(
418+
disabledVisualExperimentStateFlow,
419+
)
420+
421+
val holder: LottieAnimationView = mock()
422+
val appTheme: AppTheme = mock()
423+
whenever(appTheme.isLightModeEnabled()).thenReturn(true)
424+
425+
val testee = LottiePrivacyShieldAnimationHelper(appTheme, senseOfProtectionExperiment, experimentalThemingDataStore)
426+
427+
testee.setAnimationView(holder, UNPROTECTED, customTabViewMode)
428+
429+
verify(holder).setAnimation(R.raw.unprotected_shield)
430+
}
294431
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ open class OmnibarLayout @JvmOverloads constructor(
899899
customTabToolbarContainer.customTabShieldIcon
900900
}
901901

902-
privacyShieldView.setAnimationView(shieldIconView, privacyShield)
902+
privacyShieldView.setAnimationView(shieldIconView, privacyShield, viewMode)
903903
}
904904
}
905905

app/src/main/java/com/duckduckgo/app/browser/omnibar/animations/LottiePrivacyShieldAnimationHelper.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.duckduckgo.app.browser.omnibar.animations
1818

1919
import com.airbnb.lottie.LottieAnimationView
2020
import com.duckduckgo.app.browser.R
21+
import com.duckduckgo.app.browser.omnibar.Omnibar
2122
import com.duckduckgo.app.browser.senseofprotection.SenseOfProtectionExperiment
2223
import com.duckduckgo.app.global.model.PrivacyShield
2324
import com.duckduckgo.app.global.model.PrivacyShield.MALICIOUS
@@ -44,6 +45,7 @@ class LottiePrivacyShieldAnimationHelper @Inject constructor(
4445
override fun setAnimationView(
4546
holder: LottieAnimationView,
4647
privacyShield: PrivacyShield,
48+
viewMode: Omnibar.ViewMode,
4749
) {
4850
val protectedShield: Int
4951
val protectedShieldDark: Int
@@ -55,8 +57,13 @@ class LottiePrivacyShieldAnimationHelper @Inject constructor(
5557
unprotectedShield = R.raw.unprotected_shield_experiment
5658
unprotectedShieldDark = R.raw.unprotected_shield_experiment_dark
5759
} else if (experimentalThemingDataStore.isSingleOmnibarEnabled.value) {
58-
protectedShield = R.raw.protected_shield_new_design
59-
protectedShieldDark = R.raw.dark_protected_shield_new_design
60+
if (viewMode is Omnibar.ViewMode.CustomTab) {
61+
protectedShield = R.raw.protected_shield_custom_tab
62+
protectedShieldDark = R.raw.dark_protected_shield_custom_tab
63+
} else {
64+
protectedShield = R.raw.protected_shield_new_design
65+
protectedShieldDark = R.raw.dark_protected_shield_new_design
66+
}
6067
unprotectedShield = R.raw.unprotected_shield_visual_updates
6168
unprotectedShieldDark = R.raw.dark_unprotected_shield_visual_updates
6269
} else {

app/src/main/java/com/duckduckgo/app/browser/omnibar/animations/PrivacyShieldAnimationHelper.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.duckduckgo.app.browser.omnibar.animations
1818

1919
import com.airbnb.lottie.LottieAnimationView
20+
import com.duckduckgo.app.browser.omnibar.Omnibar
2021
import com.duckduckgo.app.global.model.PrivacyShield
2122

2223
/** Public interface for the Privacy Shield Animation Helper */
@@ -25,5 +26,5 @@ interface PrivacyShieldAnimationHelper {
2526
/**
2627
* This method will setup into [holder] a LottieAnimation based on [PrivacyShield] state.
2728
*/
28-
fun setAnimationView(holder: LottieAnimationView, privacyShield: PrivacyShield)
29+
fun setAnimationView(holder: LottieAnimationView, privacyShield: PrivacyShield, viewMode: Omnibar.ViewMode)
2930
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ class SingleOmnibarLayout @JvmOverloads constructor(
149149
} else {
150150
animateOmnibarFocusedState(focused = false)
151151
}
152+
153+
omnibarCardShadow.isVisible = viewState.viewMode !is ViewMode.CustomTab
152154
}
153155

154156
override fun renderButtons(viewState: ViewState) {

0 commit comments

Comments
 (0)