Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

🎲 For #6907 - Dispatches tabsTray update when MediaState changes. #6908

Merged
merged 3 commits into from
May 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/browser/tabstray/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ android {

dependencies {
api project(':concept-tabstray')

implementation project(':ui-icons')
implementation project(':ui-colors')
implementation project(':support-base')
Expand Down
3 changes: 2 additions & 1 deletion components/concept/tabstray/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ android {
}

dependencies {
implementation project(':support-base')
api project(':concept-engine')

implementation project(':support-base')
implementation Dependencies.kotlin_stdlib
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package mozilla.components.concept.tabstray

import android.graphics.Bitmap
import mozilla.components.concept.engine.media.Media

/**
* Data class representing a tab to be displayed in a [TabsTray].
Expand All @@ -14,11 +15,13 @@ import android.graphics.Bitmap
* @property title Current title of the tab (or an empty [String]]).
* @property icon Current icon of the tab (or null)
* @property thumbnail Current thumbnail of the tab (or null)
* @property mediaState Current media state for the tab (or null)
*/
data class Tab(
val id: String,
val url: String,
val title: String = "",
val icon: Bitmap? = null,
val thumbnail: Bitmap? = null
val thumbnail: Bitmap? = null,
val mediaState: Media.State? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@
package mozilla.components.feature.tabs.ext

import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.MediaState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.concept.tabstray.Tabs

private fun BrowserState.mediaStateForTab(tab: TabSessionState): MediaState.State =
if (media.aggregate.activeTabId == tab.id) {
media.aggregate.state
} else {
MediaState.State.NONE
}

internal fun BrowserState.toTabs(
tabsFilter: (TabSessionState) -> Boolean = { true }
) = Tabs(
list = tabs
.filter(tabsFilter)
.map { it.toTab() },
.map { it.toTab(mediaStateForTab(it)) },
selectedIndex = tabs.indexOfFirst { it.id == selectedTabId }
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@

package mozilla.components.feature.tabs.ext

import mozilla.components.browser.state.state.MediaState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.concept.engine.media.Media
import mozilla.components.concept.tabstray.Tab

internal fun TabSessionState.toTab() = Tab(
internal fun TabSessionState.toTab(mediaState: MediaState.State) = Tab(
id,
content.url,
content.title,
content.icon,
content.thumbnail
content.thumbnail,
when (mediaState) {
MediaState.State.PLAYING -> Media.State.PLAYING
MediaState.State.PAUSED -> Media.State.PAUSED
else -> null
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ class TabsTrayPresenter(
}

private suspend fun collect(flow: Flow<BrowserState>) {
flow.map { state -> state.toTabs(tabsFilter) }
flow.map { it.toTabs(tabsFilter) }
.ifChanged()
.collect { tabs ->

// Do not invoke the callback on start if this is the initial state.
if (tabs.list.isEmpty() && this.tabs != null) {
closeTabsTray.invoke()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* 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 mozilla.components.feature.tabs.ext

import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.MediaState
import mozilla.components.browser.state.state.createTab
import mozilla.components.concept.engine.media.Media
import org.junit.Test
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull

class TabSessionStateTest {
@Test
fun `mediaState gets set correctly`() {
var browserState = BrowserState(
tabs = listOf(
createTab("https://www.mozilla.org", id = "a"),
createTab("https://getpocket.com", id = "b"),
createTab("https://developer.mozilla.org", id = "c"),
createTab("https://www.firefox.com", id = "d"),
createTab("https://www.google.com", id = "e")
),
selectedTabId = "a",
media = MediaState(MediaState.Aggregate(activeTabId = "a", state = MediaState.State.PLAYING))
)

var tabs = browserState.toTabs()
assertEquals(Media.State.PLAYING, tabs.list[0].mediaState)

browserState = browserState.copy(
media = MediaState(MediaState.Aggregate(activeTabId = "b", state = MediaState.State.PAUSED))
)
tabs = browserState.toTabs()
assertNull(tabs.list[0].mediaState)
assertEquals(Media.State.PAUSED, tabs.list[1].mediaState)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import mozilla.components.browser.state.action.MediaAction
import mozilla.components.browser.state.action.TabListAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.MediaState
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.tabstray.Tabs
import mozilla.components.concept.tabstray.TabsTray
import mozilla.components.feature.tabs.ext.toTabs
import mozilla.components.support.test.any
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.mock
import org.junit.After
Expand Down Expand Up @@ -216,6 +219,38 @@ class TabsTrayPresenterTest {
verify(tabsTray).onTabsChanged(3, 1)
}

@Test
fun `tabs tray will get updated if mediaState changes`() {
val store = BrowserStore(
BrowserState(
tabs = listOf(
createTab("https://www.mozilla.org", id = "a"),
createTab("https://getpocket.com", id = "b"),
createTab("https://developer.mozilla.org", id = "c"),
createTab("https://www.firefox.com", id = "d"),
createTab("https://www.google.com", id = "e")
),
selectedTabId = "a"
)
)

val tabsTray: MockedTabsTray = spy(MockedTabsTray())
val presenter = TabsTrayPresenter(tabsTray, store, { true }, mock())

presenter.start()
testDispatcher.advanceUntilIdle()

store.dispatch(
MediaAction.UpdateMediaAggregateAction(
store.state.media.aggregate.copy(activeTabId = "a", state = MediaState.State.PLAYING)
)
).joinBlocking()

testDispatcher.advanceUntilIdle()

verify(tabsTray, times(2)).updateTabs(any())
}

@Test
fun `presenter will close tabs tray when all sessions get removed`() {
val store = BrowserStore(
Expand Down
6 changes: 6 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ permalink: /changelog/
* [Gecko](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Gecko.kt)
* [Configuration](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Config.kt)

* **feature-tabs**
* Fixed issue [#6907](https://github.com/mozilla-mobile/android-components/issues/6907). Uses MediaState when mapping BrowserState to tabs.

* **concept-tabstray**
* For issue [#6907](https://github.com/mozilla-mobile/android-components/issues/6907). Adds `Media.State` to `Tab`

* **feature-session**
* ⚠️ **This is a breaking change**: Added optional `crashReporting` param to [PictureInPictureFeature] so we can record caught exceptions.

Expand Down