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_ui
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_core
implementation Deps.androidx_core_ktx

View File

@ -23,14 +23,13 @@ import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.NavHostFragment.findNavController
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.component_search.*
import kotlinx.android.synthetic.main.fragment_browser.*
import kotlinx.android.synthetic.main.fragment_browser.view.*
import kotlinx.android.synthetic.main.fragment_search.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
@ -100,10 +99,9 @@ import org.mozilla.fenix.utils.ItsNotBrokenSnack
import org.mozilla.fenix.utils.Settings
import java.net.MalformedURLException
import java.net.URL
import kotlin.coroutines.CoroutineContext
@SuppressWarnings("TooManyFunctions", "LargeClass")
class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
class BrowserFragment : Fragment(), BackHandler {
private lateinit var toolbarComponent: ToolbarComponent
@ -125,12 +123,9 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
private val customTabsIntegration = ViewBoundFeatureWrapper<CustomTabsIntegration>()
private var findBookmarkJob: Job? = null
private lateinit var job: Job
var customTabSessionId: String? = null
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 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(
// SHARED_TRANSITION_MS
// )
job = Job()
}
@SuppressWarnings("ComplexMethod")
@ -564,9 +558,9 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private fun bookmarkTapped() {
getSessionById()?.let { session ->
CoroutineScope(IO).launch {
val components = requireComponents
val existing = components.core.bookmarksStorage.getBookmarksWithUrl(session.url)
lifecycleScope.launch(IO) {
val bookmarksStorage = requireComponents.core.bookmarksStorage
val existing = bookmarksStorage.getBookmarksWithUrl(session.url)
val found = existing.isNotEmpty() && existing[0].url == session.url
if (found) {
launch(Main) {
@ -577,13 +571,12 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
)
}
} else {
val guid = components.core.bookmarksStorage
.addItem(
BookmarkRoot.Mobile.id,
session.url,
session.title,
null
)
val guid = bookmarksStorage.addItem(
BookmarkRoot.Mobile.id,
session.url,
session.title,
null
)
launch(Main) {
getManagedEmitter<QuickActionChange>()
.onNext(QuickActionChange.BookmarkedStateChange(true))
@ -685,11 +678,6 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
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.
@SuppressWarnings("ComplexMethod")
private fun trackToolbarItemInteraction(action: SearchAction.ToolbarMenuItemTapped) {
@ -824,8 +812,8 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private fun showQuickSettingsDialog() {
val session = getSessionById() ?: return
launch {
val host = session.url.toUri()?.host
lifecycleScope.launch(IO) {
val host = session.url.toUri().host
val sitePermissions: SitePermissions? = host?.let {
val storage = requireContext().components.core.permissionStorage
storage.findSitePermissionsBy(it)
@ -923,7 +911,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private fun updateBookmarkState(session: Session) {
if (findBookmarkJob?.isActive == true) findBookmarkJob?.cancel()
findBookmarkJob = launch {
findBookmarkJob = lifecycleScope.launch(IO) {
val found = findBookmarkedURL(session)
launch(Main) {
getManagedEmitter<QuickActionChange>()

View File

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

View File

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

View File

@ -5,7 +5,6 @@
package org.mozilla.fenix.home
import android.animation.Animator
import android.content.Context
import android.content.DialogInterface
import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable
@ -14,12 +13,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.NavHostFragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
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 kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@ -79,11 +78,10 @@ import org.mozilla.fenix.onboarding.FenixOnboarding
import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.share.ShareTab
import org.mozilla.fenix.utils.allowUndo
import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt
@SuppressWarnings("TooManyFunctions", "LargeClass")
class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
class HomeFragment : Fragment(), AccountObserver {
private val bus = ActionBusFactory.get(this)
private var tabCollectionObserver: Observer<List<TabCollection>>? = null
@ -110,10 +108,6 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
private val onboarding by lazy { FenixOnboarding(requireContext()) }
private lateinit var sessionControlComponent: SessionControlComponent
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Disabled while awaiting a better solution to #3209
@ -135,7 +129,6 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
job = Job()
val view = inflater.inflate(R.layout.fragment_home, container, false)
val mode = currentMode()
@ -177,7 +170,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
val listener = object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
launch {
viewLifecycleOwner.lifecycleScope.launch {
delay(ANIM_SCROLL_DELAY)
restoreLayoutState()
startPostponedEnterTransition()
@ -209,7 +202,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
setupHomeMenu()
launch(Dispatchers.Default) {
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
val iconSize = resources.getDimension(R.dimen.preference_icon_drawable_size).toInt()
val searchIcon = requireComponents.search.searchEngineManager.getDefaultSearchEngine(
@ -274,7 +267,6 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
override fun onDestroyView() {
homeMenu = null
job.cancel()
super.onDestroyView()
}
@ -359,7 +351,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
removeTabWithUndo(action.sessionId)
} else {
pendingSessionDeletion?.deletionJob?.let {
launch {
viewLifecycleOwner.lifecycleScope.launch {
it.invoke()
}.invokeOnCompletion {
pendingSessionDeletion = null
@ -379,7 +371,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
sessionManager.filteredSessions(action.private)
) else {
pendingSessionDeletion?.deletionJob?.let {
launch {
viewLifecycleOwner.lifecycleScope.launch {
it.invoke()
}.invokeOnCompletion {
pendingSessionDeletion = null
@ -413,7 +405,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
private fun invokePendingDeleteJobs() {
pendingSessionDeletion?.deletionJob?.let {
launch {
viewLifecycleOwner.lifecycleScope.launch {
it.invoke()
}.invokeOnCompletion {
pendingSessionDeletion = null
@ -421,7 +413,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
}
deleteAllSessionsJob?.let {
launch {
viewLifecycleOwner.lifecycleScope.launch {
it.invoke()
}.invokeOnCompletion {
deleteAllSessionsJob = null
@ -438,7 +430,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
dialog.cancel()
}
setPositiveButton(R.string.tab_collection_dialog_positive) { dialog: DialogInterface, _ ->
launch(Dispatchers.IO) {
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.removeCollection(tabCollection)
}.invokeOnCompletion {
dialog.dismiss()
@ -517,7 +509,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
)
}
}
launch {
viewLifecycleOwner.lifecycleScope.launch {
delay(ANIM_SCROLL_DELAY)
sessionControlComponent.view.smoothScrollToPosition(0)
}
@ -527,7 +519,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
share(tabs = shareTabs)
}
is CollectionAction.RemoveTab -> {
launch(Dispatchers.IO) {
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.removeTabFromCollection(action.collection, action.tab)
}
}
@ -608,7 +600,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
}
deleteAllSessionsJob = deleteOperation
allowUndo(
viewLifecycleOwner.lifecycleScope.allowUndo(
view!!,
getString(R.string.snackbar_tabs_deleted),
getString(R.string.snackbar_deleted_undo), {
@ -631,7 +623,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
pendingSessionDeletion = PendingSessionDeletion(deleteOperation, sessionId)
allowUndo(
viewLifecycleOwner.lifecycleScope.allowUndo(
view!!,
getString(R.string.snackbar_tab_deleted),
getString(R.string.snackbar_deleted_undo), {
@ -732,7 +724,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
}
private fun scrollAndAnimateCollection(tabsAddedToCollectionSize: Int, changedCollection: TabCollection? = null) {
launch {
viewLifecycleOwner.lifecycleScope.launch {
val recyclerView = sessionControlComponent.view
delay(ANIM_SCROLL_DELAY)
val tabsSize = getListOfSessions().size
@ -768,7 +760,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
}
private fun animateCollection(addedTabsSize: Int, indexOfCollection: Int) {
launch {
viewLifecycleOwner.lifecycleScope.launch {
val viewHolder = sessionControlComponent.view.findViewHolderForAdapterPosition(indexOfCollection)
val border = (viewHolder as? CollectionViewHolder)?.view?.findViewById<View>(R.id.selected_border)
val listener = object : Animator.AnimatorListener {
@ -815,27 +807,24 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
}
private fun showSavedSnackbar(tabSize: Int) {
launch {
viewLifecycleOwner.lifecycleScope.launch {
delay(ANIM_SNACKBAR_DELAY)
context?.let { context: Context ->
view?.let { view: View ->
val string =
if (tabSize > 1) context.getString(R.string.create_collection_tabs_saved) else
context.getString(R.string.create_collection_tab_saved)
val snackbar = FenixSnackbar.make(view, Snackbar.LENGTH_LONG).setText(string)
snackbar.show()
view?.let { view ->
@StringRes
val stringRes = if (tabSize > 1) {
R.string.create_collection_tabs_saved
} else {
R.string.create_collection_tab_saved
}
FenixSnackbar.make(view, Snackbar.LENGTH_LONG).setText(view.context.getString(stringRes)).show()
}
}
}
private fun showRenamedSnackbar() {
context?.let { context: Context ->
view?.let { view: View ->
val string = context.getString(R.string.snackbar_collection_renamed)
FenixSnackbar.make(view, Snackbar.LENGTH_LONG).setText(string)
.show()
}
view?.let { view ->
val string = view.context.getString(R.string.snackbar_collection_renamed)
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.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_bookmark.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
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.getManagedEmitter
import org.mozilla.fenix.utils.allowUndo
import kotlin.coroutines.CoroutineContext
@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 signInComponent: SignInComponent
var currentRoot: BookmarkNode? = null
@ -74,9 +72,6 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
}
lateinit var initialJob: Job
override val coroutineContext: CoroutineContext
get() = Main + job
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_bookmark, container, false)
bookmarkComponent = BookmarkComponent(
@ -109,7 +104,6 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
activity?.title = getString(R.string.library_bookmarks)
setHasOptionsMenu(true)
}
@ -126,11 +120,11 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
}
private fun loadInitialBookmarkFolder(currentGuid: String): Job {
return launch(IO) {
return lifecycleScope.launch(IO) {
currentRoot =
context?.bookmarkStorage()?.getTree(currentGuid).withOptionalDesktopFolders(context) as BookmarkNode
launch(Main) {
lifecycleScope.launch(Main) {
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot!!))
activity?.run {
@ -151,7 +145,6 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onDestroy() {
super.onDestroy()
navigation.removeOnDestinationChangedListener(onDestinationChangedListener)
job.cancel()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -260,7 +253,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
getManagedEmitter<BookmarkChange>()
.onNext(BookmarkChange.Change(currentRoot - it.item.guid))
allowUndo(
lifecycleScope.allowUndo(
view!!,
getString(
R.string.bookmark_deletion_snackbar_message,
@ -340,7 +333,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
val selectedBookmarks = getSelectedBookmarks()
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot - selectedBookmarks))
allowUndo(
lifecycleScope.allowUndo(
view!!, getString(R.string.bookmark_deletion_multiple_snackbar_message),
getString(R.string.bookmark_undo_deletion), { refreshBookmarks() }
) {
@ -359,7 +352,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onAuthenticated(account: OAuthAccount) {
getManagedEmitter<SignInChange>().onNext(SignInChange.SignedIn)
launch {
lifecycleScope.launch {
refreshBookmarks()
}
}

View File

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

View File

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

View File

@ -18,14 +18,11 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_history.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.components.concept.storage.VisitType
@ -47,7 +44,7 @@ import org.mozilla.fenix.share.ShareTab
import java.util.concurrent.TimeUnit
@SuppressWarnings("TooManyFunctions")
class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
class HistoryFragment : Fragment(), BackHandler {
private lateinit var historyComponent: HistoryComponent
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?) {
super.onViewCreated(view, savedInstanceState)
launch { reloadData() }
lifecycleScope.launch { reloadData() }
}
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) {
val mode = (historyComponent.uiView as HistoryUIView).mode
when (mode) {
@ -144,7 +136,7 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
val components = context?.applicationContext?.components!!
val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected()
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
deleteSelectedHistory(selectedHistory, components)
reloadData()
}
@ -200,13 +192,13 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
emitChange { HistoryChange.ExitEditMode }
is HistoryAction.Delete.All ->
displayDeleteAllDialog()
is HistoryAction.Delete.One -> launch {
is HistoryAction.Delete.One -> lifecycleScope.launch {
requireComponents.core
.historyStorage
.deleteVisit(action.item.url, action.item.visitedAt)
reloadData()
}
is HistoryAction.Delete.Some -> launch {
is HistoryAction.Delete.Some -> lifecycleScope.launch {
val storage = requireComponents.core.historyStorage
for (item in action.items) {
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, _ ->
emitChange { HistoryChange.EnterDeletionMode }
launch {
lifecycleScope.launch {
requireComponents.core.historyStorage.deleteEverything()
reloadData()
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 operation A suspend block to execute if user doesn't cancel via the displayed [FenixSnackbar].
*/
fun allowUndo(
fun CoroutineScope.allowUndo(
view: View,
message: String,
undoActionTitle: String,
onCancel: suspend () -> Unit = {},
operation: suspend () -> Unit
) {
val mainScope = CoroutineScope(Dispatchers.Main)
// By using an AtomicBoolean, we achieve memory effects of reading and
// writing a volatile variable.
val requestedUndo = AtomicBoolean(false)
@ -45,7 +43,7 @@ fun allowUndo(
.setText(message)
.setAction(undoActionTitle) {
requestedUndo.set(true)
mainScope.launch {
launch {
onCancel.invoke()
}
}
@ -55,7 +53,7 @@ fun allowUndo(
// Wait a bit, and if user didn't request cancellation, proceed with
// requested operation and hide the snackbar.
mainScope.launch {
launch {
delay(UNDO_DELAY)
if (!requestedUndo.get()) {

View File

@ -141,14 +141,14 @@ object Deps {
const val leanplum = "com.leanplum:leanplum-core:${Versions.leanplum}"
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_coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:${Versions.androidx_coordinator_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_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_runtime = "androidx.lifecycle:lifecycle-runtime:${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-ktx:${Versions.androidx_lifecycle}"
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_safeargs = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.androidx_navigation}"