Extract quick action sheet observer code (#4368)
parent
7d02354f4f
commit
de14962e3f
|
@ -365,7 +365,6 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||
|
||||
@CallSuper
|
||||
override fun onSessionSelected(session: Session) {
|
||||
super.onSessionSelected(session)
|
||||
if (!browserInitialized) {
|
||||
// Initializing a new coroutineScope to avoid ConcurrentModificationException in ObserverRegistry
|
||||
// This will be removed when ObserverRegistry is deprecated by browser-state.
|
||||
|
|
|
@ -22,7 +22,6 @@ import kotlinx.android.synthetic.main.fragment_browser.view.*
|
|||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.ObsoleteCoroutinesApi
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -49,9 +48,8 @@ import org.mozilla.fenix.home.sessioncontrol.SessionControlChange
|
|||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||
import org.mozilla.fenix.quickactionsheet.DefaultQuickActionSheetController
|
||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetSessionObserver
|
||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetView
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Fragment used for browsing the web within the main app and external apps.
|
||||
|
@ -61,11 +59,11 @@ import java.net.URL
|
|||
@Suppress("TooManyFunctions")
|
||||
class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
||||
private lateinit var quickActionSheetView: QuickActionSheetView
|
||||
private var quickActionSheetSessionObserver: QuickActionSheetSessionObserver? = null
|
||||
|
||||
private val readerViewFeature = ViewBoundFeatureWrapper<ReaderViewFeature>()
|
||||
private val thumbnailsFeature = ViewBoundFeatureWrapper<ThumbnailsFeature>()
|
||||
private val customTabsIntegration = ViewBoundFeatureWrapper<CustomTabsIntegration>()
|
||||
private var findBookmarkJob: Job? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -93,7 +91,7 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
override fun initializeUI(view: View): Session? {
|
||||
val sessionManager = requireComponents.core.sessionManager
|
||||
|
||||
return super.initializeUI(view)?.also { session ->
|
||||
return super.initializeUI(view)?.also {
|
||||
|
||||
quickActionSheetView =
|
||||
QuickActionSheetView(view.nestedScrollQuickAction, browserInteractor)
|
||||
|
@ -154,8 +152,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
themeReaderViewControlsForPrivateMode(view.readerViewControlsBar)
|
||||
}
|
||||
|
||||
updateBookmarkState(session)
|
||||
|
||||
consumeFrom(browserStore) {
|
||||
quickActionSheetView.update(it)
|
||||
browserToolbarView.update(it)
|
||||
|
@ -165,8 +161,14 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
subscribeToSession()
|
||||
subscribeToTabCollections()
|
||||
quickActionSheetSessionObserver = QuickActionSheetSessionObserver(
|
||||
lifecycleScope,
|
||||
requireComponents,
|
||||
dispatch = { action -> browserStore.dispatch(action) }
|
||||
).also { observer ->
|
||||
getSessionById()?.register(observer, this, autoPause = true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -306,56 +308,9 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
})
|
||||
}
|
||||
|
||||
private fun subscribeToSession() {
|
||||
val observer = object : Session.Observer {
|
||||
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
||||
if (!loading) {
|
||||
updateBookmarkState(session)
|
||||
browserStore.dispatch(QuickActionSheetAction.BounceNeededChange)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUrlChanged(session: Session, url: String) {
|
||||
updateBookmarkState(session)
|
||||
updateAppLinksState(session)
|
||||
}
|
||||
}
|
||||
getSessionById()?.register(observer, this, autoPause = true)
|
||||
}
|
||||
|
||||
override fun onSessionSelected(session: Session) {
|
||||
super.onSessionSelected(session)
|
||||
updateBookmarkState(session)
|
||||
}
|
||||
|
||||
private suspend fun findBookmarkedURL(session: Session?): Boolean {
|
||||
return withContext(IO) {
|
||||
session?.let {
|
||||
try {
|
||||
val url = URL(it.url).toString()
|
||||
val list = requireComponents.core.bookmarksStorage.getBookmarksWithUrl(url)
|
||||
list.isNotEmpty() && list[0].url == url
|
||||
} catch (e: MalformedURLException) {
|
||||
false
|
||||
}
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateBookmarkState(session: Session) {
|
||||
findBookmarkJob?.cancel()
|
||||
findBookmarkJob = lifecycleScope.launch(IO) {
|
||||
val found = findBookmarkedURL(session)
|
||||
withContext(Main) {
|
||||
browserStore.dispatch(QuickActionSheetAction.BookmarkedStateChange(found))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAppLinksState(session: Session) {
|
||||
val url = session.url
|
||||
val appLinks = requireComponents.useCases.appLinksUseCases.appLinkRedirect
|
||||
browserStore.dispatch(QuickActionSheetAction.AppLinkStateChange(appLinks.invoke(url).hasExternalApp()))
|
||||
quickActionSheetSessionObserver?.updateBookmarkState(session)
|
||||
}
|
||||
|
||||
private val collectionStorageObserver = object : TabCollectionStorage.Observer {
|
||||
|
@ -366,14 +321,14 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||
override fun onTabsAdded(tabCollection: TabCollection, sessions: List<Session>) {
|
||||
showTabSavedToCollectionSnackbar()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showTabSavedToCollectionSnackbar() {
|
||||
view?.let { view ->
|
||||
FenixSnackbar.make(view, Snackbar.LENGTH_SHORT)
|
||||
.setText(view.context.getString(R.string.create_collection_tab_saved))
|
||||
.setAnchorView(browserToolbarView.view)
|
||||
.show()
|
||||
private fun showTabSavedToCollectionSnackbar() {
|
||||
view?.let { view ->
|
||||
FenixSnackbar.make(view, Snackbar.LENGTH_SHORT)
|
||||
.setText(view.context.getString(R.string.create_collection_tab_saved))
|
||||
.setAnchorView(browserToolbarView.view)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/* 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.quickactionsheet
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import mozilla.components.browser.session.Session
|
||||
import org.mozilla.fenix.components.Components
|
||||
import org.mozilla.fenix.components.toolbar.QuickActionSheetAction
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
|
||||
class QuickActionSheetSessionObserver(
|
||||
private val parentScope: CoroutineScope,
|
||||
private val components: Components,
|
||||
private val dispatch: (QuickActionSheetAction) -> Unit
|
||||
) : Session.Observer {
|
||||
|
||||
private var findBookmarkJob: Job? = null
|
||||
|
||||
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
||||
if (!loading) {
|
||||
updateBookmarkState(session)
|
||||
dispatch(QuickActionSheetAction.BounceNeededChange)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUrlChanged(session: Session, url: String) {
|
||||
updateBookmarkState(session)
|
||||
updateAppLinksState(session)
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches job to update the bookmark button on the quick action sheet.
|
||||
*/
|
||||
fun updateBookmarkState(session: Session) {
|
||||
findBookmarkJob?.cancel()
|
||||
findBookmarkJob = parentScope.launch(Main) {
|
||||
val found = findBookmarkedURL(session)
|
||||
dispatch(QuickActionSheetAction.BookmarkedStateChange(found))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the app link button on the quick action sheet.
|
||||
*/
|
||||
private fun updateAppLinksState(session: Session) {
|
||||
val url = session.url
|
||||
val appLinks = components.useCases.appLinksUseCases.appLinkRedirect
|
||||
dispatch(QuickActionSheetAction.AppLinkStateChange(appLinks(url).hasExternalApp()))
|
||||
}
|
||||
|
||||
private suspend fun findBookmarkedURL(session: Session): Boolean = withContext(IO) {
|
||||
try {
|
||||
val url = URL(session.url).toString()
|
||||
val list = components.core.bookmarksStorage.getBookmarksWithUrl(url)
|
||||
list.isNotEmpty() && list[0].url == url
|
||||
} catch (e: MalformedURLException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* 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.quickactionsheet
|
||||
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.ObsoleteCoroutinesApi
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.feature.app.links.AppLinkRedirect
|
||||
import mozilla.components.feature.app.links.AppLinksUseCases
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.components.Components
|
||||
import org.mozilla.fenix.components.toolbar.BrowserStore
|
||||
import org.mozilla.fenix.components.toolbar.QuickActionSheetAction
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
@ObsoleteCoroutinesApi
|
||||
class QuickActionSheetSessionObserverTest {
|
||||
|
||||
private lateinit var components: Components
|
||||
private lateinit var appLinkRedirect: AppLinksUseCases.GetAppLinkRedirect
|
||||
private lateinit var store: BrowserStore
|
||||
private lateinit var dispatch: (QuickActionSheetAction) -> Unit
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
components = mockk(relaxed = true)
|
||||
appLinkRedirect = mockk(relaxed = true)
|
||||
store = mockk(relaxed = true)
|
||||
dispatch = { store.dispatch(it) }
|
||||
|
||||
every { components.useCases.appLinksUseCases.appLinkRedirect } returns appLinkRedirect
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onLoadingStateChanged dispatches BounceNeededChange and updates bookmark button`() {
|
||||
val session: Session = mockk()
|
||||
val observer = spyk(QuickActionSheetSessionObserver(mockk(), components, dispatch))
|
||||
every { observer.updateBookmarkState(session) } just Runs
|
||||
|
||||
observer.onLoadingStateChanged(session, true)
|
||||
verify(exactly = 0) { store.dispatch(QuickActionSheetAction.BounceNeededChange) }
|
||||
|
||||
observer.onLoadingStateChanged(session, false)
|
||||
verify { observer.updateBookmarkState(session) }
|
||||
verify { store.dispatch(QuickActionSheetAction.BounceNeededChange) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onUrlChanged updates bookmark and app link buttons`() {
|
||||
val url = "https://example.com"
|
||||
val session: Session = mockk()
|
||||
every { session.url } returns url
|
||||
|
||||
val observer = spyk(QuickActionSheetSessionObserver(mockk(), components, dispatch))
|
||||
every { observer.updateBookmarkState(session) } just Runs
|
||||
every { appLinkRedirect.invoke(url) } returns AppLinkRedirect(mockk(), "", false)
|
||||
|
||||
observer.onUrlChanged(session, "")
|
||||
verify { observer.updateBookmarkState(session) }
|
||||
verify { appLinkRedirect.invoke("https://example.com") }
|
||||
verify { store.dispatch(QuickActionSheetAction.AppLinkStateChange(true)) }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue