1
0
Fork 0

For #3238: fixes race condition crash, nav destination unknown

master
Colin Lee 2019-06-06 14:40:10 -05:00 committed by Emily Kager
parent 0a3b001abe
commit 1e6da54263
15 changed files with 248 additions and 110 deletions

View File

@ -9,6 +9,7 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
@ -29,6 +30,7 @@ import mozilla.components.support.ktx.kotlin.toNormalizedUrl
import mozilla.components.support.utils.SafeIntent import mozilla.components.support.utils.SafeIntent
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.home.HomeFragmentDirections import org.mozilla.fenix.home.HomeFragmentDirections
import org.mozilla.fenix.library.bookmarks.BookmarkFragmentDirections import org.mozilla.fenix.library.bookmarks.BookmarkFragmentDirections
import org.mozilla.fenix.library.bookmarks.selectfolder.SelectBookmarkFolderFragmentDirections import org.mozilla.fenix.library.bookmarks.selectfolder.SelectBookmarkFolderFragmentDirections
@ -56,10 +58,12 @@ open class HomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
browsingModeManager = createBrowsingModeManager() browsingModeManager = createBrowsingModeManager()
themeManager = createThemeManager(when (browsingModeManager.isPrivate) { themeManager = createThemeManager(
true -> ThemeManager.Theme.Private when (browsingModeManager.isPrivate) {
false -> ThemeManager.Theme.Normal true -> ThemeManager.Theme.Private
}) false -> ThemeManager.Theme.Normal
}
)
setTheme(themeManager.currentTheme) setTheme(themeManager.currentTheme)
ThemeManager.applyStatusBarTheme(window, themeManager, this) ThemeManager.applyStatusBarTheme(window, themeManager, this)
@ -183,35 +187,55 @@ open class HomeActivity : AppCompatActivity() {
sessionObserver = subscribeToSessions() sessionObserver = subscribeToSessions()
if (navHost.navController.currentDestination?.id == R.id.browserFragment) return if (navHost.navController.currentDestination?.id == R.id.browserFragment) return
@IdRes var fragmentId: Int? = null
val directions = if (!navHost.navController.popBackStack(R.id.browserFragment, false)) { val directions = if (!navHost.navController.popBackStack(R.id.browserFragment, false)) {
when (from) { when (from) {
BrowserDirection.FromGlobal -> NavGraphDirections.actionGlobalBrowser(customTabSessionId) BrowserDirection.FromGlobal ->
BrowserDirection.FromHome -> NavGraphDirections.actionGlobalBrowser(customTabSessionId)
BrowserDirection.FromHome -> {
fragmentId = R.id.homeFragment
HomeFragmentDirections.actionHomeFragmentToBrowserFragment(customTabSessionId) HomeFragmentDirections.actionHomeFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromSearch -> }
BrowserDirection.FromSearch -> {
fragmentId = R.id.searchFragment
SearchFragmentDirections.actionSearchFragmentToBrowserFragment(customTabSessionId) SearchFragmentDirections.actionSearchFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromSettings -> }
BrowserDirection.FromSettings -> {
fragmentId = R.id.settingsFragment
SettingsFragmentDirections.actionSettingsFragmentToBrowserFragment(customTabSessionId) SettingsFragmentDirections.actionSettingsFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromBookmarks -> }
BrowserDirection.FromBookmarks -> {
fragmentId = R.id.bookmarkFragment
BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment(customTabSessionId) BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromBookmarksFolderSelect -> }
BrowserDirection.FromBookmarksFolderSelect -> {
fragmentId = R.id.bookmarkSelectFolderFragment
SelectBookmarkFolderFragmentDirections SelectBookmarkFolderFragmentDirections
.actionBookmarkSelectFolderFragmentToBrowserFragment(customTabSessionId) .actionBookmarkSelectFolderFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromHistory -> }
BrowserDirection.FromHistory -> {
fragmentId = R.id.historyFragment
HistoryFragmentDirections.actionHistoryFragmentToBrowserFragment(customTabSessionId) HistoryFragmentDirections.actionHistoryFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromPair -> }
BrowserDirection.FromPair -> {
fragmentId = R.id.pairFragment
PairFragmentDirections.actionPairFragmentToBrowserFragment(customTabSessionId) PairFragmentDirections.actionPairFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromTurnOnSync -> }
BrowserDirection.FromTurnOnSync -> {
fragmentId = R.id.turnOnSyncFragment
TurnOnSyncFragmentDirections.actionTurnOnSyncFragmentToBrowserFragment(customTabSessionId) TurnOnSyncFragmentDirections.actionTurnOnSyncFragmentToBrowserFragment(customTabSessionId)
BrowserDirection.FromAccountProblem -> }
BrowserDirection.FromAccountProblem -> {
fragmentId = R.id.turnOnSyncFragment
AccountProblemFragmentDirections.actionAccountProblemFragmentToBrowserFragment(customTabSessionId) AccountProblemFragmentDirections.actionAccountProblemFragmentToBrowserFragment(customTabSessionId)
}
} }
} else { } else {
null null
} }
directions?.let { directions?.let {
navHost.navController.navigate(it) navHost.navController.nav(fragmentId, it)
} }
} }
@ -265,10 +289,12 @@ open class HomeActivity : AppCompatActivity() {
CustomTabBrowsingModeManager() CustomTabBrowsingModeManager()
} else { } else {
DefaultBrowsingModeManager(Settings.getInstance(this).createBrowserModeStorage()) { DefaultBrowsingModeManager(Settings.getInstance(this).createBrowserModeStorage()) {
themeManager.setTheme(when (it.isPrivate()) { themeManager.setTheme(
true -> ThemeManager.Theme.Private when (it.isPrivate()) {
false -> ThemeManager.Theme.Normal true -> ThemeManager.Theme.Private
}) false -> ThemeManager.Theme.Normal
}
)
} }
} }
} }

View File

@ -17,7 +17,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.navigation.Navigation
import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.NavHostFragment.findNavController
import androidx.transition.TransitionInflater import androidx.transition.TransitionInflater
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@ -78,6 +77,7 @@ import org.mozilla.fenix.components.toolbar.ToolbarUIView
import org.mozilla.fenix.components.toolbar.ToolbarViewModel import org.mozilla.fenix.components.toolbar.ToolbarViewModel
import org.mozilla.fenix.customtabs.CustomTabsIntegration import org.mozilla.fenix.customtabs.CustomTabsIntegration
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.urlToTrimmedHost import org.mozilla.fenix.ext.urlToTrimmedHost
import org.mozilla.fenix.home.sessioncontrol.Tab import org.mozilla.fenix.home.sessioncontrol.Tab
@ -443,13 +443,12 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
.subscribe { .subscribe {
when (it) { when (it) {
is SearchAction.ToolbarClicked -> { is SearchAction.ToolbarClicked -> {
Navigation nav(
.findNavController(toolbarComponent.getView()) R.id.browserFragment,
.navigate( BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(
BrowserFragmentDirections.actionBrowserFragmentToSearchFragment( getSessionById()?.id
getSessionById()?.id
)
) )
)
requireComponents.analytics.metrics.track( requireComponents.analytics.metrics.track(
Event.SearchBarTapped(Event.SearchBarTapped.Source.BROWSER) Event.SearchBarTapped(Event.SearchBarTapped.Source.BROWSER)
@ -533,11 +532,11 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
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) {
Navigation.findNavController(requireActivity(), R.id.container) nav(
.navigate( R.id.browserFragment,
BrowserFragmentDirections BrowserFragmentDirections
.actionBrowserFragmentToBookmarkEditFragment(existing[0].guid) .actionBrowserFragmentToBookmarkEditFragment(existing[0].guid)
) )
} }
} else { } else {
val guid = components.core.bookmarksStorage val guid = components.core.bookmarksStorage
@ -558,16 +557,13 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
) )
.setAnchorView(toolbarComponent.uiView.view) .setAnchorView(toolbarComponent.uiView.view)
.setAction(getString(R.string.edit_bookmark_snackbar_action)) { .setAction(getString(R.string.edit_bookmark_snackbar_action)) {
Navigation.findNavController( nav(
requireActivity(), R.id.browserFragment,
R.id.container BrowserFragmentDirections
.actionBrowserFragmentToBookmarkEditFragment(
guid
)
) )
.navigate(
BrowserFragmentDirections
.actionBrowserFragmentToBookmarkEditFragment(
guid
)
)
} }
.setText(getString(R.string.bookmark_saved_snackbar)) .setText(getString(R.string.bookmark_saved_snackbar))
.show() .show()
@ -687,10 +683,14 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
ToolbarMenu.Item.Forward -> sessionUseCases.goForward.invoke(getSessionById()) ToolbarMenu.Item.Forward -> sessionUseCases.goForward.invoke(getSessionById())
ToolbarMenu.Item.Reload -> sessionUseCases.reload.invoke(getSessionById()) ToolbarMenu.Item.Reload -> sessionUseCases.reload.invoke(getSessionById())
ToolbarMenu.Item.Stop -> sessionUseCases.stopLoading.invoke(getSessionById()) ToolbarMenu.Item.Stop -> sessionUseCases.stopLoading.invoke(getSessionById())
ToolbarMenu.Item.Settings -> Navigation.findNavController(toolbarComponent.getView()) ToolbarMenu.Item.Settings -> nav(
.navigate(BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()) R.id.browserFragment,
ToolbarMenu.Item.Library -> Navigation.findNavController(toolbarComponent.getView()) BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()
.navigate(BrowserFragmentDirections.actionBrowserFragmentToLibraryFragment()) )
ToolbarMenu.Item.Library -> nav(
R.id.browserFragment,
BrowserFragmentDirections.actionBrowserFragmentToLibraryFragment()
)
is ToolbarMenu.Item.RequestDesktop -> sessionUseCases.requestDesktopSite.invoke(action.item.isChecked) is ToolbarMenu.Item.RequestDesktop -> sessionUseCases.requestDesktopSite.invoke(action.item.isChecked)
ToolbarMenu.Item.Share -> getSessionById()?.let { session -> ToolbarMenu.Item.Share -> getSessionById()?.let { session ->
session.url.apply { session.url.apply {
@ -700,7 +700,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
ToolbarMenu.Item.NewPrivateTab -> { ToolbarMenu.Item.NewPrivateTab -> {
val directions = BrowserFragmentDirections val directions = BrowserFragmentDirections
.actionBrowserFragmentToSearchFragment(null) .actionBrowserFragmentToSearchFragment(null)
Navigation.findNavController(view!!).navigate(directions) nav(R.id.browserFragment, directions)
(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private (activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private
} }
ToolbarMenu.Item.FindInPage -> { ToolbarMenu.Item.FindInPage -> {
@ -724,7 +724,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
ToolbarMenu.Item.NewTab -> { ToolbarMenu.Item.NewTab -> {
val directions = BrowserFragmentDirections val directions = BrowserFragmentDirections
.actionBrowserFragmentToSearchFragment(null) .actionBrowserFragmentToSearchFragment(null)
Navigation.findNavController(view!!).navigate(directions) nav(R.id.browserFragment, directions)
(activity as HomeActivity).browsingModeManager.mode = (activity as HomeActivity).browsingModeManager.mode =
BrowsingModeManager.Mode.Normal BrowsingModeManager.Mode.Normal
} }
@ -759,7 +759,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
viewModel?.snackbarAnchorView = nestedScrollQuickAction viewModel?.snackbarAnchorView = nestedScrollQuickAction
view?.let { view?.let {
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment() val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment()
Navigation.findNavController(it).navigate(directions) nav(R.id.browserFragment, directions)
} }
} }
} }
@ -793,7 +793,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
sitePermissions = sitePermissions, sitePermissions = sitePermissions,
gravity = getAppropriateLayoutGravity() gravity = getAppropriateLayoutGravity()
) )
Navigation.findNavController(it).navigate(directions) nav(R.id.browserFragment, directions)
} }
} }
} }
@ -876,7 +876,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
private fun shareUrl(url: String) { private fun shareUrl(url: String) {
val directions = BrowserFragmentDirections.actionBrowserFragmentToShareFragment(url) val directions = BrowserFragmentDirections.actionBrowserFragmentToShareFragment(url)
Navigation.findNavController(view!!).navigate(directions) nav(R.id.browserFragment, directions)
} }
companion object { companion object {

View File

@ -23,6 +23,7 @@ import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ThemeManager import org.mozilla.fenix.ThemeManager
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
class ToolbarIntegration( class ToolbarIntegration(
@ -67,8 +68,18 @@ class ToolbarIntegration(
) )
.build() .build()
val navController = Navigation.findNavController(toolbar) val navController = Navigation.findNavController(toolbar)
if (!navController.popBackStack(R.id.homeFragment, false)) { if (!navController.popBackStack(
navController.navigate(R.id.action_browserFragment_to_homeFragment, null, options, extras) R.id.homeFragment,
false
)
) {
navController.nav(
R.id.browserFragment,
R.id.action_browserFragment_to_homeFragment,
null,
options,
extras
)
} }
}, },
isPrivate isPrivate

View File

@ -4,10 +4,28 @@
package org.mozilla.fenix.ext package org.mozilla.fenix.ext
import androidx.annotation.IdRes
import androidx.fragment.app.Fragment
import androidx.navigation.NavDirections
import androidx.navigation.NavOptions
import androidx.navigation.Navigator
import androidx.navigation.fragment.NavHostFragment.findNavController
import org.mozilla.fenix.components.Components import org.mozilla.fenix.components.Components
/** /**
* Get the requireComponents of this application. * Get the requireComponents of this application.
*/ */
val androidx.fragment.app.Fragment.requireComponents: Components val Fragment.requireComponents: Components
get() = requireContext().components get() = requireContext().components
fun Fragment.nav(@IdRes id: Int?, directions: NavDirections) {
findNavController(this).nav(id, directions)
}
fun Fragment.nav(@IdRes id: Int?, directions: NavDirections, extras: Navigator.Extras) {
findNavController(this).nav(id, directions, extras)
}
fun Fragment.nav(@IdRes id: Int?, directions: NavDirections, options: NavOptions) {
findNavController(this).nav(id, directions, options)
}

View File

@ -0,0 +1,58 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.ext
import android.os.Bundle
import androidx.annotation.IdRes
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import androidx.navigation.NavOptions
import androidx.navigation.Navigator
import io.sentry.Sentry
import org.mozilla.fenix.BuildConfig
fun NavController.nav(@IdRes id: Int?, directions: NavDirections) {
if (id == null || this.currentDestination?.id == id) {
this.navigate(directions)
} else {
recordIdException(this.currentDestination?.id, id)
}
}
fun NavController.nav(@IdRes id: Int?, directions: NavDirections, extras: Navigator.Extras) {
if (id == null || this.currentDestination?.id == id) {
this.navigate(directions, extras)
} else {
recordIdException(this.currentDestination?.id, id)
}
}
fun NavController.nav(@IdRes id: Int?, directions: NavDirections, options: NavOptions) {
if (id == null || this.currentDestination?.id == id) {
this.navigate(directions, options)
} else {
recordIdException(this.currentDestination?.id, id)
}
}
fun NavController.nav(
@IdRes id: Int?,
@IdRes destId: Int,
args: Bundle?,
navOptions: NavOptions?,
extras: Navigator.Extras?
) {
if (id == null || this.currentDestination?.id == id) {
this.navigate(destId, args, navOptions, extras)
} else {
recordIdException(this.currentDestination?.id, id)
}
}
fun recordIdException(actual: Int?, expected: Int?) {
if (!BuildConfig.SENTRY_TOKEN.isNullOrEmpty()) {
Sentry.capture("Fragment id $actual did not match expected $expected")
}
}

View File

@ -18,7 +18,6 @@ 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.navigation.Navigation
import androidx.navigation.fragment.FragmentNavigator import androidx.navigation.fragment.FragmentNavigator
import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.NavHostFragment.findNavController
import androidx.transition.TransitionInflater import androidx.transition.TransitionInflater
@ -50,6 +49,7 @@ import org.mozilla.fenix.collections.CreateCollectionViewModel
import org.mozilla.fenix.collections.SaveCollectionStep import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.urlToTrimmedHost import org.mozilla.fenix.ext.urlToTrimmedHost
import org.mozilla.fenix.home.sessioncontrol.CollectionAction import org.mozilla.fenix.home.sessioncontrol.CollectionAction
@ -220,7 +220,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
FragmentNavigator.Extras.Builder() FragmentNavigator.Extras.Builder()
.addSharedElement(toolbar_wrapper, "toolbar_wrapper_transition") .addSharedElement(toolbar_wrapper, "toolbar_wrapper_transition")
.build() .build()
Navigation.findNavController(it).navigate(directions, extras) nav(R.id.homeFragment, directions, extras)
requireComponents.analytics.metrics.track(Event.SearchBarTapped(Event.SearchBarTapped.Source.HOME)) requireComponents.analytics.metrics.track(Event.SearchBarTapped(Event.SearchBarTapped.Source.HOME))
} }
@ -328,7 +328,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
FragmentNavigator.Extras.Builder() FragmentNavigator.Extras.Builder()
.addSharedElement(action.tabView, "$TAB_ITEM_TRANSITION_NAME${action.sessionId}") .addSharedElement(action.tabView, "$TAB_ITEM_TRANSITION_NAME${action.sessionId}")
.build() .build()
Navigation.findNavController(action.tabView).navigate(directions, extras) nav(R.id.homeFragment, directions, extras)
} }
is TabAction.Close -> { is TabAction.Close -> {
if (deleteSessionJob == null) removeTabWithUndo(action.sessionId) else { if (deleteSessionJob == null) removeTabWithUndo(action.sessionId) else {
@ -362,7 +362,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
is TabAction.Add -> { is TabAction.Add -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
val directions = HomeFragmentDirections.actionHomeFragmentToSearchFragment(null) val directions = HomeFragmentDirections.actionHomeFragmentToSearchFragment(null)
Navigation.findNavController(view!!).navigate(directions) nav(R.id.homeFragment, directions)
} }
is TabAction.ShareTabs -> { is TabAction.ShareTabs -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
@ -504,14 +504,16 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
HomeMenu.Item.Settings -> { HomeMenu.Item.Settings -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
onboarding.finish() onboarding.finish()
Navigation.findNavController(homeLayout).navigate( nav(
R.id.homeFragment,
HomeFragmentDirections.actionHomeFragmentToSettingsFragment() HomeFragmentDirections.actionHomeFragmentToSettingsFragment()
) )
} }
HomeMenu.Item.Library -> { HomeMenu.Item.Library -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
onboarding.finish() onboarding.finish()
Navigation.findNavController(homeLayout).navigate( nav(
R.id.homeFragment,
HomeFragmentDirections.actionHomeFragmentToLibraryFragment() HomeFragmentDirections.actionHomeFragmentToLibraryFragment()
) )
} }
@ -673,14 +675,14 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
view?.let { view?.let {
val directions = HomeFragmentDirections.actionHomeFragmentToCreateCollectionFragment() val directions = HomeFragmentDirections.actionHomeFragmentToCreateCollectionFragment()
Navigation.findNavController(it).navigate(directions) nav(R.id.homeFragment, directions)
} }
} }
private fun share(url: String? = null, tabs: List<ShareTab>? = null) { private fun share(url: String? = null, tabs: List<ShareTab>? = null) {
val directions = val directions =
HomeFragmentDirections.actionHomeFragmentToShareFragment(url = url, tabs = tabs?.toTypedArray()) HomeFragmentDirections.actionHomeFragmentToShareFragment(url = url, tabs = tabs?.toTypedArray())
Navigation.findNavController(view!!).navigate(directions) nav(R.id.homeFragment, directions)
} }
private fun currentMode(): Mode = if (!onboarding.userHasBeenOnboarded()) { private fun currentMode(): Mode = if (!onboarding.userHasBeenOnboarded()) {
@ -696,11 +698,25 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
Mode.Normal Mode.Normal
} }
override fun onAuthenticationProblems() { emitAccountChanges() } override fun onAuthenticationProblems() {
override fun onAuthenticated(account: OAuthAccount) { emitAccountChanges() } emitAccountChanges()
override fun onError(error: Exception) { emitAccountChanges() } }
override fun onLoggedOut() { emitAccountChanges() }
override fun onProfileUpdated(profile: Profile) { emitAccountChanges() } override fun onAuthenticated(account: OAuthAccount) {
emitAccountChanges()
}
override fun onError(error: Exception) {
emitAccountChanges()
}
override fun onLoggedOut() {
emitAccountChanges()
}
override fun onProfileUpdated(profile: Profile) {
emitAccountChanges()
}
companion object { companion object {
private const val SHARED_TRANSITION_MS = 200L private const val SHARED_TRANSITION_MS = 200L

View File

@ -22,6 +22,7 @@ import mozilla.appservices.places.BookmarkRoot
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.getColorFromAttr import org.mozilla.fenix.ext.getColorFromAttr
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
class LibraryFragment : Fragment() { class LibraryFragment : Fragment() {
@ -53,15 +54,16 @@ class LibraryFragment : Fragment() {
libraryHistory.setOnClickListener { libraryHistory.setOnClickListener {
requireComponents.analytics.metrics requireComponents.analytics.metrics
.track(Event.LibrarySelectedItem(view.context.getString(R.string.library_history))) .track(Event.LibrarySelectedItem(view.context.getString(R.string.library_history)))
Navigation.findNavController(view) nav(R.id.libraryFragment, LibraryFragmentDirections.actionLibraryFragmentToHistoryFragment())
.navigate(LibraryFragmentDirections.actionLibraryFragmentToHistoryFragment())
} }
libraryBookmarks.setOnClickListener { libraryBookmarks.setOnClickListener {
requireComponents.analytics.metrics requireComponents.analytics.metrics
.track(Event.LibrarySelectedItem(view.context.getString(R.string.library_bookmarks))) .track(Event.LibrarySelectedItem(view.context.getString(R.string.library_bookmarks)))
Navigation.findNavController(view) nav(
.navigate(LibraryFragmentDirections.actionLibraryFragmentToBookmarksFragment(BookmarkRoot.Mobile.id)) R.id.libraryFragment,
LibraryFragmentDirections.actionLibraryFragmentToBookmarksFragment(BookmarkRoot.Mobile.id)
)
} }
requireComponents.analytics.metrics.track(Event.LibraryOpened) requireComponents.analytics.metrics.track(Event.LibraryOpened)
@ -95,6 +97,6 @@ class LibraryFragment : Fragment() {
toolbar.setBackgroundColor(backgroundColor) toolbar.setBackgroundColor(backgroundColor)
toolbar.setTitleTextColor(foregroundColor) toolbar.setTitleTextColor(foregroundColor)
toolbar.navigationIcon?.colorFilter = toolbar.navigationIcon?.colorFilter =
PorterDuffColorFilter(foregroundColor, PorterDuff.Mode.SRC_IN) PorterDuffColorFilter(foregroundColor, PorterDuff.Mode.SRC_IN)
} }
} }

View File

@ -45,6 +45,7 @@ import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.urlToTrimmedHost import org.mozilla.fenix.ext.urlToTrimmedHost
import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
@ -197,18 +198,20 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
metrics()?.track(Event.OpenedBookmark) metrics()?.track(Event.OpenedBookmark)
} }
is BookmarkAction.Expand -> { is BookmarkAction.Expand -> {
navigation nav(
.navigate(BookmarkFragmentDirections.actionBookmarkFragmentSelf(it.folder.guid)) R.id.bookmarkFragment,
BookmarkFragmentDirections.actionBookmarkFragmentSelf(it.folder.guid)
)
} }
is BookmarkAction.BackPressed -> { is BookmarkAction.BackPressed -> {
navigation.popBackStack() navigation.popBackStack()
} }
is BookmarkAction.Edit -> { is BookmarkAction.Edit -> {
navigation nav(
.navigate( R.id.bookmarkFragment,
BookmarkFragmentDirections BookmarkFragmentDirections
.actionBookmarkFragmentToBookmarkEditFragment(it.item.guid) .actionBookmarkFragmentToBookmarkEditFragment(it.item.guid)
) )
} }
is BookmarkAction.Select -> { is BookmarkAction.Select -> {
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.IsSelected(it.item)) getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.IsSelected(it.item))
@ -224,7 +227,8 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
} }
is BookmarkAction.Share -> { is BookmarkAction.Share -> {
it.item.url?.apply { it.item.url?.apply {
navigation.navigate( nav(
R.id.bookmarkFragment,
BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment( BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(
this, this,
it.item.title it.item.title
@ -308,18 +312,17 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Normal (activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Normal
(activity as HomeActivity).supportActionBar?.hide() (activity as HomeActivity).supportActionBar?.hide()
navigation nav(R.id.bookmarkFragment, BookmarkFragmentDirections.actionBookmarkFragmentToHomeFragment())
.navigate(BookmarkFragmentDirections.actionBookmarkFragmentToHomeFragment())
metrics()?.track(Event.OpenedBookmarksInNewTabs) metrics()?.track(Event.OpenedBookmarksInNewTabs)
true true
} }
R.id.edit_bookmark_multi_select -> { R.id.edit_bookmark_multi_select -> {
val bookmark = getSelectedBookmarks().first() val bookmark = getSelectedBookmarks().first()
navigation nav(
.navigate( R.id.bookmarkFragment,
BookmarkFragmentDirections BookmarkFragmentDirections
.actionBookmarkFragmentToBookmarkEditFragment(bookmark.guid) .actionBookmarkFragmentToBookmarkEditFragment(bookmark.guid)
) )
true true
} }
R.id.open_bookmarks_in_private_tabs_multi_select -> { R.id.open_bookmarks_in_private_tabs_multi_select -> {
@ -331,8 +334,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private (activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private
(activity as HomeActivity).supportActionBar?.hide() (activity as HomeActivity).supportActionBar?.hide()
navigation nav(R.id.bookmarkFragment, BookmarkFragmentDirections.actionBookmarkFragmentToHomeFragment())
.navigate(BookmarkFragmentDirections.actionBookmarkFragmentToHomeFragment())
metrics()?.track(Event.OpenedBookmarksInPrivateTabs) metrics()?.track(Event.OpenedBookmarksInPrivateTabs)
true true
} }
@ -422,8 +424,8 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
children = childrenWithVirtualFolder children = childrenWithVirtualFolder
) )
// If we're looking at the root, that means we're in the "Desktop Bookmarks" folder. // If we're looking at the root, that means we're in the "Desktop Bookmarks" folder.
// Rename its child roots and remove the mobile root. // Rename its child roots and remove the mobile root.
} else if (node.guid == BookmarkRoot.Root.id) { } else if (node.guid == BookmarkRoot.Root.id) {
return BookmarkNode( return BookmarkNode(
type = node.type, type = node.type,
@ -434,7 +436,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
url = node.url, url = node.url,
children = processDesktopRoots(node.children) children = processDesktopRoots(node.children)
) )
// If we're looking at one of the desktop roots, change their titles to friendly names. // If we're looking at one of the desktop roots, change their titles to friendly names.
} else if (node.guid in listOf(BookmarkRoot.Menu.id, BookmarkRoot.Toolbar.id, BookmarkRoot.Unfiled.id)) { } else if (node.guid in listOf(BookmarkRoot.Menu.id, BookmarkRoot.Toolbar.id, BookmarkRoot.Unfiled.id)) {
return BookmarkNode( return BookmarkNode(
type = node.type, type = node.type,

View File

@ -28,6 +28,7 @@ import mozilla.appservices.places.BookmarkRoot
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.getColorFromAttr import org.mozilla.fenix.ext.getColorFromAttr
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 import kotlin.coroutines.CoroutineContext
@ -65,14 +66,14 @@ class AddBookmarkFolderFragment : Fragment(), CoroutineScope {
launch(Main) { launch(Main) {
bookmark_add_folder_parent_selector.text = sharedViewModel.selectedFolder!!.title bookmark_add_folder_parent_selector.text = sharedViewModel.selectedFolder!!.title
bookmark_add_folder_parent_selector.setOnClickListener { bookmark_add_folder_parent_selector.setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.container) nav(
.navigate( R.id.bookmarkAddFolderFragment,
AddBookmarkFolderFragmentDirections AddBookmarkFolderFragmentDirections
.actionBookmarkAddFolderFragmentToBookmarkSelectFolderFragment( .actionBookmarkAddFolderFragmentToBookmarkSelectFolderFragment(
BookmarkRoot.Root.id, BookmarkRoot.Root.id,
true true
) )
) )
} }
} }
} }

View File

@ -39,6 +39,7 @@ import mozilla.components.concept.storage.BookmarkNodeType
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.getColorFromAttr import org.mozilla.fenix.ext.getColorFromAttr
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 java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -106,7 +107,8 @@ class EditBookmarkFragment : Fragment(), CoroutineScope {
bookmark_folder_selector.text = node.title bookmark_folder_selector.text = node.title
bookmark_folder_selector.setOnClickListener { bookmark_folder_selector.setOnClickListener {
sharedViewModel.selectedFolder = null sharedViewModel.selectedFolder = null
Navigation.findNavController(requireActivity(), R.id.container).navigate( nav(
R.id.bookmarkEditFragment,
EditBookmarkFragmentDirections EditBookmarkFragmentDirections
.actionBookmarkEditFragmentToBookmarkSelectFolderFragment(null) .actionBookmarkEditFragmentToBookmarkSelectFolderFragment(null)
) )

View File

@ -16,8 +16,6 @@ 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.lifecycle.ViewModelProviders
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_bookmark.view.*
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.CoroutineScope
@ -36,6 +34,7 @@ import org.mozilla.fenix.FenixViewModelProvider
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.getColorFromAttr import org.mozilla.fenix.ext.getColorFromAttr
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 org.mozilla.fenix.library.bookmarks.SignInAction import org.mozilla.fenix.library.bookmarks.SignInAction
@ -145,7 +144,8 @@ class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver
return when (item.itemId) { return when (item.itemId) {
R.id.add_folder_button -> { R.id.add_folder_button -> {
launch(Main) { launch(Main) {
Navigation.findNavController(requireActivity(), R.id.container).navigate( nav(
R.id.bookmarkSelectFolderFragment,
SelectBookmarkFolderFragmentDirections SelectBookmarkFolderFragmentDirections
.actionBookmarkSelectFolderFragmentToBookmarkAddFolderFragment() .actionBookmarkSelectFolderFragmentToBookmarkAddFolderFragment()
) )

View File

@ -38,6 +38,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components import org.mozilla.fenix.components.Components
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getHostFromUrl import org.mozilla.fenix.ext.getHostFromUrl
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
@ -161,7 +162,7 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
browsingModeManager.mode = BrowsingModeManager.Mode.Normal browsingModeManager.mode = BrowsingModeManager.Mode.Normal
supportActionBar?.hide() supportActionBar?.hide()
} }
navigation.navigate(HistoryFragmentDirections.actionHistoryFragmentToHomeFragment()) nav(R.id.historyFragment, HistoryFragmentDirections.actionHistoryFragmentToHomeFragment())
true true
} }
R.id.open_history_in_private_tabs_multi_select -> { R.id.open_history_in_private_tabs_multi_select -> {
@ -176,7 +177,7 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
browsingModeManager.mode = BrowsingModeManager.Mode.Private browsingModeManager.mode = BrowsingModeManager.Mode.Private
supportActionBar?.hide() supportActionBar?.hide()
} }
navigation.navigate(HistoryFragmentDirections.actionHistoryFragmentToHomeFragment()) nav(R.id.historyFragment, HistoryFragmentDirections.actionHistoryFragmentToHomeFragment())
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
@ -297,7 +298,7 @@ class HistoryFragment : Fragment(), CoroutineScope by MainScope(), BackHandler {
private fun share(url: String? = null, tabs: List<ShareTab>? = null) { private fun share(url: String? = null, tabs: List<ShareTab>? = null) {
val directions = val directions =
HistoryFragmentDirections.actionHistoryFragmentToShareFragment(url = url, tabs = tabs?.toTypedArray()) HistoryFragmentDirections.actionHistoryFragmentToShareFragment(url = url, tabs = tabs?.toTypedArray())
Navigation.findNavController(view!!).navigate(directions) nav(R.id.historyFragment, directions)
} }
private inline fun emitChange(producer: () -> HistoryChange) { private inline fun emitChange(producer: () -> HistoryChange) {

View File

@ -16,6 +16,7 @@ import androidx.fragment.app.DialogFragment
import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.NavHostFragment.findNavController
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.nav
class PairInstructionsFragment : BottomSheetDialogFragment() { class PairInstructionsFragment : BottomSheetDialogFragment() {
@ -46,7 +47,7 @@ class PairInstructionsFragment : BottomSheetDialogFragment() {
val openCamera = view.findViewById(R.id.pair_open_camera) as Button val openCamera = view.findViewById(R.id.pair_open_camera) as Button
openCamera.setOnClickListener { openCamera.setOnClickListener {
val directions = PairInstructionsFragmentDirections.actionPairInstructionsFragmentToPairFragment() val directions = PairInstructionsFragmentDirections.actionPairInstructionsFragmentToPairFragment()
findNavController(this@PairInstructionsFragment).navigate(directions) nav(R.id.pairInstructionsFragment, directions)
} }
val cancelCamera = view.findViewById(R.id.pair_cancel) as Button val cancelCamera = view.findViewById(R.id.pair_cancel) as Button

View File

@ -15,7 +15,6 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.navigation.Navigation
import androidx.paging.LivePagedListBuilder import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.paging.PagedListAdapter import androidx.paging.PagedListAdapter
@ -38,6 +37,7 @@ import org.mozilla.fenix.ext.components
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.widget.ImageView import android.widget.ImageView
import org.mozilla.fenix.ext.nav
private const val MAX_ITEMS_PER_PAGE = 50 private const val MAX_ITEMS_PER_PAGE = 50
@ -135,7 +135,7 @@ class SitePermissionsExceptionsFragment : Fragment(), View.OnClickListener, Coro
val sitePermissions = view?.tag as SitePermissions val sitePermissions = view?.tag as SitePermissions
val directions = SitePermissionsExceptionsFragmentDirections val directions = SitePermissionsExceptionsFragmentDirections
.actionSitePermissionsToExceptionsToSitePermissionsDetails(sitePermissions) .actionSitePermissionsToExceptionsToSitePermissionsDetails(sitePermissions)
Navigation.findNavController(requireNotNull(view)).navigate(directions) nav(R.id.sitePermissionsExceptionsFragment, directions)
} }
} }

View File

@ -16,7 +16,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import androidx.navigation.fragment.NavHostFragment.findNavController
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_share.view.* import kotlinx.android.synthetic.main.fragment_share.view.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -26,6 +25,7 @@ import mozilla.components.concept.sync.DeviceEventOutgoing
import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.OAuthAccount
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.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
@ -87,7 +87,7 @@ class ShareFragment : AppCompatDialogFragment(), CoroutineScope {
} }
ShareAction.SignInClicked -> { ShareAction.SignInClicked -> {
val directions = ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment() val directions = ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment()
findNavController(this@ShareFragment).navigate(directions) nav(R.id.shareFragment, directions)
dismiss() dismiss()
} }
ShareAction.AddNewDeviceClicked -> { ShareAction.AddNewDeviceClicked -> {