Commit 9d1982b7 authored by Christian Sadilek's avatar Christian Sadilek
Browse files

Closes #3680: Synchronize thumbnails between browser-store and session

parent 66145fa6
......@@ -11,10 +11,12 @@ import mozilla.components.browser.session.engine.request.LoadRequestOption
import mozilla.components.browser.session.ext.syncDispatch
import mozilla.components.browser.session.ext.toSecurityInfoState
import mozilla.components.browser.session.tab.CustomTabConfig
import mozilla.components.browser.state.action.ContentAction.RemoveThumbnailAction
import mozilla.components.browser.state.action.ContentAction.UpdateLoadingStateAction
import mozilla.components.browser.state.action.ContentAction.UpdateProgressAction
import mozilla.components.browser.state.action.ContentAction.UpdateSecurityInfo
import mozilla.components.browser.state.action.ContentAction.UpdateSearchTermsAction
import mozilla.components.browser.state.action.ContentAction.UpdateThumbnailAction
import mozilla.components.browser.state.action.ContentAction.UpdateTitleAction
import mozilla.components.browser.state.action.ContentAction.UpdateUrlAction
import mozilla.components.browser.state.store.BrowserStore
......@@ -332,6 +334,9 @@ class Session(
*/
var thumbnail: Bitmap? by Delegates.observable<Bitmap?>(null) { _, _, new ->
notifyObservers { onThumbnailChanged(this@Session, new) }
val action = if (new != null) UpdateThumbnailAction(id, new) else RemoveThumbnailAction(id)
store?.syncDispatch(action)
}
/**
......
......@@ -676,6 +676,24 @@ class SessionTest {
verify(observer, never()).onThumbnailChanged(session, emptyThumbnail)
}
@Test
fun `action is dispatched when thumbnail changes`() {
val store: BrowserStore = mock()
`when`(store.dispatch(any())).thenReturn(mock())
val session = Session("https://www.mozilla.org")
session.store = store
val emptyThumbnail = spy(Bitmap::class.java)
session.thumbnail = emptyThumbnail
verify(store).dispatch(ContentAction.UpdateThumbnailAction(session.id, emptyThumbnail))
session.thumbnail = null
verify(store).dispatch(ContentAction.RemoveThumbnailAction(session.id))
verifyNoMoreInteractions(store)
}
@Test
fun `session observer has default methods`() {
val session = Session("")
......
......@@ -4,6 +4,7 @@
package mozilla.components.browser.state.action
import android.graphics.Bitmap
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.SecurityInfoState
......@@ -98,6 +99,11 @@ sealed class CustomTabListAction : BrowserAction() {
* [BrowserState].
*/
sealed class ContentAction : BrowserAction() {
/**
* Removes the thumbnail of the [ContentState] with the given [sessionId].
*/
data class RemoveThumbnailAction(val sessionId: String) : ContentAction()
/**
* Updates the URL of the [ContentState] with the given [sessionId].
*/
......@@ -127,4 +133,9 @@ sealed class ContentAction : BrowserAction() {
* Updates the [SecurityInfoState] of the [ContentState] with the given [sessionId].
*/
data class UpdateSecurityInfo(val sessionId: String, val securityInfo: SecurityInfoState) : ContentAction()
/**
* Updates the thumbnail of the [ContentState] with the given [sessionId].
*/
data class UpdateThumbnailAction(val sessionId: String, val thumbnail: Bitmap) : ContentAction()
}
......@@ -15,6 +15,9 @@ internal object ContentStateReducer {
*/
fun reduce(state: BrowserState, action: ContentAction): BrowserState {
return when (action) {
is ContentAction.RemoveThumbnailAction -> updateContentState(state, action.sessionId) {
it.copy(thumbnail = null)
}
is ContentAction.UpdateUrlAction -> updateContentState(state, action.sessionId) {
it.copy(url = action.url)
}
......@@ -33,6 +36,9 @@ internal object ContentStateReducer {
is ContentAction.UpdateSecurityInfo -> updateContentState(state, action.sessionId) {
it.copy(securityInfo = action.securityInfo)
}
is ContentAction.UpdateThumbnailAction -> updateContentState(state, action.sessionId) {
it.copy(thumbnail = action.thumbnail)
}
}
}
}
......
......@@ -4,6 +4,8 @@
package mozilla.components.browser.state.state
import android.graphics.Bitmap
/**
* Value type that represents the state of the content within a [SessionState].
*
......@@ -14,8 +16,10 @@ package mozilla.components.browser.state.state
* @property searchTerms the last used search terms, or an empty string if no
* search was executed for this session.
* @property securityInfo the security information as [SecurityInfoState],
* describing whether or not the current session is for a secure URL, as well
* describing whether or not the this session is for a secure URL, as well
* as the host and SSL certificate authority.
* @property thumbnail the last generated [Bitmap] of this session's content, to
* be used as a preview in e.g. a tab switcher.
*/
data class ContentState(
val url: String,
......@@ -24,5 +28,6 @@ data class ContentState(
val progress: Int = 0,
val loading: Boolean = false,
val searchTerms: String = "",
val securityInfo: SecurityInfoState = SecurityInfoState()
val securityInfo: SecurityInfoState = SecurityInfoState(),
val thumbnail: Bitmap? = null
)
......@@ -4,6 +4,7 @@
package mozilla.components.browser.state.action
import android.graphics.Bitmap
import mozilla.components.browser.state.selector.findCustomTab
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.SecurityInfoState
......@@ -15,9 +16,11 @@ import mozilla.components.support.test.ext.joinBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.spy
class ContentActionTest {
private lateinit var store: BrowserStore
......@@ -156,6 +159,40 @@ class ContentActionTest {
assertEquals("The Mozilla Team", tab.content.securityInfo.issuer)
}
@Test
fun `UpdateThumbnailAction updates thumbnail`() {
val thumbnail = spy(Bitmap::class.java)
assertNotEquals(thumbnail, tab.content.thumbnail)
assertNotEquals(thumbnail, otherTab.content.thumbnail)
store.dispatch(
ContentAction.UpdateThumbnailAction(tab.id, thumbnail)
).joinBlocking()
assertEquals(thumbnail, tab.content.thumbnail)
assertNotEquals(thumbnail, otherTab.content.thumbnail)
}
@Test
fun `RemoveThumbnailAction removes thumbnail`() {
val thumbnail = spy(Bitmap::class.java)
assertNotEquals(thumbnail, tab.content.thumbnail)
store.dispatch(
ContentAction.UpdateThumbnailAction(tab.id, thumbnail)
).joinBlocking()
assertEquals(thumbnail, tab.content.thumbnail)
store.dispatch(
ContentAction.RemoveThumbnailAction(tab.id)
).joinBlocking()
assertNull(tab.content.thumbnail)
}
@Test
fun `Updating custom tab`() {
val customTab = createCustomTab("https://getpocket.com")
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment