diff --git a/android-design-system/design-system/src/main/res/layout/include_tab_switcher_toolbar_top.xml b/android-design-system/design-system/src/main/res/layout/include_tab_switcher_toolbar_top.xml index d292bf01e56d..ddf4645da3b1 100644 --- a/android-design-system/design-system/src/main/res/layout/include_tab_switcher_toolbar_top.xml +++ b/android-design-system/design-system/src/main/res/layout/include_tab_switcher_toolbar_top.xml @@ -34,9 +34,4 @@ app:buttonGravity="center_vertical" app:popupTheme="@style/Widget.DuckDuckGo.PopUpOverflowMenu" /> - - \ No newline at end of file diff --git a/android-design-system/design-system/src/main/res/values/design-system-dimensions.xml b/android-design-system/design-system/src/main/res/values/design-system-dimensions.xml index 1298c7add800..73b49e00336d 100644 --- a/android-design-system/design-system/src/main/res/values/design-system-dimensions.xml +++ b/android-design-system/design-system/src/main/res/values/design-system-dimensions.xml @@ -46,8 +46,8 @@ 60dp - 12dp - 8dp + 8dp + 4dp 18dp 24dp diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt index 45a28c322a6b..96de0b8ec038 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt @@ -573,7 +573,6 @@ class BrowserTabViewModel @Inject constructor( @VisibleForTesting internal val autoCompleteStateFlow = MutableStateFlow("") private val fireproofWebsiteState: LiveData> = fireproofWebsiteRepository.getFireproofWebsites() - private var alreadyShownKeyboard = false @ExperimentalCoroutinesApi @FlowPreview @@ -603,6 +602,7 @@ class BrowserTabViewModel @Inject constructor( private var isLinkOpenedInNewTab = false private var allowlistRefreshTriggerJob: Job? = null private var isCustomTabScreen: Boolean = false + private var alreadyShownKeyboard: Boolean = false private val fireproofWebsitesObserver = Observer> { diff --git a/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/BrowserNavigationBarViewIntegration.kt b/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/BrowserNavigationBarViewIntegration.kt index 306f50380954..d719132d2b0c 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/BrowserNavigationBarViewIntegration.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/BrowserNavigationBarViewIntegration.kt @@ -21,6 +21,7 @@ import com.duckduckgo.app.browser.databinding.FragmentBrowserTabBinding import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarObserver import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode.Browser +import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode.CustomTab import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode.NewTab import com.duckduckgo.app.browser.omnibar.Omnibar import com.duckduckgo.common.ui.view.gone @@ -61,7 +62,7 @@ class BrowserNavigationBarViewIntegration( } fun configureCustomTab() { - navigationBarView.setCustomTab(isCustomTab = true) + navigationBarView.setViewMode(CustomTab) } fun configureBrowserViewMode() { diff --git a/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarView.kt b/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarView.kt index d6a6ccd448f3..6d02ab487185 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarView.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarView.kt @@ -110,12 +110,6 @@ class BrowserNavigationBarView @JvmOverloads constructor( var browserNavigationBarObserver: BrowserNavigationBarObserver? = null - fun setCustomTab(isCustomTab: Boolean) { - doOnAttach { - viewModel.setCustomTab(isCustomTab) - } - } - fun setViewMode(viewMode: ViewMode) { doOnAttach { viewModel.setViewMode(viewMode) @@ -195,7 +189,8 @@ class BrowserNavigationBarView @JvmOverloads constructor( binding.tabsButton.isVisible = viewState.tabsButtonVisible binding.tabsButton.count = viewState.tabsCount binding.tabsButton.hasUnread = viewState.hasUnreadTabs - binding.browserMenuHighlight?.isVisible = viewState.showBrowserMenuHighlight + binding.browserMenuHighlight.isVisible = viewState.showBrowserMenuHighlight + binding.shadowView.isVisible = viewState.showShadow renderFireButtonPulseAnimation(enabled = viewState.fireButtonHighlighted) } @@ -225,6 +220,7 @@ class BrowserNavigationBarView @JvmOverloads constructor( } enum class ViewMode { + CustomTab, NewTab, Browser, TabManager, diff --git a/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModel.kt index afafb56ce181..090f4fa9fe1e 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModel.kt @@ -24,7 +24,9 @@ import com.duckduckgo.anvil.annotations.ContributesViewModel import com.duckduckgo.app.browser.defaultbrowsing.prompts.AdditionalDefaultBrowserPrompts import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode.Browser +import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode.CustomTab import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode.NewTab +import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarView.ViewMode.TabManager import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarViewModel.Command.NotifyAutofillButtonClicked import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarViewModel.Command.NotifyBookmarksButtonClicked import com.duckduckgo.app.browser.navigation.bar.view.BrowserNavigationBarViewModel.Command.NotifyFireButtonClicked @@ -61,16 +63,13 @@ class BrowserNavigationBarViewModel @Inject constructor( private val _commands = Channel(capacity = Channel.CONFLATED) val commands: Flow = _commands.receiveAsFlow() - private val isCustomTab = MutableStateFlow(false) private val _viewState = MutableStateFlow(ViewState()) val viewState = combine( _viewState.asStateFlow(), - isCustomTab, tabRepository.flowTabs, additionalDefaultBrowserPrompts.highlightPopupMenu, - ) { state, isCustomTab, tabs, highlightOverflowMenu -> + ) { state, tabs, highlightOverflowMenu -> state.copy( - isVisible = !isCustomTab, tabsCount = tabs.size, hasUnreadTabs = tabs.firstOrNull { !it.viewed } != null, showBrowserMenuHighlight = highlightOverflowMenu, @@ -115,10 +114,6 @@ class BrowserNavigationBarViewModel @Inject constructor( _commands.trySend(NotifyBookmarksButtonClicked) } - fun setCustomTab(customTab: Boolean) { - isCustomTab.update { customTab } - } - fun setViewMode(viewMode: ViewMode) { when (viewMode) { NewTab -> { @@ -139,13 +134,21 @@ class BrowserNavigationBarViewModel @Inject constructor( } } - ViewMode.TabManager -> { + TabManager -> { _viewState.update { it.copy( newTabButtonVisible = true, autofillButtonVisible = false, tabsButtonVisible = false, bookmarksButtonVisible = false, + showShadow = false, + ) + } + } + CustomTab -> { + _viewState.update { + it.copy( + isVisible = false, ) } } @@ -181,5 +184,6 @@ class BrowserNavigationBarViewModel @Inject constructor( val tabsCount: Int = 0, val hasUnreadTabs: Boolean = false, val showBrowserMenuHighlight: Boolean = false, + val showShadow: Boolean = true, ) } diff --git a/app/src/main/java/com/duckduckgo/app/pixels/remoteconfig/AndroidBrowserConfigFeature.kt b/app/src/main/java/com/duckduckgo/app/pixels/remoteconfig/AndroidBrowserConfigFeature.kt index c42e4503952c..441e66225000 100644 --- a/app/src/main/java/com/duckduckgo/app/pixels/remoteconfig/AndroidBrowserConfigFeature.kt +++ b/app/src/main/java/com/duckduckgo/app/pixels/remoteconfig/AndroidBrowserConfigFeature.kt @@ -193,6 +193,7 @@ interface AndroidBrowserConfigFeature { * If the remote feature is not present defaults to `false` */ @Toggle.DefaultValue(DefaultFeatureValue.FALSE) + @Toggle.InternalAlwaysEnabled fun splitOmnibar(): Toggle /** diff --git a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt index ca23378d3d2d..bbbb34658884 100644 --- a/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/tabs/ui/TabSwitcherActivity.kt @@ -39,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.OnScrollListener import com.duckduckgo.anvil.annotations.InjectWith import com.duckduckgo.app.browser.R +import com.duckduckgo.app.browser.api.OmnibarRepository import com.duckduckgo.app.browser.databinding.ActivityTabSwitcherBinding import com.duckduckgo.app.browser.databinding.PopupTabsMenuBinding import com.duckduckgo.app.browser.favicon.FaviconManager @@ -165,6 +166,9 @@ class TabSwitcherActivity : @Inject lateinit var onboardingExperimentFireAnimationHelper: OnboardingExperimentFireAnimationHelper + @Inject + lateinit var omnibarRepository: OmnibarRepository + private val viewModel: TabSwitcherViewModel by bindViewModel() private val tabsAdapter: TabSwitcherAdapter by lazy { @@ -253,21 +257,26 @@ class TabSwitcherActivity : } private fun configureNavigationBar() { - binding.navigationBar.browserNavigationBarObserver = - object : BrowserNavigationBarObserver { - override fun onMenuButtonClicked() { - showPopupMenu(binding.navigationBar.popupMenuAnchor.id) - } + if (omnibarRepository.omnibarType == OmnibarType.SPLIT) { + binding.navigationBar.browserNavigationBarObserver = + object : BrowserNavigationBarObserver { + override fun onMenuButtonClicked() { + showPopupMenu(binding.navigationBar.popupMenuAnchor.id) + } - override fun onNewTabButtonClicked() { - viewModel.onNewTabRequested() - } + override fun onNewTabButtonClicked() { + viewModel.onNewTabRequested() + } - override fun onFireButtonClicked() { - viewModel.onFireButtonTapped() + override fun onFireButtonClicked() { + viewModel.onFireButtonTapped() + } } - } - binding.navigationBar.setViewMode(BrowserNavigationBarView.ViewMode.TabManager) + binding.navigationBar.setViewMode(BrowserNavigationBarView.ViewMode.TabManager) + binding.navigationBar.show() + } else { + binding.navigationBar.gone() + } } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/res/layout-w600dp/view_browser_navigation_bar.xml b/app/src/main/res/layout-w600dp/view_browser_navigation_bar.xml deleted file mode 100644 index 728887f3a06f..000000000000 --- a/app/src/main/res/layout-w600dp/view_browser_navigation_bar.xml +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-w600dp/view_browser_navigation_bar_mockup.xml b/app/src/main/res/layout-w600dp/view_browser_navigation_bar_mockup.xml deleted file mode 100644 index 33a0b6bee3ca..000000000000 --- a/app/src/main/res/layout-w600dp/view_browser_navigation_bar_mockup.xml +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_appearance.xml b/app/src/main/res/layout/activity_appearance.xml index d394dacb187d..21df8722d5ca 100644 --- a/app/src/main/res/layout/activity_appearance.xml +++ b/app/src/main/res/layout/activity_appearance.xml @@ -123,19 +123,19 @@ android:gravity="center" android:orientation="vertical" android:padding="@dimen/keyline_2" - android:background="@drawable/selectable_rounded_ripple" - app:layout_constraintWidth_max="160dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/bottomOmnibarContainer" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent"> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintWidth_max="160dp"> @@ -167,7 +167,6 @@ android:orientation="vertical" android:padding="@dimen/keyline_2" app:layout_constraintWidth_max="160dp" - android:background="@drawable/selectable_rounded_ripple" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/splitOmnibarContainer" app:layout_constraintStart_toEndOf="@+id/topOmnibarContainer" @@ -175,9 +174,10 @@ @@ -216,7 +216,6 @@ android:padding="@dimen/keyline_2" android:gravity="center" android:orientation="vertical" - android:background="@drawable/selectable_rounded_ripple" app:layout_constraintWidth_max="160dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -225,9 +224,10 @@ diff --git a/app/src/main/res/layout/activity_tab_switcher.xml b/app/src/main/res/layout/activity_tab_switcher.xml index a536acbb8697..4bc91562dea6 100644 --- a/app/src/main/res/layout/activity_tab_switcher.xml +++ b/app/src/main/res/layout/activity_tab_switcher.xml @@ -72,6 +72,7 @@ diff --git a/app/src/test/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModelTest.kt b/app/src/test/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModelTest.kt index 25eea6776d8a..d223ac34be14 100644 --- a/app/src/test/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModelTest.kt +++ b/app/src/test/java/com/duckduckgo/app/browser/navigation/bar/view/BrowserNavigationBarViewModelTest.kt @@ -156,4 +156,69 @@ class BrowserNavigationBarViewModelTest { cancelAndIgnoreRemainingEvents() } } + + @Test + fun `when setViewMode NewTab then viewState reflects NewTab configuration`() = runTest { + testee.viewState.test { + val initial = awaitItem() + // sanity check defaults + Assert.assertTrue(initial.newTabButtonVisible) + Assert.assertFalse(initial.autofillButtonVisible) + + testee.setViewMode(BrowserNavigationBarView.ViewMode.NewTab) + + val updated = awaitItem() + Assert.assertFalse(updated.newTabButtonVisible) + Assert.assertTrue(updated.autofillButtonVisible) + // unchanged flags + Assert.assertTrue(updated.tabsButtonVisible) + Assert.assertTrue(updated.bookmarksButtonVisible) + Assert.assertTrue(updated.showShadow) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `when setViewMode TabManager then viewState reflects TabManager configuration`() = runTest { + testee.viewState.test { + awaitItem() // initial + testee.setViewMode(BrowserNavigationBarView.ViewMode.TabManager) + val updated = awaitItem() + Assert.assertTrue(updated.newTabButtonVisible) + Assert.assertFalse(updated.autofillButtonVisible) + Assert.assertFalse(updated.tabsButtonVisible) + Assert.assertFalse(updated.bookmarksButtonVisible) + Assert.assertFalse(updated.showShadow) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `when switching NewTab then Browser then viewState reflects Browser configuration`() = runTest { + testee.viewState.test { + awaitItem() // initial + testee.setViewMode(BrowserNavigationBarView.ViewMode.NewTab) + awaitItem() // NewTab state + testee.setViewMode(BrowserNavigationBarView.ViewMode.Browser) + val browserState = awaitItem() + Assert.assertTrue(browserState.newTabButtonVisible) + Assert.assertFalse(browserState.autofillButtonVisible) + Assert.assertTrue(browserState.tabsButtonVisible) + Assert.assertTrue(browserState.bookmarksButtonVisible) + Assert.assertTrue(browserState.showShadow) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `when setViewMode CustomTab then navigation bar becomes hidden`() = runTest { + testee.viewState.test { + val initial = awaitItem() + Assert.assertTrue(initial.isVisible) + + testee.setViewMode(BrowserNavigationBarView.ViewMode.CustomTab) + val hidden = awaitItem() + Assert.assertFalse(hidden.isVisible) + } + } }