diff --git a/app/build.gradle b/app/build.gradle index b149f22557..b1524e5cac 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -487,6 +487,7 @@ dependencies { implementation Deps.mozilla_ui_icons implementation Deps.mozilla_lib_publicsuffixlist implementation Deps.mozilla_ui_widgets + implementation Deps.mozilla_ui_tabcounter implementation Deps.mozilla_lib_crash implementation Deps.mozilla_lib_push_firebase diff --git a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 1fd65872d8..2c53e2bb62 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -572,7 +572,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, useCase.invoke(request.query) requireActivity().startActivity(openInFenixIntent) } else { - useCase.invoke(request.query, parentSession = parentSession) + useCase.invoke(request.query, parentSessionId = parentSession?.id) } }, owner = this, diff --git a/app/src/main/java/org/mozilla/fenix/browser/TabPreview.kt b/app/src/main/java/org/mozilla/fenix/browser/TabPreview.kt index c72182352f..346cce7e5f 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/TabPreview.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/TabPreview.kt @@ -13,8 +13,8 @@ import android.widget.FrameLayout import androidx.appcompat.content.res.AppCompatResources import androidx.core.view.doOnNextLayout import androidx.core.view.updateLayoutParams -import kotlinx.android.synthetic.main.mozac_ui_tabcounter_layout.view.* import kotlinx.android.synthetic.main.tab_preview.view.* +import kotlinx.android.synthetic.main.tabs_tray_tab_counter.view.* import mozilla.components.browser.thumbnails.loader.ThumbnailLoader import mozilla.components.concept.base.images.ImageLoadRequest import org.mozilla.fenix.R diff --git a/app/src/main/java/org/mozilla/fenix/components/Core.kt b/app/src/main/java/org/mozilla/fenix/components/Core.kt index a6011c217b..405bf5c8da 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Core.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Core.kt @@ -23,7 +23,6 @@ import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.engine.EngineMiddleware import mozilla.components.browser.session.storage.SessionStorage import mozilla.components.browser.session.undo.UndoMiddleware -import mozilla.components.browser.state.action.RecentlyClosedAction import mozilla.components.browser.state.action.RestoreCompleteAction import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.store.BrowserStore @@ -40,8 +39,8 @@ import mozilla.components.concept.fetch.Client import mozilla.components.feature.customtabs.store.CustomTabsServiceStore import mozilla.components.feature.downloads.DownloadMiddleware import mozilla.components.feature.logins.exceptions.LoginExceptionStorage -import mozilla.components.feature.media.RecordingDevicesNotificationFeature import mozilla.components.feature.media.middleware.MediaMiddleware +import mozilla.components.feature.media.middleware.RecordingDevicesMiddleware import mozilla.components.feature.pwa.ManifestStorage import mozilla.components.feature.pwa.WebAppShortcutManager import mozilla.components.feature.readerview.ReaderViewMiddleware @@ -198,11 +197,10 @@ class Core( context, additionalBundledSearchEngineIds = listOf("reddit", "youtube"), migration = SearchMigration(context) - ) + ), + RecordingDevicesMiddleware(context) ) + EngineMiddleware.create(engine, ::findSessionById) - ).also { - it.dispatch(RecentlyClosedAction.InitializeRecentlyClosedState) - } + ) } private fun lookupSessionManager(): SessionManager { @@ -242,10 +240,6 @@ class Core( // Install the "cookies" WebExtension and tracks user interaction with SERPs. searchTelemetry.install(engine, store) - // Show an ongoing notification when recording devices (camera, microphone) are used by web content - RecordingDevicesNotificationFeature(context, sessionManager) - .enable() - // Restore the previous state. GlobalScope.launch(Dispatchers.Main) { withContext(Dispatchers.IO) { diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt index ba8f71b35d..03d7971c84 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt @@ -4,6 +4,8 @@ package org.mozilla.fenix.components.toolbar +import mozilla.components.ui.tabcounter.TabCounterMenu + open class BrowserInteractor( private val browserToolbarController: BrowserToolbarController, private val menuController: BrowserToolbarMenuController diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt index 588a3a8609..b52b849e7a 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt @@ -9,10 +9,12 @@ import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.concept.engine.EngineView import mozilla.components.support.ktx.kotlin.isUrl +import mozilla.components.ui.tabcounter.TabCounterMenu import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions import org.mozilla.fenix.browser.BrowserFragmentDirections +import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.readermode.ReaderModeController import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.MetricController @@ -104,6 +106,9 @@ class DefaultBrowserToolbarController( override fun handleTabCounterItemInteraction(item: TabCounterMenu.Item) { when (item) { is TabCounterMenu.Item.CloseTab -> { + metrics.track( + Event.TabCounterMenuItemTapped(Event.TabCounterMenuItemTapped.Item.CLOSE_TAB) + ) sessionManager.selectedSession?.let { // When closing the last tab we must show the undo snackbar in the home fragment if (sessionManager.sessionsOfType(it.private).count() == 1) { @@ -120,8 +125,24 @@ class DefaultBrowserToolbarController( } } is TabCounterMenu.Item.NewTab -> { - activity.browsingModeManager.mode = item.mode - navController.navigate(BrowserFragmentDirections.actionGlobalHome(focusOnAddressBar = true)) + metrics.track( + Event.TabCounterMenuItemTapped(Event.TabCounterMenuItemTapped.Item.NEW_TAB) + ) + activity.browsingModeManager.mode = BrowsingMode.Normal + navController.navigate( + BrowserFragmentDirections.actionGlobalHome(focusOnAddressBar = true) + ) + } + is TabCounterMenu.Item.NewPrivateTab -> { + metrics.track( + Event.TabCounterMenuItemTapped( + Event.TabCounterMenuItemTapped.Item.NEW_PRIVATE_TAB + ) + ) + activity.browsingModeManager.mode = BrowsingMode.Private + navController.navigate( + BrowserFragmentDirections.actionGlobalHome(focusOnAddressBar = true) + ) } } } diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt index d79a11884c..882dc3df59 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt @@ -29,6 +29,7 @@ import mozilla.components.browser.toolbar.BrowserToolbar import mozilla.components.browser.toolbar.behavior.BrowserToolbarBottomBehavior import mozilla.components.browser.toolbar.display.DisplayToolbar import mozilla.components.support.utils.URLStringUtils +import mozilla.components.ui.tabcounter.TabCounterMenu import org.mozilla.fenix.R import org.mozilla.fenix.customtabs.CustomTabToolbarIntegration import org.mozilla.fenix.customtabs.CustomTabToolbarMenu @@ -267,10 +268,6 @@ class BrowserToolbarView( } } - companion object { - private const val TOOLBAR_ELEVATION = 16 - } - @Suppress("ComplexCondition") private fun ToolbarMenu.Item.performHapticIfNeeded(view: View) { if (this is ToolbarMenu.Item.Reload && this.bypassCache || diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/FenixTabCounterMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/FenixTabCounterMenu.kt new file mode 100644 index 0000000000..224f19340b --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/FenixTabCounterMenu.kt @@ -0,0 +1,60 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.components.toolbar + +import android.content.Context +import androidx.annotation.VisibleForTesting +import mozilla.components.concept.menu.candidate.DividerMenuCandidate +import mozilla.components.concept.menu.candidate.MenuCandidate +import mozilla.components.ui.tabcounter.TabCounterMenu +import org.mozilla.fenix.browser.browsingmode.BrowsingMode + +class FenixTabCounterMenu( + context: Context, + onItemTapped: (Item) -> Unit, + iconColor: Int? = null +) : TabCounterMenu(context, onItemTapped, iconColor) { + + @VisibleForTesting + internal fun menuItems(showOnly: BrowsingMode): List { + return when (showOnly) { + BrowsingMode.Normal -> listOf(newTabItem) + BrowsingMode.Private -> listOf(newPrivateTabItem) + } + } + + @VisibleForTesting + internal fun menuItems(toolbarPosition: ToolbarPosition): List { + val items = listOf( + newTabItem, + newPrivateTabItem, + DividerMenuCandidate(), + closeTabItem + ) + + return when (toolbarPosition) { + ToolbarPosition.BOTTOM -> items.reversed() + ToolbarPosition.TOP -> items + } + } + + /** + * Update the displayed menu items. + * @param showOnly Show only the new tab item corresponding to the given [BrowsingMode]. + */ + fun updateMenu(showOnly: BrowsingMode) { + val items = menuItems(showOnly) + + menuController.submitList(items) + } + + /** + * Update the displayed menu items. + * @param toolbarPosition Return a list that is ordered based on the given [ToolbarPosition]. + */ + fun updateMenu(toolbarPosition: ToolbarPosition) { + menuController.submitList(menuItems(toolbarPosition)) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounter.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounter.kt deleted file mode 100644 index 1585fb7c36..0000000000 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounter.kt +++ /dev/null @@ -1,271 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.fenix.components.toolbar - -import android.animation.AnimatorSet -import android.animation.ObjectAnimator -import android.content.Context -import android.graphics.Typeface -import android.util.AttributeSet -import android.util.TypedValue -import android.view.LayoutInflater -import android.widget.RelativeLayout -import androidx.core.view.updatePadding -import kotlinx.android.synthetic.main.mozac_ui_tabcounter_layout.view.* -import org.mozilla.fenix.R -import java.text.NumberFormat - -class TabCounter @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyle: Int = 0 -) : RelativeLayout(context, attrs, defStyle) { - - private val animationSet: AnimatorSet - - init { - val inflater = LayoutInflater.from(context) - inflater.inflate(R.layout.mozac_ui_tabcounter_layout, this) - - // This is needed because without this counter box will be empty. - setCount(INTERNAL_COUNT) - - animationSet = createAnimatorSet() - } - - private fun updateContentDescription(count: Int) { - counter_root.contentDescription = if (count == 1) { - context?.getString(R.string.open_tab_tray_single) - } else { - String.format(context.getString(R.string.open_tab_tray_plural), count.toString()) - } - } - - fun setCountWithAnimation(count: Int) { - setCount(count) - - // No need to animate on these cases. - when { - INTERNAL_COUNT == 0 -> return // Initial state. - INTERNAL_COUNT == count -> return // There isn't any tab added or removed. - INTERNAL_COUNT > MAX_VISIBLE_TABS -> return // There are still over MAX_VISIBLE_TABS tabs open. - } - - // Cancel previous animations if necessary. - if (animationSet.isRunning) { - animationSet.cancel() - } - // Trigger animations. - animationSet.start() - } - - fun setCount(count: Int) { - updateContentDescription(count) - adjustTextSize(count) - counter_text.text = formatForDisplay(count) - INTERNAL_COUNT = count - } - - private fun createAnimatorSet(): AnimatorSet { - val animatorSet = AnimatorSet() - createBoxAnimatorSet(animatorSet) - createTextAnimatorSet(animatorSet) - return animatorSet - } - - private fun createBoxAnimatorSet(animatorSet: AnimatorSet) { - // The first animator, fadeout in 33 ms (49~51, 2 frames). - val fadeOut = ObjectAnimator.ofFloat( - counter_box, "alpha", - ANIM_BOX_FADEOUT_FROM, ANIM_BOX_FADEOUT_TO - ).setDuration(ANIM_BOX_FADEOUT_DURATION) - - // Move up on y-axis, from 0.0 to -5.3 in 50ms, with fadeOut (49~52, 3 frames). - val moveUp1 = ObjectAnimator.ofFloat( - counter_box, "translationY", - ANIM_BOX_MOVEUP1_TO, ANIM_BOX_MOVEUP1_FROM - ).setDuration(ANIM_BOX_MOVEUP1_DURATION) - - // Move down on y-axis, from -5.3 to -1.0 in 116ms, after moveUp1 (52~59, 7 frames). - val moveDown2 = ObjectAnimator.ofFloat( - counter_box, "translationY", - ANIM_BOX_MOVEDOWN2_FROM, ANIM_BOX_MOVEDOWN2_TO - ).setDuration(ANIM_BOX_MOVEDOWN2_DURATION) - - // FadeIn in 66ms, with moveDown2 (52~56, 4 frames). - val fadeIn = ObjectAnimator.ofFloat( - counter_box, "alpha", - ANIM_BOX_FADEIN_FROM, ANIM_BOX_FADEIN_TO - ).setDuration(ANIM_BOX_FADEIN_DURATION) - - // Move down on y-axis, from -1.0 to 2.7 in 116ms, after moveDown2 (59~66, 7 frames). - val moveDown3 = ObjectAnimator.ofFloat( - counter_box, "translationY", - ANIM_BOX_MOVEDOWN3_FROM, ANIM_BOX_MOVEDOWN3_TO - ).setDuration(ANIM_BOX_MOVEDOWN3_DURATION) - - // Move up on y-axis, from 2.7 to 0 in 133ms, after moveDown3 (66~74, 8 frames). - val moveUp4 = ObjectAnimator.ofFloat( - counter_box, "translationY", - ANIM_BOX_MOVEDOWN4_FROM, ANIM_BOX_MOVEDOWN4_TO - ).setDuration(ANIM_BOX_MOVEDOWN4_DURATION) - - // Scale up height from 2% to 105% in 100ms, after moveUp1 and delay 16ms (53~59, 6 frames). - val scaleUp1 = ObjectAnimator.ofFloat( - counter_box, "scaleY", - ANIM_BOX_SCALEUP1_FROM, ANIM_BOX_SCALEUP1_TO - ).setDuration(ANIM_BOX_SCALEUP1_DURATION) - scaleUp1.startDelay = ANIM_BOX_SCALEUP1_DELAY // delay 1 frame after moveUp1 - - // Scale down height from 105% to 99% in 116ms, after scaleUp1 (59~66, 7 frames). - val scaleDown2 = ObjectAnimator.ofFloat( - counter_box, "scaleY", - ANIM_BOX_SCALEDOWN2_FROM, ANIM_BOX_SCALEDOWN2_TO - ).setDuration(ANIM_BOX_SCALEDOWN2_DURATION) - - // Scale up height from 99% to 100% in 133ms, after scaleDown2 (66~74, 8 frames). - val scaleUp3 = ObjectAnimator.ofFloat( - counter_box, "scaleY", - ANIM_BOX_SCALEUP3_FROM, ANIM_BOX_SCALEUP3_TO - ).setDuration(ANIM_BOX_SCALEUP3_DURATION) - - animatorSet.play(fadeOut).with(moveUp1) - animatorSet.play(moveUp1).before(moveDown2) - animatorSet.play(moveDown2).with(fadeIn) - animatorSet.play(moveDown2).before(moveDown3) - animatorSet.play(moveDown3).before(moveUp4) - - animatorSet.play(moveUp1).before(scaleUp1) - animatorSet.play(scaleUp1).before(scaleDown2) - animatorSet.play(scaleDown2).before(scaleUp3) - } - - private fun createTextAnimatorSet(animatorSet: AnimatorSet) { - val firstAnimator = animatorSet.childAnimations[0] - - // Fadeout in 100ms, with firstAnimator (49~51, 2 frames). - val fadeOut = ObjectAnimator.ofFloat( - counter_text, "alpha", - ANIM_TEXT_FADEOUT_FROM, ANIM_TEXT_FADEOUT_TO - ).setDuration(ANIM_TEXT_FADEOUT_DURATION) - - // FadeIn in 66 ms, after fadeOut with delay 96ms (57~61, 4 frames). - val fadeIn = ObjectAnimator.ofFloat( - counter_text, "alpha", - ANIM_TEXT_FADEIN_FROM, ANIM_TEXT_FADEIN_TO - ).setDuration(ANIM_TEXT_FADEIN_DURATION) - fadeIn.startDelay = (ANIM_TEXT_FADEIN_DELAY) // delay 6 frames after fadeOut - - // Move down on y-axis, from 0 to 4.4 in 66ms, with fadeIn (57~61, 4 frames). - val moveDown = ObjectAnimator.ofFloat( - counter_text, "translationY", - ANIM_TEXT_MOVEDOWN_FROM, ANIM_TEXT_MOVEDOWN_TO - ).setDuration(ANIM_TEXT_MOVEDOWN_DURATION) - moveDown.startDelay = (ANIM_TEXT_MOVEDOWN_DELAY) // delay 6 frames after fadeOut - - // Move up on y-axis, from 0 to 4.4 in 66ms, after moveDown (61~69, 8 frames). - val moveUp = ObjectAnimator.ofFloat( - counter_text, "translationY", - ANIM_TEXT_MOVEUP_FROM, ANIM_TEXT_MOVEUP_TO - ).setDuration(ANIM_TEXT_MOVEUP_DURATION) - - animatorSet.play(firstAnimator).with(fadeOut) - animatorSet.play(fadeOut).before(fadeIn) - animatorSet.play(fadeIn).with(moveDown) - animatorSet.play(moveDown).before(moveUp) - } - - private fun formatForDisplay(count: Int): String { - return if (count > MAX_VISIBLE_TABS) { - counter_text.updatePadding(bottom = INFINITE_CHAR_PADDING_BOTTOM) - SO_MANY_TABS_OPEN - } else NumberFormat.getInstance().format(count.toLong()) - } - - private fun adjustTextSize(newCount: Int) { - val newRatio = if (newCount in TWO_DIGITS_TAB_COUNT_THRESHOLD..MAX_VISIBLE_TABS) { - TWO_DIGITS_SIZE_RATIO - } else { - ONE_DIGIT_SIZE_RATIO - } - - val counterBoxWidth = - context.resources.getDimensionPixelSize(R.dimen.tab_counter_box_width_height) - val textSize = newRatio * counterBoxWidth - counter_text.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - counter_text.setTypeface(null, Typeface.BOLD) - counter_text.setPadding(0, 0, 0, 0) - } - - companion object { - internal var INTERNAL_COUNT = 0 - - internal const val MAX_VISIBLE_TABS = 99 - - internal const val SO_MANY_TABS_OPEN = "∞" - - internal const val INFINITE_CHAR_PADDING_BOTTOM = 6 - - internal const val ONE_DIGIT_SIZE_RATIO = 0.5f - internal const val TWO_DIGITS_SIZE_RATIO = 0.4f - internal const val TWO_DIGITS_TAB_COUNT_THRESHOLD = 10 - - // createBoxAnimatorSet - private const val ANIM_BOX_FADEOUT_FROM = 1.0f - private const val ANIM_BOX_FADEOUT_TO = 0.0f - private const val ANIM_BOX_FADEOUT_DURATION = 33L - - private const val ANIM_BOX_MOVEUP1_FROM = 0.0f - private const val ANIM_BOX_MOVEUP1_TO = -5.3f - private const val ANIM_BOX_MOVEUP1_DURATION = 50L - - private const val ANIM_BOX_MOVEDOWN2_FROM = -5.3f - private const val ANIM_BOX_MOVEDOWN2_TO = -1.0f - private const val ANIM_BOX_MOVEDOWN2_DURATION = 167L - - private const val ANIM_BOX_FADEIN_FROM = 0.01f - private const val ANIM_BOX_FADEIN_TO = 1.0f - private const val ANIM_BOX_FADEIN_DURATION = 66L - private const val ANIM_BOX_MOVEDOWN3_FROM = -1.0f - private const val ANIM_BOX_MOVEDOWN3_TO = 2.7f - private const val ANIM_BOX_MOVEDOWN3_DURATION = 116L - - private const val ANIM_BOX_MOVEDOWN4_FROM = 2.7f - private const val ANIM_BOX_MOVEDOWN4_TO = 0.0f - private const val ANIM_BOX_MOVEDOWN4_DURATION = 133L - - private const val ANIM_BOX_SCALEUP1_FROM = 0.02f - private const val ANIM_BOX_SCALEUP1_TO = 1.05f - private const val ANIM_BOX_SCALEUP1_DURATION = 100L - private const val ANIM_BOX_SCALEUP1_DELAY = 16L - - private const val ANIM_BOX_SCALEDOWN2_FROM = 1.05f - private const val ANIM_BOX_SCALEDOWN2_TO = 0.99f - private const val ANIM_BOX_SCALEDOWN2_DURATION = 116L - - private const val ANIM_BOX_SCALEUP3_FROM = 0.99f - private const val ANIM_BOX_SCALEUP3_TO = 1.00f - private const val ANIM_BOX_SCALEUP3_DURATION = 133L - - // createTextAnimatorSet - private const val ANIM_TEXT_FADEOUT_FROM = 1.0f - private const val ANIM_TEXT_FADEOUT_TO = 0.0f - private const val ANIM_TEXT_FADEOUT_DURATION = 33L - - private const val ANIM_TEXT_FADEIN_FROM = 0.01f - private const val ANIM_TEXT_FADEIN_TO = 1.0f - private const val ANIM_TEXT_FADEIN_DURATION = 66L - private const val ANIM_TEXT_FADEIN_DELAY = 16L * 6 - - private const val ANIM_TEXT_MOVEDOWN_FROM = 0.0f - private const val ANIM_TEXT_MOVEDOWN_TO = 4.4f - private const val ANIM_TEXT_MOVEDOWN_DURATION = 66L - private const val ANIM_TEXT_MOVEDOWN_DELAY = 16L * 6 - - private const val ANIM_TEXT_MOVEUP_FROM = 4.4f - private const val ANIM_TEXT_MOVEUP_TO = 0.0f - private const val ANIM_TEXT_MOVEUP_DURATION = 66L - } -} diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounterMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounterMenu.kt deleted file mode 100644 index 6d6bebe5a7..0000000000 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounterMenu.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.fenix.components.toolbar - -import android.content.Context -import androidx.annotation.VisibleForTesting -import mozilla.components.browser.menu2.BrowserMenuController -import mozilla.components.concept.menu.MenuController -import mozilla.components.concept.menu.candidate.DividerMenuCandidate -import mozilla.components.concept.menu.candidate.DrawableMenuIcon -import mozilla.components.concept.menu.candidate.MenuCandidate -import mozilla.components.concept.menu.candidate.TextMenuCandidate -import mozilla.components.concept.menu.candidate.TextStyle -import mozilla.components.support.ktx.android.content.getColorFromAttr -import org.mozilla.fenix.R -import org.mozilla.fenix.browser.browsingmode.BrowsingMode -import org.mozilla.fenix.components.metrics.Event -import org.mozilla.fenix.components.metrics.MetricController - -class TabCounterMenu( - context: Context, - private val metrics: MetricController, - private val onItemTapped: (Item) -> Unit -) { - - sealed class Item { - object CloseTab : Item() - data class NewTab(val mode: BrowsingMode) : Item() - } - - val menuController: MenuController by lazy { BrowserMenuController() } - - private val newTabItem: TextMenuCandidate - private val newPrivateTabItem: TextMenuCandidate - private val closeTabItem: TextMenuCandidate - - init { - val primaryTextColor = context.getColorFromAttr(R.attr.primaryText) - val textStyle = TextStyle(color = primaryTextColor) - - newTabItem = TextMenuCandidate( - text = context.getString(R.string.browser_menu_new_tab), - start = DrawableMenuIcon( - context, - R.drawable.ic_new, - tint = primaryTextColor - ), - textStyle = textStyle - ) { - metrics.track(Event.TabCounterMenuItemTapped(Event.TabCounterMenuItemTapped.Item.NEW_TAB)) - onItemTapped(Item.NewTab(BrowsingMode.Normal)) - } - - newPrivateTabItem = TextMenuCandidate( - text = context.getString(R.string.home_screen_shortcut_open_new_private_tab_2), - start = DrawableMenuIcon( - context, - R.drawable.ic_private_browsing, - tint = primaryTextColor - ), - textStyle = textStyle - ) { - metrics.track(Event.TabCounterMenuItemTapped(Event.TabCounterMenuItemTapped.Item.NEW_PRIVATE_TAB)) - onItemTapped(Item.NewTab(BrowsingMode.Private)) - } - - closeTabItem = TextMenuCandidate( - text = context.getString(R.string.close_tab), - start = DrawableMenuIcon( - context, - R.drawable.ic_close, - tint = primaryTextColor - ), - textStyle = textStyle - ) { - metrics.track(Event.TabCounterMenuItemTapped(Event.TabCounterMenuItemTapped.Item.CLOSE_TAB)) - onItemTapped(Item.CloseTab) - } - } - - @VisibleForTesting - internal fun menuItems(showOnly: BrowsingMode): List { - return when (showOnly) { - BrowsingMode.Normal -> listOf(newTabItem) - BrowsingMode.Private -> listOf(newPrivateTabItem) - } - } - - @VisibleForTesting - internal fun menuItems(toolbarPosition: ToolbarPosition): List { - val items = listOf( - newTabItem, - newPrivateTabItem, - DividerMenuCandidate(), - closeTabItem - ) - - return when (toolbarPosition) { - ToolbarPosition.BOTTOM -> items.reversed() - ToolbarPosition.TOP -> items - } - } - - /** - * Update the displayed menu items. - * @param showOnly Show only the new tab item corresponding to the given [BrowsingMode]. - */ - fun updateMenu(showOnly: BrowsingMode) { - menuController.submitList(menuItems(showOnly)) - } - - /** - * Update the displayed menu items. - * @param toolbarPosition Return a list that is ordered based on the given [ToolbarPosition]. - */ - fun updateMenu(toolbarPosition: ToolbarPosition) { - menuController.submitList(menuItems(toolbarPosition)) - } -} diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounterToolbarButton.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounterToolbarButton.kt deleted file mode 100644 index 6123eab56f..0000000000 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/TabCounterToolbarButton.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.fenix.components.toolbar - -import android.view.View -import android.view.ViewGroup -import androidx.lifecycle.LifecycleOwner -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.map -import mozilla.components.browser.state.selector.getNormalOrPrivateTabs -import mozilla.components.browser.state.selector.selectedTab -import mozilla.components.browser.state.store.BrowserStore -import mozilla.components.concept.toolbar.Toolbar -import mozilla.components.lib.state.ext.flowScoped -import mozilla.components.support.ktx.android.content.res.resolveAttribute -import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged -import org.mozilla.fenix.ext.components -import java.lang.ref.WeakReference - -/** - * A [Toolbar.Action] implementation that shows a [TabCounter]. - */ -@OptIn(ExperimentalCoroutinesApi::class) -class TabCounterToolbarButton( - private val lifecycleOwner: LifecycleOwner, - private val onItemTapped: (TabCounterMenu.Item) -> Unit = {}, - private val showTabs: () -> Unit -) : Toolbar.Action { - - private var reference: WeakReference = WeakReference(null) - - override fun createView(parent: ViewGroup): View { - val store = parent.context.components.core.store - val metrics = parent.context.components.analytics.metrics - val settings = parent.context.components.settings - - store.flowScoped(lifecycleOwner) { flow -> - flow.map { state -> state.getNormalOrPrivateTabs(isPrivate(store)).size } - .ifChanged() - .collect { tabs -> updateCount(tabs) } - } - - val menu = TabCounterMenu(parent.context, metrics, onItemTapped) - menu.updateMenu(settings.toolbarPosition) - - val view = TabCounter(parent.context).apply { - reference = WeakReference(this) - setOnClickListener { - showTabs.invoke() - } - - setOnLongClickListener { - menu.menuController.show(anchor = it) - true - } - - addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { - override fun onViewAttachedToWindow(v: View?) { - setCount(store.state.getNormalOrPrivateTabs(isPrivate(store)).size) - } - - override fun onViewDetachedFromWindow(v: View?) { /* no-op */ } - }) - } - - // Set selectableItemBackgroundBorderless - view.setBackgroundResource(parent.context.theme.resolveAttribute( - android.R.attr.selectableItemBackgroundBorderless - )) - return view - } - - override fun bind(view: View) = Unit - - private fun updateCount(count: Int) { - reference.get()?.setCountWithAnimation(count) - } - - private fun isPrivate(store: BrowserStore): Boolean { - return store.state.selectedTab?.content?.private ?: false - } -} diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt index 66131222ce..ea8f9bb2d7 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/ToolbarIntegration.kt @@ -7,13 +7,17 @@ package org.mozilla.fenix.components.toolbar import android.content.Context import android.content.res.Configuration import androidx.appcompat.content.res.AppCompatResources +import androidx.core.content.ContextCompat import androidx.lifecycle.LifecycleOwner import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider +import mozilla.components.browser.state.selector.normalTabs +import mozilla.components.browser.state.selector.privateTabs import mozilla.components.browser.toolbar.BrowserToolbar import mozilla.components.browser.toolbar.display.DisplayToolbar import mozilla.components.concept.engine.Engine import mozilla.components.concept.storage.HistoryStorage +import mozilla.components.feature.tabs.toolbar.TabCounterToolbarButton import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature import mozilla.components.feature.toolbar.ToolbarFeature import mozilla.components.feature.toolbar.ToolbarPresenter @@ -35,9 +39,10 @@ abstract class ToolbarIntegration( renderStyle: ToolbarFeature.RenderStyle ) : LifecycleAwareFeature { + val store = context.components.core.store private val toolbarPresenter: ToolbarPresenter = ToolbarPresenter( toolbar, - context.components.core.store, + store, sessionId, ToolbarFeature.UrlRenderConfiguration( PublicSuffixList(context), @@ -139,16 +144,40 @@ class DefaultToolbarIntegration( )!! ) - val tabsAction = TabCounterToolbarButton( - lifecycleOwner, + val tabCounterMenu = FenixTabCounterMenu( + context = context, onItemTapped = { interactor.onTabCounterMenuItemTapped(it) }, + iconColor = + if (isPrivate) { + ContextCompat.getColor(context, R.color.primary_text_private_theme) + } else { + null + } + ).also { + it.updateMenu(context.settings().toolbarPosition) + } + + val tabsAction = TabCounterToolbarButton( + lifecycleOwner = lifecycleOwner, showTabs = { toolbar.hideKeyboard() interactor.onTabCounterClicked() - } + }, + store = store, + menu = tabCounterMenu, + privateColor = ContextCompat.getColor(context, R.color.primary_text_private_theme) ) + + val tabCount = if (isPrivate) { + store.state.privateTabs.size + } else { + store.state.normalTabs.size + } + + tabsAction.updateCount(tabCount) + toolbar.addBrowserAction(tabsAction) val engineForSpeculativeConnects = if (!isPrivate) engine else null diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index ec7d2e5755..58e3136a5d 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -41,9 +41,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE import com.google.android.material.appbar.AppBarLayout import com.google.android.material.snackbar.Snackbar -import kotlinx.android.synthetic.main.fragment_home.privateBrowsingButton -import kotlinx.android.synthetic.main.fragment_home.search_engine_icon -import kotlinx.android.synthetic.main.fragment_home.toolbarLayout +import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.view.bottomBarShadow import kotlinx.android.synthetic.main.fragment_home.view.bottom_bar import kotlinx.android.synthetic.main.fragment_home.view.homeAppBar @@ -81,6 +79,7 @@ import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.ktx.android.content.res.resolveAttribute import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged +import mozilla.components.ui.tabcounter.TabCounterMenu import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R @@ -94,7 +93,7 @@ import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.tips.FenixTipManager import org.mozilla.fenix.components.tips.Tip import org.mozilla.fenix.components.tips.providers.MasterPasswordTipProvider -import org.mozilla.fenix.components.toolbar.TabCounterMenu +import org.mozilla.fenix.components.toolbar.FenixTabCounterMenu import org.mozilla.fenix.components.toolbar.ToolbarPosition import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.hideToolbar @@ -351,23 +350,7 @@ class HomeFragment : Fragment() { observeSearchEngineChanges() createHomeMenu(requireContext(), WeakReference(view.menuButton)) - val tabCounterMenu = TabCounterMenu( - view.context, - metrics = view.context.components.analytics.metrics - ) { - if (it is TabCounterMenu.Item.NewTab) { - (activity as HomeActivity).browsingModeManager.mode = it.mode - } - } - val inverseBrowsingMode = when ((activity as HomeActivity).browsingModeManager.mode) { - BrowsingMode.Normal -> BrowsingMode.Private - BrowsingMode.Private -> BrowsingMode.Normal - } - tabCounterMenu.updateMenu(showOnly = inverseBrowsingMode) - view.tab_button.setOnLongClickListener { - tabCounterMenu.menuController.show(anchor = it) - true - } + createTabCounterMenu(view) view.menuButton.setColorFilter( ContextCompat.getColor( @@ -463,6 +446,40 @@ class HomeFragment : Fragment() { } } + private fun createTabCounterMenu(view: View) { + val browsingModeManager = (activity as HomeActivity).browsingModeManager + val mode = browsingModeManager.mode + + val onItemTapped: (TabCounterMenu.Item) -> Unit = { + if (it is TabCounterMenu.Item.NewTab) { + browsingModeManager.mode = BrowsingMode.Normal + } else if (it is TabCounterMenu.Item.NewPrivateTab) { + browsingModeManager.mode = BrowsingMode.Private + } + } + + val tabCounterMenu = FenixTabCounterMenu( + view.context, + onItemTapped, + iconColor = if (mode == BrowsingMode.Private) { + ContextCompat.getColor(requireContext(), R.color.primary_text_private_theme) + } else { + null + } + ) + + val inverseBrowsingMode = when (mode) { + BrowsingMode.Normal -> BrowsingMode.Private + BrowsingMode.Private -> BrowsingMode.Normal + } + + tabCounterMenu.updateMenu(showOnly = inverseBrowsingMode) + view.tab_button.setOnLongClickListener { + tabCounterMenu.menuController.show(anchor = it) + true + } + } + private fun removeAllTabsAndShowSnackbar(sessionCode: String) { if (sessionCode == ALL_PRIVATE_TABS) { sessionManager.removePrivateSessions() @@ -960,8 +977,11 @@ class HomeFragment : Fragment() { ) } + // TODO use [FenixTabCounterToolbarButton] instead of [TabCounter]: + // https://github.com/mozilla-mobile/fenix/issues/16792 private fun updateTabCounter(browserState: BrowserState) { val tabCount = if (browsingModeManager.mode.isPrivate) { + view?.tab_button?.setColor(ContextCompat.getColor(requireContext(), R.color.primary_text_private_theme)) browserState.privateTabs.size } else { browserState.normalTabs.size diff --git a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt index c24d17b6c6..541711b357 100644 --- a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt +++ b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarView.kt @@ -68,7 +68,7 @@ class AwesomeBarView( override fun invoke( searchTerms: String, searchEngine: mozilla.components.browser.search.SearchEngine?, - parentSession: Session? + parentSessionId: String? ) { interactor.onSearchTermsTapped(searchTerms) } @@ -78,7 +78,7 @@ class AwesomeBarView( override fun invoke( searchTerms: String, searchEngine: mozilla.components.browser.search.SearchEngine?, - parentSession: Session? + parentSessionId: String? ) { interactor.onSearchTermsTapped(searchTerms) } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt index cb1f411cd6..4b26df0c73 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt @@ -42,12 +42,12 @@ import mozilla.components.browser.tabstray.TabViewHolder import mozilla.components.feature.syncedtabs.SyncedTabsFeature import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.ktx.android.util.dpToPx +import mozilla.components.ui.tabcounter.TabCounter.Companion.INFINITE_CHAR_PADDING_BOTTOM import org.mozilla.fenix.R import org.mozilla.fenix.browser.InfoBanner import org.mozilla.fenix.components.metrics.Event -import org.mozilla.fenix.components.toolbar.TabCounter.Companion.INFINITE_CHAR_PADDING_BOTTOM -import org.mozilla.fenix.components.toolbar.TabCounter.Companion.MAX_VISIBLE_TABS -import org.mozilla.fenix.components.toolbar.TabCounter.Companion.SO_MANY_TABS_OPEN +import mozilla.components.ui.tabcounter.TabCounter.Companion.MAX_VISIBLE_TABS +import mozilla.components.ui.tabcounter.TabCounter.Companion.SO_MANY_TABS_OPEN import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.updateAccessibilityCollectionInfo @@ -62,7 +62,7 @@ import mozilla.components.browser.storage.sync.Tab as SyncTab /** * View that contains and configures the BrowserAwesomeBar */ -@Suppress("LongParameterList", "TooManyFunctions", "LargeClass") +@Suppress("LongParameterList", "TooManyFunctions", "LargeClass", "ForbiddenComment") class TabTrayView( private val container: ViewGroup, private val tabsAdapter: FenixTabsAdapter, @@ -697,7 +697,7 @@ class TabTrayView( view.resources.getDimensionPixelSize(R.dimen.tab_tray_top_offset) } - behavior.setExpandedOffset(topOffset) + behavior.expandedOffset = topOffset } fun dismissMenu() { diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 23d861686c..ebfe8e6cb2 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -145,7 +145,7 @@ app:barrierDirection="start" app:constraint_referenced_ids="tab_button" /> - - - - - - - - - - - - diff --git a/app/src/main/res/layout/tab_preview.xml b/app/src/main/res/layout/tab_preview.xml index e7da4ce042..6d4cc1464e 100644 --- a/app/src/main/res/layout/tab_preview.xml +++ b/app/src/main/res/layout/tab_preview.xml @@ -31,7 +31,7 @@ android:layout_weight="1" android:background="@drawable/home_search_background" /> - @color/destructive_dark_theme + + + @color/primary_text_dark_theme + @color/primary_text_dark_theme diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 521ef6a157..845bb44c4e 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -413,4 +413,8 @@ @color/destructive_light_theme + + + @color/primary_text_light_theme + @color/primary_text_light_theme diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2c1e92a163..aafc1dfb97 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -152,8 +152,6 @@ Find in page Private tab - - New tab Save to collection diff --git a/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserInteractorTest.kt index 29b955e6dc..5f2135aa54 100644 --- a/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserInteractorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserInteractorTest.kt @@ -4,6 +4,7 @@ import io.mockk.MockKAnnotations import io.mockk.impl.annotations.RelaxedMockK import io.mockk.mockk import io.mockk.verify +import mozilla.components.ui.tabcounter.TabCounterMenu import org.junit.Before import org.junit.Test diff --git a/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarControllerTest.kt b/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarControllerTest.kt index a5f543f2b9..ac9393d7fd 100644 --- a/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/toolbar/DefaultBrowserToolbarControllerTest.kt @@ -22,6 +22,7 @@ import mozilla.components.concept.engine.EngineView import mozilla.components.feature.search.SearchUseCases import mozilla.components.feature.session.SessionUseCases import mozilla.components.feature.top.sites.TopSitesUseCases +import mozilla.components.ui.tabcounter.TabCounterMenu import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -240,7 +241,7 @@ class DefaultBrowserToolbarControllerTest { @Test fun handleToolbarNewTabPress() { val browsingModeManager = SimpleBrowsingModeManager(BrowsingMode.Private) - val item = TabCounterMenu.Item.NewTab(BrowsingMode.Normal) + val item = TabCounterMenu.Item.NewTab every { activity.browsingModeManager } returns browsingModeManager every { navController.navigate(BrowserFragmentDirections.actionGlobalHome(focusOnAddressBar = true)) } just Runs @@ -254,7 +255,7 @@ class DefaultBrowserToolbarControllerTest { @Test fun handleToolbarNewPrivateTabPress() { val browsingModeManager = SimpleBrowsingModeManager(BrowsingMode.Normal) - val item = TabCounterMenu.Item.NewTab(BrowsingMode.Private) + val item = TabCounterMenu.Item.NewPrivateTab every { activity.browsingModeManager } returns browsingModeManager every { navController.navigate(BrowserFragmentDirections.actionGlobalHome(focusOnAddressBar = true)) } just Runs diff --git a/app/src/test/java/org/mozilla/fenix/components/toolbar/TabCounterMenuTest.kt b/app/src/test/java/org/mozilla/fenix/components/toolbar/TabCounterMenuTest.kt index a85c533b22..a9316f266e 100644 --- a/app/src/test/java/org/mozilla/fenix/components/toolbar/TabCounterMenuTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/toolbar/TabCounterMenuTest.kt @@ -7,50 +7,31 @@ package org.mozilla.fenix.components.toolbar import android.content.Context import androidx.appcompat.view.ContextThemeWrapper import io.mockk.mockk -import io.mockk.verifyAll +import io.mockk.verify import mozilla.components.concept.menu.candidate.DividerMenuCandidate -import mozilla.components.concept.menu.candidate.DrawableMenuIcon import mozilla.components.concept.menu.candidate.TextMenuCandidate import mozilla.components.support.test.robolectric.testContext +import mozilla.components.ui.tabcounter.TabCounterMenu import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode -import org.mozilla.fenix.components.metrics.Event -import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class TabCounterMenuTest { private lateinit var context: Context - private lateinit var metrics: MetricController private lateinit var onItemTapped: (TabCounterMenu.Item) -> Unit - private lateinit var menu: TabCounterMenu + private lateinit var menu: FenixTabCounterMenu @Before fun setup() { context = ContextThemeWrapper(testContext, R.style.NormalTheme) - metrics = mockk(relaxed = true) onItemTapped = mockk(relaxed = true) - menu = TabCounterMenu(context, metrics, onItemTapped) - } - - @Test - fun `all items use primary text color styling`() { - val items = menu.menuItems(ToolbarPosition.BOTTOM) - assertEquals(4, items.size) - - val textItems = items.mapNotNull { it as? TextMenuCandidate } - assertEquals(3, textItems.size) - - val primaryTextColor = context.getColor(R.color.primary_text_normal_theme) - for (item in textItems) { - assertEquals(primaryTextColor, item.textStyle.color) - assertEquals(primaryTextColor, (item.start as DrawableMenuIcon).tint) - } + menu = FenixTabCounterMenu(context, onItemTapped) } @Test @@ -62,10 +43,7 @@ class TabCounterMenuTest { assertEquals("New tab", item.text) item.onClick() - verifyAll { - metrics.track(Event.TabCounterMenuItemTapped(Event.TabCounterMenuItemTapped.Item.NEW_TAB)) - onItemTapped(TabCounterMenu.Item.NewTab(BrowsingMode.Normal)) - } + verify { onItemTapped(TabCounterMenu.Item.NewTab) } } @Test @@ -77,10 +55,7 @@ class TabCounterMenuTest { assertEquals("New private tab", item.text) item.onClick() - verifyAll { - metrics.track(Event.TabCounterMenuItemTapped(Event.TabCounterMenuItemTapped.Item.NEW_PRIVATE_TAB)) - onItemTapped(TabCounterMenu.Item.NewTab(BrowsingMode.Private)) - } + verify { onItemTapped(TabCounterMenu.Item.NewPrivateTab) } } @Test diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 432a889121..c706cedb76 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "68.0.20201201190117" + const val VERSION = "69.0.20201203202830" } diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 6749a03655..8d834b2268 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -32,7 +32,7 @@ object Versions { const val androidx_core = "1.3.2" const val androidx_paging = "2.1.0" const val androidx_transition = "1.3.0" - const val androidx_work = "2.2.0" + const val androidx_work = "2.4.0" const val google_material = "1.2.1" const val mozilla_android_components = AndroidComponents.VERSION @@ -139,6 +139,7 @@ object Deps { const val mozilla_ui_colors = "org.mozilla.components:ui-colors:${Versions.mozilla_android_components}" const val mozilla_ui_icons = "org.mozilla.components:ui-icons:${Versions.mozilla_android_components}" const val mozilla_ui_widgets = "org.mozilla.components:ui-widgets:${Versions.mozilla_android_components}" + const val mozilla_ui_tabcounter = "org.mozilla.components:ui-tabcounter:${Versions.mozilla_android_components}" const val mozilla_lib_crash = "org.mozilla.components:lib-crash:${Versions.mozilla_android_components}" const val mozilla_lib_push_firebase = "org.mozilla.components:lib-push-firebase:${Versions.mozilla_android_components}"