1
0
Fork 0

Use lifecycleScope for collections fragments

master
Tiger Oakes 2019-06-12 20:14:46 -04:00 committed by Emily Kager
parent 6bf8d6be34
commit d01bb8c442
12 changed files with 99 additions and 204 deletions

View File

@ -353,7 +353,8 @@ dependencies {
implementation Deps.androidx_navigation_fragment implementation Deps.androidx_navigation_fragment
implementation Deps.androidx_navigation_ui implementation Deps.androidx_navigation_ui
implementation Deps.androidx_recyclerview implementation Deps.androidx_recyclerview
implementation Deps.androidx_lifecycle_viewmodel_ktx implementation Deps.androidx_lifecycle_runtime
implementation Deps.androidx_lifecycle_viewmodel
implementation Deps.androidx_lifecycle_viewmodel_ss implementation Deps.androidx_lifecycle_viewmodel_ss
implementation Deps.androidx_core implementation Deps.androidx_core
implementation Deps.androidx_core_ktx implementation Deps.androidx_core_ktx

View File

@ -23,14 +23,13 @@ import androidx.core.net.toUri
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.NavHostFragment.findNavController
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.component_search.* import kotlinx.android.synthetic.main.component_search.*
import kotlinx.android.synthetic.main.fragment_browser.* import kotlinx.android.synthetic.main.fragment_browser.*
import kotlinx.android.synthetic.main.fragment_browser.view.* import kotlinx.android.synthetic.main.fragment_browser.view.*
import kotlinx.android.synthetic.main.fragment_search.* import kotlinx.android.synthetic.main.fragment_search.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -100,10 +99,9 @@ import org.mozilla.fenix.utils.ItsNotBrokenSnack
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
import java.net.MalformedURLException import java.net.MalformedURLException
import java.net.URL import java.net.URL
import kotlin.coroutines.CoroutineContext
@SuppressWarnings("TooManyFunctions", "LargeClass") @SuppressWarnings("TooManyFunctions", "LargeClass")
class BrowserFragment : Fragment(), BackHandler, CoroutineScope { class BrowserFragment : Fragment(), BackHandler {
private lateinit var toolbarComponent: ToolbarComponent private lateinit var toolbarComponent: ToolbarComponent
@ -125,12 +123,9 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>() private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
private val customTabsIntegration = ViewBoundFeatureWrapper<CustomTabsIntegration>() private val customTabsIntegration = ViewBoundFeatureWrapper<CustomTabsIntegration>()
private var findBookmarkJob: Job? = null private var findBookmarkJob: Job? = null
private lateinit var job: Job
var customTabSessionId: String? = null var customTabSessionId: String? = null
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// Disabled while awaiting a better solution to #3209 // Disabled while awaiting a better solution to #3209
@ -139,7 +134,6 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
// TransitionInflater.from(context).inflateTransition(android.R.transition.move).setDuration( // TransitionInflater.from(context).inflateTransition(android.R.transition.move).setDuration(
// SHARED_TRANSITION_MS // SHARED_TRANSITION_MS
// ) // )
job = Job()
} }
@SuppressWarnings("ComplexMethod") @SuppressWarnings("ComplexMethod")
@ -564,9 +558,9 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private fun bookmarkTapped() { private fun bookmarkTapped() {
getSessionById()?.let { session -> getSessionById()?.let { session ->
CoroutineScope(IO).launch { lifecycleScope.launch(IO) {
val components = requireComponents val bookmarksStorage = requireComponents.core.bookmarksStorage
val existing = components.core.bookmarksStorage.getBookmarksWithUrl(session.url) val existing = bookmarksStorage.getBookmarksWithUrl(session.url)
val found = existing.isNotEmpty() && existing[0].url == session.url val found = existing.isNotEmpty() && existing[0].url == session.url
if (found) { if (found) {
launch(Main) { launch(Main) {
@ -577,13 +571,12 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
) )
} }
} else { } else {
val guid = components.core.bookmarksStorage val guid = bookmarksStorage.addItem(
.addItem( BookmarkRoot.Mobile.id,
BookmarkRoot.Mobile.id, session.url,
session.url, session.title,
session.title, null
null )
)
launch(Main) { launch(Main) {
getManagedEmitter<QuickActionChange>() getManagedEmitter<QuickActionChange>()
.onNext(QuickActionChange.BookmarkedStateChange(true)) .onNext(QuickActionChange.BookmarkedStateChange(true))
@ -685,11 +678,6 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
promptsFeature.withFeature { it.onActivityResult(requestCode, resultCode, data) } promptsFeature.withFeature { it.onActivityResult(requestCode, resultCode, data) }
} }
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
// This method triggers the complexity warning. However it's actually not that hard to understand. // This method triggers the complexity warning. However it's actually not that hard to understand.
@SuppressWarnings("ComplexMethod") @SuppressWarnings("ComplexMethod")
private fun trackToolbarItemInteraction(action: SearchAction.ToolbarMenuItemTapped) { private fun trackToolbarItemInteraction(action: SearchAction.ToolbarMenuItemTapped) {
@ -824,8 +812,8 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private fun showQuickSettingsDialog() { private fun showQuickSettingsDialog() {
val session = getSessionById() ?: return val session = getSessionById() ?: return
launch { lifecycleScope.launch(IO) {
val host = session.url.toUri()?.host val host = session.url.toUri().host
val sitePermissions: SitePermissions? = host?.let { val sitePermissions: SitePermissions? = host?.let {
val storage = requireContext().components.core.permissionStorage val storage = requireContext().components.core.permissionStorage
storage.findSitePermissionsBy(it) storage.findSitePermissionsBy(it)
@ -923,7 +911,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private fun updateBookmarkState(session: Session) { private fun updateBookmarkState(session: Session) {
if (findBookmarkJob?.isActive == true) findBookmarkJob?.cancel() if (findBookmarkJob?.isActive == true) findBookmarkJob?.cancel()
findBookmarkJob = launch { findBookmarkJob = lifecycleScope.launch(IO) {
val found = findBookmarkedURL(session) val found = findBookmarkedURL(session)
launch(Main) { launch(Main) {
getManagedEmitter<QuickActionChange>() getManagedEmitter<QuickActionChange>()

View File

@ -11,28 +11,23 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.fragment_create_collection.view.* import kotlinx.android.synthetic.main.fragment_create_collection.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.mozilla.fenix.FenixViewModelProvider import org.mozilla.fenix.FenixViewModelProvider
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.home.sessioncontrol.toSessionBundle import org.mozilla.fenix.home.sessioncontrol.toSessionBundle
import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter import org.mozilla.fenix.mvi.getManagedEmitter
import kotlin.coroutines.CoroutineContext
class CreateCollectionFragment : DialogFragment(), CoroutineScope { class CreateCollectionFragment : DialogFragment() {
private lateinit var collectionCreationComponent: CollectionCreationComponent private lateinit var collectionCreationComponent: CollectionCreationComponent
private lateinit var job: Job
private lateinit var viewModel: CreateCollectionViewModel private lateinit var viewModel: CreateCollectionViewModel
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
isCancelable = false isCancelable = false
@ -44,7 +39,6 @@ class CreateCollectionFragment : DialogFragment(), CoroutineScope {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
job = Job()
val view = inflater.inflate(R.layout.fragment_create_collection, container, false) val view = inflater.inflate(R.layout.fragment_create_collection, container, false)
viewModel = activity!!.run { viewModel = activity!!.run {
@ -86,11 +80,6 @@ class CreateCollectionFragment : DialogFragment(), CoroutineScope {
subscribeToActions() subscribeToActions()
} }
override fun onDestroyView() {
super.onDestroyView()
job.cancel()
}
@Suppress("ComplexMethod") @Suppress("ComplexMethod")
private fun subscribeToActions() { private fun subscribeToActions() {
getAutoDisposeObservable<CollectionCreationAction>().subscribe { getAutoDisposeObservable<CollectionCreationAction>().subscribe {
@ -129,8 +118,8 @@ class CreateCollectionFragment : DialogFragment(), CoroutineScope {
context?.let { context -> context?.let { context ->
val sessionBundle = it.tabs.toList().toSessionBundle(context) val sessionBundle = it.tabs.toList().toSessionBundle(context)
launch(Dispatchers.IO) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.createCollection(it.name, sessionBundle) context.components.core.tabCollectionStorage.createCollection(it.name, sessionBundle)
} }
} }
} }
@ -138,15 +127,15 @@ class CreateCollectionFragment : DialogFragment(), CoroutineScope {
dismiss() dismiss()
context?.let { context -> context?.let { context ->
val sessionBundle = it.tabs.toList().toSessionBundle(context) val sessionBundle = it.tabs.toList().toSessionBundle(context)
launch(Dispatchers.IO) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage context.components.core.tabCollectionStorage
.addTabsToCollection(it.collection, sessionBundle) .addTabsToCollection(it.collection, sessionBundle)
} }
} }
} }
is CollectionCreationAction.RenameCollection -> { is CollectionCreationAction.RenameCollection -> {
dismiss() dismiss()
launch(Dispatchers.IO) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.renameCollection(it.collection, it.name) requireComponents.core.tabCollectionStorage.renameCollection(it.collection, it.name)
} }
} }

View File

@ -10,11 +10,11 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_exceptions.view.* import kotlinx.android.synthetic.main.fragment_exceptions.view.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.mozilla.fenix.FenixViewModelProvider import org.mozilla.fenix.FenixViewModelProvider
@ -22,19 +22,10 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter import org.mozilla.fenix.mvi.getManagedEmitter
import kotlin.coroutines.CoroutineContext
class ExceptionsFragment : Fragment(), CoroutineScope { class ExceptionsFragment : Fragment() {
private var job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private lateinit var exceptionsComponent: ExceptionsComponent private lateinit var exceptionsComponent: ExceptionsComponent
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
activity?.title = getString(R.string.preference_exceptions) activity?.title = getString(R.string.preference_exceptions)
@ -65,14 +56,14 @@ class ExceptionsFragment : Fragment(), CoroutineScope {
getAutoDisposeObservable<ExceptionsAction>() getAutoDisposeObservable<ExceptionsAction>()
.subscribe { .subscribe {
when (it) { when (it) {
is ExceptionsAction.Delete.All -> launch(Dispatchers.IO) { is ExceptionsAction.Delete.All -> viewLifecycleOwner.lifecycleScope.launch(IO) {
val domains = ExceptionDomains.load(context!!) val domains = ExceptionDomains.load(context!!)
ExceptionDomains.remove(context!!, domains) ExceptionDomains.remove(context!!, domains)
launch(Dispatchers.Main) { launch(Main) {
view?.let { view: View -> Navigation.findNavController(view).navigateUp() } view?.let { view -> Navigation.findNavController(view).navigateUp() }
} }
} }
is ExceptionsAction.Delete.One -> launch(Dispatchers.IO) { is ExceptionsAction.Delete.One -> viewLifecycleOwner.lifecycleScope.launch(IO) {
ExceptionDomains.remove(context!!, listOf(it.item.url)) ExceptionDomains.remove(context!!, listOf(it.item.url))
reloadData() reloadData()
} }
@ -93,7 +84,7 @@ class ExceptionsFragment : Fragment(), CoroutineScope {
val items = loadAndMapExceptions() val items = loadAndMapExceptions()
coroutineScope { coroutineScope {
launch(Dispatchers.Main) { launch(Main) {
if (items.isEmpty()) { if (items.isEmpty()) {
view?.let { view: View -> Navigation.findNavController(view).navigateUp() } view?.let { view: View -> Navigation.findNavController(view).navigateUp() }
return@launch return@launch

View File

@ -5,7 +5,6 @@
package org.mozilla.fenix.home package org.mozilla.fenix.home
import android.animation.Animator import android.animation.Animator
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.res.Resources import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
@ -14,12 +13,14 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.NavHostFragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -27,9 +28,7 @@ import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.* import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -79,11 +78,10 @@ import org.mozilla.fenix.onboarding.FenixOnboarding
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.share.ShareTab import org.mozilla.fenix.share.ShareTab
import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.utils.allowUndo
import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt import kotlin.math.roundToInt
@SuppressWarnings("TooManyFunctions", "LargeClass") @SuppressWarnings("TooManyFunctions", "LargeClass")
class HomeFragment : Fragment(), CoroutineScope, AccountObserver { class HomeFragment : Fragment(), AccountObserver {
private val bus = ActionBusFactory.get(this) private val bus = ActionBusFactory.get(this)
private var tabCollectionObserver: Observer<List<TabCollection>>? = null private var tabCollectionObserver: Observer<List<TabCollection>>? = null
@ -110,10 +108,6 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
private val onboarding by lazy { FenixOnboarding(requireContext()) } private val onboarding by lazy { FenixOnboarding(requireContext()) }
private lateinit var sessionControlComponent: SessionControlComponent private lateinit var sessionControlComponent: SessionControlComponent
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// Disabled while awaiting a better solution to #3209 // Disabled while awaiting a better solution to #3209
@ -135,7 +129,6 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
job = Job()
val view = inflater.inflate(R.layout.fragment_home, container, false) val view = inflater.inflate(R.layout.fragment_home, container, false)
val mode = currentMode() val mode = currentMode()
@ -177,7 +170,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
val listener = object : ViewTreeObserver.OnPreDrawListener { val listener = object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean { override fun onPreDraw(): Boolean {
launch { viewLifecycleOwner.lifecycleScope.launch {
delay(ANIM_SCROLL_DELAY) delay(ANIM_SCROLL_DELAY)
restoreLayoutState() restoreLayoutState()
startPostponedEnterTransition() startPostponedEnterTransition()
@ -209,7 +202,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
setupHomeMenu() setupHomeMenu()
launch(Dispatchers.Default) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
val iconSize = resources.getDimension(R.dimen.preference_icon_drawable_size).toInt() val iconSize = resources.getDimension(R.dimen.preference_icon_drawable_size).toInt()
val searchIcon = requireComponents.search.searchEngineManager.getDefaultSearchEngine( val searchIcon = requireComponents.search.searchEngineManager.getDefaultSearchEngine(
@ -274,7 +267,6 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
override fun onDestroyView() { override fun onDestroyView() {
homeMenu = null homeMenu = null
job.cancel()
super.onDestroyView() super.onDestroyView()
} }
@ -359,7 +351,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
removeTabWithUndo(action.sessionId) removeTabWithUndo(action.sessionId)
} else { } else {
pendingSessionDeletion?.deletionJob?.let { pendingSessionDeletion?.deletionJob?.let {
launch { viewLifecycleOwner.lifecycleScope.launch {
it.invoke() it.invoke()
}.invokeOnCompletion { }.invokeOnCompletion {
pendingSessionDeletion = null pendingSessionDeletion = null
@ -379,7 +371,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
sessionManager.filteredSessions(action.private) sessionManager.filteredSessions(action.private)
) else { ) else {
pendingSessionDeletion?.deletionJob?.let { pendingSessionDeletion?.deletionJob?.let {
launch { viewLifecycleOwner.lifecycleScope.launch {
it.invoke() it.invoke()
}.invokeOnCompletion { }.invokeOnCompletion {
pendingSessionDeletion = null pendingSessionDeletion = null
@ -413,7 +405,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
private fun invokePendingDeleteJobs() { private fun invokePendingDeleteJobs() {
pendingSessionDeletion?.deletionJob?.let { pendingSessionDeletion?.deletionJob?.let {
launch { viewLifecycleOwner.lifecycleScope.launch {
it.invoke() it.invoke()
}.invokeOnCompletion { }.invokeOnCompletion {
pendingSessionDeletion = null pendingSessionDeletion = null
@ -421,7 +413,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
deleteAllSessionsJob?.let { deleteAllSessionsJob?.let {
launch { viewLifecycleOwner.lifecycleScope.launch {
it.invoke() it.invoke()
}.invokeOnCompletion { }.invokeOnCompletion {
deleteAllSessionsJob = null deleteAllSessionsJob = null
@ -438,7 +430,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
dialog.cancel() dialog.cancel()
} }
setPositiveButton(R.string.tab_collection_dialog_positive) { dialog: DialogInterface, _ -> setPositiveButton(R.string.tab_collection_dialog_positive) { dialog: DialogInterface, _ ->
launch(Dispatchers.IO) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.removeCollection(tabCollection) requireComponents.core.tabCollectionStorage.removeCollection(tabCollection)
}.invokeOnCompletion { }.invokeOnCompletion {
dialog.dismiss() dialog.dismiss()
@ -517,7 +509,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
) )
} }
} }
launch { viewLifecycleOwner.lifecycleScope.launch {
delay(ANIM_SCROLL_DELAY) delay(ANIM_SCROLL_DELAY)
sessionControlComponent.view.smoothScrollToPosition(0) sessionControlComponent.view.smoothScrollToPosition(0)
} }
@ -527,7 +519,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
share(tabs = shareTabs) share(tabs = shareTabs)
} }
is CollectionAction.RemoveTab -> { is CollectionAction.RemoveTab -> {
launch(Dispatchers.IO) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.removeTabFromCollection(action.collection, action.tab) requireComponents.core.tabCollectionStorage.removeTabFromCollection(action.collection, action.tab)
} }
} }
@ -608,7 +600,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
deleteAllSessionsJob = deleteOperation deleteAllSessionsJob = deleteOperation
allowUndo( viewLifecycleOwner.lifecycleScope.allowUndo(
view!!, view!!,
getString(R.string.snackbar_tabs_deleted), getString(R.string.snackbar_tabs_deleted),
getString(R.string.snackbar_deleted_undo), { getString(R.string.snackbar_deleted_undo), {
@ -631,7 +623,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
pendingSessionDeletion = PendingSessionDeletion(deleteOperation, sessionId) pendingSessionDeletion = PendingSessionDeletion(deleteOperation, sessionId)
allowUndo( viewLifecycleOwner.lifecycleScope.allowUndo(
view!!, view!!,
getString(R.string.snackbar_tab_deleted), getString(R.string.snackbar_tab_deleted),
getString(R.string.snackbar_deleted_undo), { getString(R.string.snackbar_deleted_undo), {
@ -732,7 +724,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
private fun scrollAndAnimateCollection(tabsAddedToCollectionSize: Int, changedCollection: TabCollection? = null) { private fun scrollAndAnimateCollection(tabsAddedToCollectionSize: Int, changedCollection: TabCollection? = null) {
launch { viewLifecycleOwner.lifecycleScope.launch {
val recyclerView = sessionControlComponent.view val recyclerView = sessionControlComponent.view
delay(ANIM_SCROLL_DELAY) delay(ANIM_SCROLL_DELAY)
val tabsSize = getListOfSessions().size val tabsSize = getListOfSessions().size
@ -768,7 +760,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
private fun animateCollection(addedTabsSize: Int, indexOfCollection: Int) { private fun animateCollection(addedTabsSize: Int, indexOfCollection: Int) {
launch { viewLifecycleOwner.lifecycleScope.launch {
val viewHolder = sessionControlComponent.view.findViewHolderForAdapterPosition(indexOfCollection) val viewHolder = sessionControlComponent.view.findViewHolderForAdapterPosition(indexOfCollection)
val border = (viewHolder as? CollectionViewHolder)?.view?.findViewById<View>(R.id.selected_border) val border = (viewHolder as? CollectionViewHolder)?.view?.findViewById<View>(R.id.selected_border)
val listener = object : Animator.AnimatorListener { val listener = object : Animator.AnimatorListener {
@ -815,27 +807,24 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
private fun showSavedSnackbar(tabSize: Int) { private fun showSavedSnackbar(tabSize: Int) {
launch { viewLifecycleOwner.lifecycleScope.launch {
delay(ANIM_SNACKBAR_DELAY) delay(ANIM_SNACKBAR_DELAY)
context?.let { context: Context -> view?.let { view ->
view?.let { view: View -> @StringRes
val string = val stringRes = if (tabSize > 1) {
if (tabSize > 1) context.getString(R.string.create_collection_tabs_saved) else R.string.create_collection_tabs_saved
context.getString(R.string.create_collection_tab_saved) } else {
val snackbar = FenixSnackbar.make(view, Snackbar.LENGTH_LONG).setText(string) R.string.create_collection_tab_saved
snackbar.show()
} }
FenixSnackbar.make(view, Snackbar.LENGTH_LONG).setText(view.context.getString(stringRes)).show()
} }
} }
} }
private fun showRenamedSnackbar() { private fun showRenamedSnackbar() {
context?.let { context: Context -> view?.let { view ->
view?.let { view: View -> val string = view.context.getString(R.string.snackbar_collection_renamed)
val string = context.getString(R.string.snackbar_collection_renamed) FenixSnackbar.make(view, Snackbar.LENGTH_LONG).setText(string).show()
FenixSnackbar.make(view, Snackbar.LENGTH_LONG).setText(string)
.show()
}
} }
} }

View File

@ -21,10 +21,10 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.Navigation import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_bookmark.view.* import kotlinx.android.synthetic.main.fragment_bookmark.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -55,12 +55,10 @@ import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter import org.mozilla.fenix.mvi.getManagedEmitter
import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.utils.allowUndo
import kotlin.coroutines.CoroutineContext
@SuppressWarnings("TooManyFunctions", "LargeClass") @SuppressWarnings("TooManyFunctions", "LargeClass")
class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserver { class BookmarkFragment : Fragment(), BackHandler, AccountObserver {
private lateinit var job: Job
private lateinit var bookmarkComponent: BookmarkComponent private lateinit var bookmarkComponent: BookmarkComponent
private lateinit var signInComponent: SignInComponent private lateinit var signInComponent: SignInComponent
var currentRoot: BookmarkNode? = null var currentRoot: BookmarkNode? = null
@ -74,9 +72,6 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
} }
lateinit var initialJob: Job lateinit var initialJob: Job
override val coroutineContext: CoroutineContext
get() = Main + job
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_bookmark, container, false) val view = inflater.inflate(R.layout.fragment_bookmark, container, false)
bookmarkComponent = BookmarkComponent( bookmarkComponent = BookmarkComponent(
@ -109,7 +104,6 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
job = Job()
activity?.title = getString(R.string.library_bookmarks) activity?.title = getString(R.string.library_bookmarks)
setHasOptionsMenu(true) setHasOptionsMenu(true)
} }
@ -126,11 +120,11 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
} }
private fun loadInitialBookmarkFolder(currentGuid: String): Job { private fun loadInitialBookmarkFolder(currentGuid: String): Job {
return launch(IO) { return lifecycleScope.launch(IO) {
currentRoot = currentRoot =
context?.bookmarkStorage()?.getTree(currentGuid).withOptionalDesktopFolders(context) as BookmarkNode context?.bookmarkStorage()?.getTree(currentGuid).withOptionalDesktopFolders(context) as BookmarkNode
launch(Main) { lifecycleScope.launch(Main) {
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot!!)) getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot!!))
activity?.run { activity?.run {
@ -151,7 +145,6 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
navigation.removeOnDestinationChangedListener(onDestinationChangedListener) navigation.removeOnDestinationChangedListener(onDestinationChangedListener)
job.cancel()
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -260,7 +253,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
getManagedEmitter<BookmarkChange>() getManagedEmitter<BookmarkChange>()
.onNext(BookmarkChange.Change(currentRoot - it.item.guid)) .onNext(BookmarkChange.Change(currentRoot - it.item.guid))
allowUndo( lifecycleScope.allowUndo(
view!!, view!!,
getString( getString(
R.string.bookmark_deletion_snackbar_message, R.string.bookmark_deletion_snackbar_message,
@ -340,7 +333,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
val selectedBookmarks = getSelectedBookmarks() val selectedBookmarks = getSelectedBookmarks()
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot - selectedBookmarks)) getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot - selectedBookmarks))
allowUndo( lifecycleScope.allowUndo(
view!!, getString(R.string.bookmark_deletion_multiple_snackbar_message), view!!, getString(R.string.bookmark_deletion_multiple_snackbar_message),
getString(R.string.bookmark_undo_deletion), { refreshBookmarks() } getString(R.string.bookmark_undo_deletion), { refreshBookmarks() }
) { ) {
@ -359,7 +352,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onAuthenticated(account: OAuthAccount) { override fun onAuthenticated(account: OAuthAccount) {
getManagedEmitter<SignInChange>().onNext(SignInChange.SignedIn) getManagedEmitter<SignInChange>().onNext(SignInChange.SignedIn)
launch { lifecycleScope.launch {
refreshBookmarks() refreshBookmarks()
} }
} }

View File

@ -15,14 +15,12 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_add_bookmark_folder.* import kotlinx.android.synthetic.main.fragment_add_bookmark_folder.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -31,23 +29,14 @@ import org.mozilla.fenix.ext.getColorFromAttr
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel
import kotlin.coroutines.CoroutineContext
class AddBookmarkFolderFragment : Fragment(), CoroutineScope { class AddBookmarkFolderFragment : Fragment() {
private lateinit var sharedViewModel: BookmarksSharedViewModel private val sharedViewModel: BookmarksSharedViewModel by activityViewModels()
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
job = Job()
setHasOptionsMenu(true) setHasOptionsMenu(true)
sharedViewModel = activity?.run {
ViewModelProviders.of(this).get(BookmarksSharedViewModel::class.java)
}!!
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -60,7 +49,7 @@ class AddBookmarkFolderFragment : Fragment(), CoroutineScope {
getString(R.string.bookmark_add_folder_fragment_label) getString(R.string.bookmark_add_folder_fragment_label)
(activity as AppCompatActivity).supportActionBar?.show() (activity as AppCompatActivity).supportActionBar?.show()
launch(IO) { lifecycleScope.launch(IO) {
sharedViewModel.selectedFolder = sharedViewModel.selectedFolder sharedViewModel.selectedFolder = sharedViewModel.selectedFolder
?: requireComponents.core.bookmarksStorage.getTree(BookmarkRoot.Mobile.id) ?: requireComponents.core.bookmarksStorage.getTree(BookmarkRoot.Mobile.id)
launch(Main) { launch(Main) {
@ -79,11 +68,6 @@ class AddBookmarkFolderFragment : Fragment(), CoroutineScope {
} }
} }
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.bookmarks_add_folder, menu) inflater.inflate(R.menu.bookmarks_add_folder, menu)
menu.findItem(R.id.confirm_add_folder_button).icon.colorFilter = menu.findItem(R.id.confirm_add_folder_button).icon.colorFilter =
@ -97,7 +81,7 @@ class AddBookmarkFolderFragment : Fragment(), CoroutineScope {
bookmark_add_folder_title_edit.error = getString(R.string.bookmark_empty_title_error) bookmark_add_folder_title_edit.error = getString(R.string.bookmark_empty_title_error)
return true return true
} }
launch(IO) { lifecycleScope.launch(IO) {
val newGuid = requireComponents.core.bookmarksStorage.addFolder( val newGuid = requireComponents.core.bookmarksStorage.addFolder(
sharedViewModel.selectedFolder!!.guid, bookmark_add_folder_title_edit.text.toString(), null sharedViewModel.selectedFolder!!.guid, bookmark_add_folder_title_edit.text.toString(), null
) )

View File

@ -18,7 +18,8 @@ import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation import androidx.navigation.Navigation
import com.jakewharton.rxbinding3.widget.textChanges import com.jakewharton.rxbinding3.widget.textChanges
import com.uber.autodispose.AutoDispose import com.uber.autodispose.AutoDispose
@ -28,10 +29,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.BiFunction import io.reactivex.functions.BiFunction
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.fragment_edit_bookmark.* import kotlinx.android.synthetic.main.fragment_edit_bookmark.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.appservices.places.UrlParseFailed import mozilla.appservices.places.UrlParseFailed
import mozilla.components.concept.storage.BookmarkInfo import mozilla.components.concept.storage.BookmarkInfo
@ -46,26 +45,17 @@ import org.mozilla.fenix.ext.setRootTitles
import org.mozilla.fenix.ext.withRootTitle import org.mozilla.fenix.ext.withRootTitle
import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.coroutines.CoroutineContext
class EditBookmarkFragment : Fragment(), CoroutineScope { class EditBookmarkFragment : Fragment() {
private lateinit var sharedViewModel: BookmarksSharedViewModel
private lateinit var job: Job
private lateinit var guidToEdit: String private lateinit var guidToEdit: String
private val sharedViewModel: BookmarksSharedViewModel by activityViewModels()
private var bookmarkNode: BookmarkNode? = null private var bookmarkNode: BookmarkNode? = null
private var bookmarkParent: BookmarkNode? = null private var bookmarkParent: BookmarkNode? = null
override val coroutineContext: CoroutineContext
get() = Main + job
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
job = Job()
setHasOptionsMenu(true) setHasOptionsMenu(true)
sharedViewModel = activity?.run {
ViewModelProviders.of(this).get(BookmarksSharedViewModel::class.java)
}!!
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -83,7 +73,7 @@ class EditBookmarkFragment : Fragment(), CoroutineScope {
activity?.supportActionBar?.show() activity?.supportActionBar?.show()
guidToEdit = EditBookmarkFragmentArgs.fromBundle(arguments!!).guidToEdit guidToEdit = EditBookmarkFragmentArgs.fromBundle(arguments!!).guidToEdit
launch(IO) { lifecycleScope.launch(IO) {
bookmarkNode = requireComponents.core.bookmarksStorage.getTree(guidToEdit) bookmarkNode = requireComponents.core.bookmarksStorage.getTree(guidToEdit)
bookmarkParent = sharedViewModel.selectedFolder bookmarkParent = sharedViewModel.selectedFolder
?: bookmarkNode?.parentGuid?.let { ?: bookmarkNode?.parentGuid?.let {
@ -149,11 +139,6 @@ class EditBookmarkFragment : Fragment(), CoroutineScope {
} }
} }
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.bookmarks_edit, menu) inflater.inflate(R.menu.bookmarks_edit, menu)
menu.findItem(R.id.delete_bookmark_button).icon.colorFilter = menu.findItem(R.id.delete_bookmark_button).icon.colorFilter =
@ -178,7 +163,7 @@ class EditBookmarkFragment : Fragment(), CoroutineScope {
dialog.cancel() dialog.cancel()
} }
setPositiveButton(R.string.tab_collection_dialog_positive) { dialog: DialogInterface, _ -> setPositiveButton(R.string.tab_collection_dialog_positive) { dialog: DialogInterface, _ ->
launch(IO) { lifecycleScope.launch(IO) {
requireComponents.core.bookmarksStorage.deleteNode(guidToEdit) requireComponents.core.bookmarksStorage.deleteNode(guidToEdit)
requireComponents.analytics.metrics.track(Event.RemoveBookmark) requireComponents.analytics.metrics.track(Event.RemoveBookmark)
launch(Main) { launch(Main) {
@ -193,7 +178,7 @@ class EditBookmarkFragment : Fragment(), CoroutineScope {
} }
private fun updateBookmarkNode(pair: Pair<String?, String?>) { private fun updateBookmarkNode(pair: Pair<String?, String?>) {
launch(IO) { lifecycleScope.launch(IO) {
try { try {
requireComponents.let { requireComponents.let {
if (pair != Pair(bookmarkNode?.title, bookmarkNode?.url)) { if (pair != Pair(bookmarkNode?.title, bookmarkNode?.url)) {

View File

@ -16,13 +16,12 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.fragment_select_bookmark_folder.* import kotlinx.android.synthetic.main.fragment_select_bookmark_folder.*
import kotlinx.android.synthetic.main.fragment_select_bookmark_folder.view.* import kotlinx.android.synthetic.main.fragment_select_bookmark_folder.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot
import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNode
@ -47,21 +46,16 @@ import org.mozilla.fenix.library.bookmarks.SignInViewModel
import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter import org.mozilla.fenix.mvi.getManagedEmitter
import kotlin.coroutines.CoroutineContext
@SuppressWarnings("TooManyFunctions") @SuppressWarnings("TooManyFunctions")
class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver { class SelectBookmarkFolderFragment : Fragment(), AccountObserver {
private lateinit var sharedViewModel: BookmarksSharedViewModel private val sharedViewModel: BookmarksSharedViewModel by activityViewModels()
private lateinit var job: Job
private var folderGuid: String? = null private var folderGuid: String? = null
private var bookmarkNode: BookmarkNode? = null private var bookmarkNode: BookmarkNode? = null
private lateinit var signInComponent: SignInComponent private lateinit var signInComponent: SignInComponent
override val coroutineContext: CoroutineContext
get() = Main + job
// Fill out our title map once we have context. // Fill out our title map once we have context.
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
@ -70,11 +64,7 @@ class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
job = Job()
setHasOptionsMenu(true) setHasOptionsMenu(true)
sharedViewModel = activity?.run {
ViewModelProviders.of(this).get(BookmarksSharedViewModel::class.java)
}!!
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -116,7 +106,7 @@ class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver
folderGuid = SelectBookmarkFolderFragmentArgs.fromBundle(arguments!!).folderGuid ?: BookmarkRoot.Root.id folderGuid = SelectBookmarkFolderFragmentArgs.fromBundle(arguments!!).folderGuid ?: BookmarkRoot.Root.id
checkIfSignedIn() checkIfSignedIn()
launch(IO) { lifecycleScope.launch(IO) {
bookmarkNode = bookmarkNode =
requireComponents.core.bookmarksStorage.getTree(BookmarkRoot.Root.id, true) requireComponents.core.bookmarksStorage.getTree(BookmarkRoot.Root.id, true)
.withOptionalDesktopFolders(context, showMobileRoot = true) .withOptionalDesktopFolders(context, showMobileRoot = true)
@ -136,11 +126,6 @@ class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver
?: getManagedEmitter<SignInChange>().onNext(SignInChange.SignedOut) ?: getManagedEmitter<SignInChange>().onNext(SignInChange.SignedOut)
} }
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
val visitedAddBookmark = SelectBookmarkFolderFragmentArgs.fromBundle(arguments!!).visitedAddBookmark val visitedAddBookmark = SelectBookmarkFolderFragmentArgs.fromBundle(arguments!!).visitedAddBookmark
if (!visitedAddBookmark) { if (!visitedAddBookmark) {
@ -153,7 +138,7 @@ class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.add_folder_button -> { R.id.add_folder_button -> {
launch(Main) { lifecycleScope.launch(Main) {
nav( nav(
R.id.bookmarkSelectFolderFragment, R.id.bookmarkSelectFolderFragment,
SelectBookmarkFolderFragmentDirections SelectBookmarkFolderFragmentDirections

View File

@ -18,14 +18,11 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_history.view.* import kotlinx.android.synthetic.main.fragment_history.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mozilla.components.concept.storage.VisitType import mozilla.components.concept.storage.VisitType
@ -47,7 +44,7 @@ import org.mozilla.fenix.share.ShareTab
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@SuppressWarnings("TooManyFunctions") @SuppressWarnings("TooManyFunctions")
class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler { class HistoryFragment : Fragment(), BackHandler {
private lateinit var historyComponent: HistoryComponent private lateinit var historyComponent: HistoryComponent
private val navigation by lazy { Navigation.findNavController(requireView()) } private val navigation by lazy { Navigation.findNavController(requireView()) }
@ -78,7 +75,7 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
launch { reloadData() } lifecycleScope.launch { reloadData() }
} }
override fun onStart() { override fun onStart() {
@ -95,11 +92,6 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
} }
} }
override fun onDestroy() {
coroutineContext.cancel()
super.onDestroy()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
val mode = (historyComponent.uiView as HistoryUIView).mode val mode = (historyComponent.uiView as HistoryUIView).mode
when (mode) { when (mode) {
@ -144,7 +136,7 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
val components = context?.applicationContext?.components!! val components = context?.applicationContext?.components!!
val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected() val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected()
GlobalScope.launch(Main) { lifecycleScope.launch(Main) {
deleteSelectedHistory(selectedHistory, components) deleteSelectedHistory(selectedHistory, components)
reloadData() reloadData()
} }
@ -200,13 +192,13 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
emitChange { HistoryChange.ExitEditMode } emitChange { HistoryChange.ExitEditMode }
is HistoryAction.Delete.All -> is HistoryAction.Delete.All ->
displayDeleteAllDialog() displayDeleteAllDialog()
is HistoryAction.Delete.One -> launch { is HistoryAction.Delete.One -> lifecycleScope.launch {
requireComponents.core requireComponents.core
.historyStorage .historyStorage
.deleteVisit(action.item.url, action.item.visitedAt) .deleteVisit(action.item.url, action.item.visitedAt)
reloadData() reloadData()
} }
is HistoryAction.Delete.Some -> launch { is HistoryAction.Delete.Some -> lifecycleScope.launch {
val storage = requireComponents.core.historyStorage val storage = requireComponents.core.historyStorage
for (item in action.items) { for (item in action.items) {
storage.deleteVisit(item.url, item.visitedAt) storage.deleteVisit(item.url, item.visitedAt)
@ -235,7 +227,7 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
} }
setPositiveButton(R.string.history_clear_dialog) { dialog: DialogInterface, _ -> setPositiveButton(R.string.history_clear_dialog) { dialog: DialogInterface, _ ->
emitChange { HistoryChange.EnterDeletionMode } emitChange { HistoryChange.EnterDeletionMode }
launch { lifecycleScope.launch {
requireComponents.core.historyStorage.deleteEverything() requireComponents.core.historyStorage.deleteEverything()
reloadData() reloadData()
launch(Dispatchers.Main) { launch(Dispatchers.Main) {

View File

@ -26,15 +26,13 @@ internal const val UNDO_DELAY = 3000L
* @param onCancel A suspend block to execute in case of cancellation. * @param onCancel A suspend block to execute in case of cancellation.
* @param operation A suspend block to execute if user doesn't cancel via the displayed [FenixSnackbar]. * @param operation A suspend block to execute if user doesn't cancel via the displayed [FenixSnackbar].
*/ */
fun allowUndo( fun CoroutineScope.allowUndo(
view: View, view: View,
message: String, message: String,
undoActionTitle: String, undoActionTitle: String,
onCancel: suspend () -> Unit = {}, onCancel: suspend () -> Unit = {},
operation: suspend () -> Unit operation: suspend () -> Unit
) { ) {
val mainScope = CoroutineScope(Dispatchers.Main)
// By using an AtomicBoolean, we achieve memory effects of reading and // By using an AtomicBoolean, we achieve memory effects of reading and
// writing a volatile variable. // writing a volatile variable.
val requestedUndo = AtomicBoolean(false) val requestedUndo = AtomicBoolean(false)
@ -45,7 +43,7 @@ fun allowUndo(
.setText(message) .setText(message)
.setAction(undoActionTitle) { .setAction(undoActionTitle) {
requestedUndo.set(true) requestedUndo.set(true)
mainScope.launch { launch {
onCancel.invoke() onCancel.invoke()
} }
} }
@ -55,7 +53,7 @@ fun allowUndo(
// Wait a bit, and if user didn't request cancellation, proceed with // Wait a bit, and if user didn't request cancellation, proceed with
// requested operation and hide the snackbar. // requested operation and hide the snackbar.
mainScope.launch { launch {
delay(UNDO_DELAY) delay(UNDO_DELAY)
if (!requestedUndo.get()) { if (!requestedUndo.get()) {

View File

@ -141,14 +141,14 @@ object Deps {
const val leanplum = "com.leanplum:leanplum-core:${Versions.leanplum}" const val leanplum = "com.leanplum:leanplum-core:${Versions.leanplum}"
const val androidx_annotation = "androidx.annotation:annotation:${Versions.androidx_annotation}" const val androidx_annotation = "androidx.annotation:annotation:${Versions.androidx_annotation}"
const val androidx_fragment = "androidx.fragment:fragment:${Versions.androidx_fragment}" const val androidx_fragment = "androidx.fragment:fragment-ktx:${Versions.androidx_fragment}"
const val androidx_appcompat = "androidx.appcompat:appcompat:${Versions.androidx_appcompat}" const val androidx_appcompat = "androidx.appcompat:appcompat:${Versions.androidx_appcompat}"
const val androidx_coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:${Versions.androidx_coordinator_layout}" const val androidx_coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:${Versions.androidx_coordinator_layout}"
const val androidx_constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.androidx_constraint_layout}" const val androidx_constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.androidx_constraint_layout}"
const val androidx_legacy = "androidx.legacy:legacy-support-v4:${Versions.androidx_legacy}" const val androidx_legacy = "androidx.legacy:legacy-support-v4:${Versions.androidx_legacy}"
const val androidx_lifecycle_extensions = "androidx.lifecycle:lifecycle-extensions:${Versions.androidx_lifecycle}" const val androidx_lifecycle_extensions = "androidx.lifecycle:lifecycle-extensions:${Versions.androidx_lifecycle}"
const val androidx_lifecycle_viewmodel_ktx = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.androidx_lifecycle}" const val androidx_lifecycle_viewmodel = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.androidx_lifecycle}"
const val androidx_lifecycle_runtime = "androidx.lifecycle:lifecycle-runtime:${Versions.androidx_lifecycle}" const val androidx_lifecycle_runtime = "androidx.lifecycle:lifecycle-runtime-ktx:${Versions.androidx_lifecycle}"
const val androidx_lifecycle_viewmodel_ss = "androidx.lifecycle:lifecycle-viewmodel-savedstate:${Versions.androidx_lifecycle_savedstate}" const val androidx_lifecycle_viewmodel_ss = "androidx.lifecycle:lifecycle-viewmodel-savedstate:${Versions.androidx_lifecycle_savedstate}"
const val androidx_preference = "androidx.preference:preference-ktx:${Versions.androidx_preference}" const val androidx_preference = "androidx.preference:preference-ktx:${Versions.androidx_preference}"
const val androidx_safeargs = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.androidx_navigation}" const val androidx_safeargs = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.androidx_navigation}"