Skip to content

Commit 711eb6f

Browse files
0nkoCrisBarreiro
andauthored
Fix: Tab swiping taking over Duck Player (#6005)
Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1210107135506123?focus=true ### Description This PR disables the tab swiping when the browser is in full-screen mode. This fixes an issue when playing a video in Duck player in full-screen mode and it is not possible to control the player. ### Steps to test this PR - [x] Open a video in Duck player - [x] Toggle the full-screen mode - [x] Verify the tab swiping is completely disabled - [x] Toggled off the full-screen mode - [x] Verify the tab swiping on the omnibar works as expected --------- Co-authored-by: Cris Barreiro <[email protected]>
1 parent b061ab8 commit 711eb6f

File tree

9 files changed

+128
-46
lines changed

9 files changed

+128
-46
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ import com.duckduckgo.common.ui.experiments.visual.store.VisualDesignExperimentD
8888
import com.duckduckgo.common.ui.tabs.SwipingTabsFeatureProvider
8989
import com.duckduckgo.common.ui.view.dialog.TextAlertDialogBuilder
9090
import com.duckduckgo.common.ui.view.gone
91+
import com.duckduckgo.common.ui.view.isFullScreen
9192
import com.duckduckgo.common.ui.view.show
9293
import com.duckduckgo.common.ui.view.toPx
9394
import com.duckduckgo.common.ui.viewbinding.viewBinding
@@ -759,6 +760,14 @@ open class BrowserActivity : DuckDuckGoActivity() {
759760
)
760761
}
761762

763+
override fun toggleFullScreen() {
764+
super.toggleFullScreen()
765+
766+
if (swipingTabsFeature.isEnabled) {
767+
viewModel.onFullScreenModeChanged(isFullScreen())
768+
}
769+
}
770+
762771
companion object {
763772

764773
fun intent(

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,8 @@ import com.duckduckgo.app.fire.fireproofwebsite.data.website
187187
import com.duckduckgo.app.global.model.PrivacyShield.UNKNOWN
188188
import com.duckduckgo.app.global.model.orderedTrackerBlockedEntities
189189
import com.duckduckgo.app.global.view.NonDismissibleBehavior
190-
import com.duckduckgo.app.global.view.isFullScreen
191-
import com.duckduckgo.app.global.view.isImmersiveModeEnabled
192190
import com.duckduckgo.app.global.view.launchDefaultAppActivity
193191
import com.duckduckgo.app.global.view.renderIfChanged
194-
import com.duckduckgo.app.global.view.toggleFullScreen
195192
import com.duckduckgo.app.pixels.AppPixelName
196193
import com.duckduckgo.app.privatesearch.PrivateSearchScreenNoParams
197194
import com.duckduckgo.app.settings.db.SettingsDataStore
@@ -236,6 +233,7 @@ import com.duckduckgo.browser.api.WebViewVersionProvider
236233
import com.duckduckgo.browser.api.brokensite.BrokenSiteData
237234
import com.duckduckgo.browser.api.brokensite.BrokenSiteData.ReportFlow.RELOAD_THREE_TIMES_WITHIN_20_SECONDS
238235
import com.duckduckgo.browser.api.ui.BrowserScreens.WebViewActivityWithParams
236+
import com.duckduckgo.common.ui.DuckDuckGoActivity
239237
import com.duckduckgo.common.ui.DuckDuckGoFragment
240238
import com.duckduckgo.common.ui.experiments.visual.store.VisualDesignExperimentDataStore
241239
import com.duckduckgo.common.ui.store.BrowserAppTheme
@@ -251,6 +249,8 @@ import com.duckduckgo.common.ui.view.getColorFromAttr
251249
import com.duckduckgo.common.ui.view.gone
252250
import com.duckduckgo.common.ui.view.hide
253251
import com.duckduckgo.common.ui.view.hideKeyboard
252+
import com.duckduckgo.common.ui.view.isFullScreen
253+
import com.duckduckgo.common.ui.view.isImmersiveModeEnabled
254254
import com.duckduckgo.common.ui.view.makeSnackbarWithNoBottomInset
255255
import com.duckduckgo.common.ui.view.show
256256
import com.duckduckgo.common.ui.view.toPx
@@ -4378,15 +4378,15 @@ class BrowserTabFragment :
43784378
private fun goFullScreen() {
43794379
omnibar.hide()
43804380
binding.webViewFullScreenContainer.show()
4381-
activity?.toggleFullScreen()
4381+
(activity as? DuckDuckGoActivity)?.toggleFullScreen()
43824382
showToast(R.string.fullScreenMessage, Toast.LENGTH_SHORT)
43834383
}
43844384

43854385
private fun exitFullScreen() {
43864386
omnibar.show()
43874387
binding.webViewFullScreenContainer.removeAllViews()
43884388
binding.webViewFullScreenContainer.gone()
4389-
activity?.toggleFullScreen()
4389+
(activity as? DuckDuckGoActivity)?.toggleFullScreen()
43904390
binding.focusDummy.requestFocus()
43914391
}
43924392
}

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,11 @@ class BrowserViewModel @Inject constructor(
104104

105105
data class ViewState(
106106
val hideWebContent: Boolean = true,
107-
val isTabSwipingEnabled: Boolean = false,
108-
)
107+
private val isInEditMode: Boolean = false,
108+
private val isInFullScreenMode: Boolean = false,
109+
) {
110+
val isTabSwipingEnabled: Boolean = !isInEditMode && !isInFullScreenMode
111+
}
109112

110113
sealed class Command {
111114
data class Query(val query: String) : Command()
@@ -424,7 +427,11 @@ class BrowserViewModel @Inject constructor(
424427
}
425428

426429
fun onOmnibarEditModeChanged(isInEditMode: Boolean) {
427-
viewState.value = currentViewState.copy(isTabSwipingEnabled = !isInEditMode)
430+
viewState.value = currentViewState.copy(isInEditMode = isInEditMode)
431+
}
432+
433+
fun onFullScreenModeChanged(isFullScreen: Boolean) {
434+
viewState.value = currentViewState.copy(isInFullScreenMode = isFullScreen)
428435
}
429436

430437
// user has not tapped the Undo action -> purge the deletable tabs and remove all data

app/src/main/java/com/duckduckgo/app/fire/FireActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import android.os.Bundle
2323
import androidx.appcompat.app.AppCompatActivity
2424
import com.duckduckgo.anvil.annotations.InjectWith
2525
import com.duckduckgo.app.browser.BrowserActivity
26-
import com.duckduckgo.app.global.view.fadeTransitionConfig
27-
import com.duckduckgo.app.global.view.noAnimationConfig
26+
import com.duckduckgo.common.ui.view.fadeTransitionConfig
27+
import com.duckduckgo.common.ui.view.noAnimationConfig
2828
import com.duckduckgo.di.scopes.ActivityScope
2929

3030
/**

app/src/main/java/com/duckduckgo/app/generalsettings/GeneralSettingsActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchO
3636
import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.LastOpenedTab
3737
import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.NewTabPage
3838
import com.duckduckgo.app.generalsettings.showonapplaunch.model.ShowOnAppLaunchOption.SpecificPage
39-
import com.duckduckgo.app.global.view.fadeTransitionConfig
4039
import com.duckduckgo.browser.api.ui.BrowserScreens.WebViewActivityWithParams
4140
import com.duckduckgo.common.ui.DuckDuckGoActivity
4241
import com.duckduckgo.common.ui.spans.DuckDuckGoClickableSpan
4342
import com.duckduckgo.common.ui.view.addClickableSpan
43+
import com.duckduckgo.common.ui.view.fadeTransitionConfig
4444
import com.duckduckgo.common.ui.viewbinding.viewBinding
4545
import com.duckduckgo.di.scopes.ActivityScope
4646
import com.duckduckgo.navigation.api.GlobalActivityStarter

app/src/main/java/com/duckduckgo/app/global/view/ActivityExtension.kt renamed to app/src/main/java/com/duckduckgo/app/global/view/LaunchActivityExtensions.kt

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,7 @@ package com.duckduckgo.app.global.view
1919
import android.content.ActivityNotFoundException
2020
import android.content.Context
2121
import android.content.Intent
22-
import android.content.pm.ActivityInfo
23-
import android.os.Bundle
24-
import android.view.View
2522
import android.widget.Toast
26-
import androidx.core.app.ActivityOptionsCompat
2723
import androidx.fragment.app.FragmentActivity
2824
import com.duckduckgo.app.browser.R
2925
import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserSystemSettings
@@ -47,34 +43,3 @@ fun Context.launchDefaultAppActivity() {
4743
Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show()
4844
}
4945
}
50-
51-
fun Context.fadeTransitionConfig(): Bundle? {
52-
val config = ActivityOptionsCompat.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
53-
return config.toBundle()
54-
}
55-
56-
fun Context.noAnimationConfig(): Bundle? =
57-
ActivityOptionsCompat.makeCustomAnimation(this, 0, 0).toBundle()
58-
59-
fun FragmentActivity.toggleFullScreen() {
60-
if (isFullScreen()) {
61-
// If we are exiting full screen, reset the orientation
62-
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
63-
}
64-
65-
val newUiOptions = window.decorView.systemUiVisibility
66-
.xor(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
67-
.xor(View.SYSTEM_UI_FLAG_FULLSCREEN)
68-
.xor(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
69-
70-
window.decorView.systemUiVisibility = newUiOptions
71-
}
72-
73-
fun FragmentActivity.isFullScreen(): Boolean {
74-
return window.decorView.systemUiVisibility.and(View.SYSTEM_UI_FLAG_FULLSCREEN) == View.SYSTEM_UI_FLAG_FULLSCREEN
75-
}
76-
77-
fun FragmentActivity.isImmersiveModeEnabled(): Boolean {
78-
val uiOptions = window.decorView.systemUiVisibility
79-
return uiOptions or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY == uiOptions
80-
}

app/src/test/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,50 @@ class BrowserViewModelTest {
462462
assertEquals(!isInEditMode, testee.viewState.value!!.isTabSwipingEnabled)
463463
}
464464

465+
@Test
466+
fun whenBrowserIsNotInFullscreenModeTabSwipingIsEnabled() {
467+
swipingTabsFeature.self().setRawStoredState(State(enable = true))
468+
469+
val isFullScreen = false
470+
testee.onFullScreenModeChanged(isFullScreen)
471+
assertEquals(true, testee.viewState.value!!.isTabSwipingEnabled)
472+
}
473+
474+
@Test
475+
fun whenBrowserIsInFullscreenModeTabSwipingIsDisabled() {
476+
swipingTabsFeature.self().setRawStoredState(State(enable = true))
477+
478+
val isFullScreen = true
479+
testee.onFullScreenModeChanged(isFullScreen)
480+
assertEquals(false, testee.viewState.value!!.isTabSwipingEnabled)
481+
}
482+
483+
@Test
484+
fun whenOmnibarIsNotInEditModeAndBrowserIsInFullscreenModeTabSwipingIsDisabled() {
485+
swipingTabsFeature.self().setRawStoredState(State(enable = true))
486+
487+
val isFullScreen = true
488+
testee.onFullScreenModeChanged(isFullScreen)
489+
490+
val isInEditMode = false
491+
testee.onOmnibarEditModeChanged(isInEditMode)
492+
493+
assertEquals(false, testee.viewState.value!!.isTabSwipingEnabled)
494+
}
495+
496+
@Test
497+
fun whenOmnibarIsInEditModeAndBrowserIsNotInFullscreenModeTabSwipingIsDisabled() {
498+
swipingTabsFeature.self().setRawStoredState(State(enable = true))
499+
500+
val isFullScreen = false
501+
testee.onFullScreenModeChanged(isFullScreen)
502+
503+
val isInEditMode = true
504+
testee.onOmnibarEditModeChanged(isInEditMode)
505+
506+
assertEquals(false, testee.viewState.value!!.isTabSwipingEnabled)
507+
}
508+
465509
private fun initTestee() {
466510
testee = BrowserViewModel(
467511
tabRepository = mockTabRepository,

common/common-ui/src/main/java/com/duckduckgo/common/ui/DuckDuckGoActivity.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@ import android.annotation.SuppressLint
2020
import android.app.UiModeManager
2121
import android.content.BroadcastReceiver
2222
import android.content.Context
23+
import android.content.pm.ActivityInfo
2324
import android.os.Bundle
2425
import android.view.MenuItem
26+
import android.view.View
2527
import androidx.appcompat.widget.Toolbar
2628
import androidx.lifecycle.ViewModel
2729
import androidx.lifecycle.ViewModelProvider
2830
import androidx.localbroadcastmanager.content.LocalBroadcastManager
2931
import com.duckduckgo.common.ui.DuckDuckGoTheme.DARK
3032
import com.duckduckgo.common.ui.DuckDuckGoTheme.EXPERIMENT_DARK
3133
import com.duckduckgo.common.ui.store.ThemingDataStore
34+
import com.duckduckgo.common.ui.view.isFullScreen
3235
import com.duckduckgo.mobile.android.R
3336
import dagger.android.AndroidInjection
3437
import dagger.android.DaggerActivity
@@ -106,4 +109,18 @@ abstract class DuckDuckGoActivity : DaggerActivity() {
106109
protected inline fun <reified V : ViewModel> bindViewModel() = lazy {
107110
ViewModelProvider(this, viewModelFactory).get(V::class.java)
108111
}
112+
113+
open fun toggleFullScreen() {
114+
if (isFullScreen()) {
115+
// If we are exiting full screen, reset the orientation
116+
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
117+
}
118+
119+
val newUiOptions = window.decorView.systemUiVisibility
120+
.xor(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
121+
.xor(View.SYSTEM_UI_FLAG_FULLSCREEN)
122+
.xor(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
123+
124+
window.decorView.systemUiVisibility = newUiOptions
125+
}
109126
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2018 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.common.ui.view
18+
19+
import android.content.Context
20+
import android.os.Bundle
21+
import android.view.View
22+
import androidx.core.app.ActivityOptionsCompat
23+
import androidx.fragment.app.FragmentActivity
24+
25+
fun Context.fadeTransitionConfig(): Bundle? {
26+
val config = ActivityOptionsCompat.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
27+
return config.toBundle()
28+
}
29+
30+
fun Context.noAnimationConfig(): Bundle? =
31+
ActivityOptionsCompat.makeCustomAnimation(this, 0, 0).toBundle()
32+
33+
fun FragmentActivity.isFullScreen(): Boolean {
34+
return window.decorView.systemUiVisibility.and(View.SYSTEM_UI_FLAG_FULLSCREEN) == View.SYSTEM_UI_FLAG_FULLSCREEN
35+
}
36+
37+
fun FragmentActivity.isImmersiveModeEnabled(): Boolean {
38+
val uiOptions = window.decorView.systemUiVisibility
39+
return uiOptions or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY == uiOptions
40+
}

0 commit comments

Comments
 (0)