1
0
Fork 0

For #4529, #4427: Resuming after restoring instance state breaks UI (#4571)

* For #4529, #4427: Resuming after restoring instance state breaks UI

* Clear up warnings
master
Colin Lee 2019-08-08 11:05:01 -05:00 committed by GitHub
parent c21c91eac5
commit ef97173cd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 277 additions and 248 deletions

View File

@ -8,7 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- #4137 - Adds pagination to the history view - #4137 - Adds pagination to the history view
- #3695 - Made search suggestions for other tabs clickable - #3695 - Made search suggestions for other tabs clickable
### Changed
- Remove forced focus of toolbar on homescreen - Remove forced focus of toolbar on homescreen
- #4529 - Fixed an issue where the app would sometimes return to a blank toolbar
- #4427 - Fixed an issue where the app would sometimes return to the home fragment
### Removed
## [1.1.0 and earlier] - 2019-07-23 ## [1.1.0 and earlier] - 2019-07-23
### Added ### Added

View File

@ -7,10 +7,10 @@ package org.mozilla.fenix
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import org.mozilla.fenix.mvi.ViewState
import org.mozilla.fenix.mvi.Change import org.mozilla.fenix.mvi.Change
import org.mozilla.fenix.mvi.UIComponentViewModelBase import org.mozilla.fenix.mvi.UIComponentViewModelBase
import org.mozilla.fenix.mvi.UIComponentViewModelProvider import org.mozilla.fenix.mvi.UIComponentViewModelProvider
import org.mozilla.fenix.mvi.ViewState
object FenixViewModelProvider { object FenixViewModelProvider {
fun <S : ViewState, C : Change, T : UIComponentViewModelBase<S, C>> create( fun <S : ViewState, C : Change, T : UIComponentViewModelBase<S, C>> create(

View File

@ -15,7 +15,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
@ -25,9 +25,12 @@ 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.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.MainScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.browser.session.intent.EXTRA_SESSION_ID import mozilla.components.browser.session.intent.EXTRA_SESSION_ID
import mozilla.components.feature.app.links.AppLinksFeature import mozilla.components.feature.app.links.AppLinksFeature
import mozilla.components.feature.contextmenu.ContextMenuFeature import mozilla.components.feature.contextmenu.ContextMenuFeature
@ -76,8 +79,8 @@ import org.mozilla.fenix.utils.Settings
* This class only contains shared code focused on the main browsing content. * This class only contains shared code focused on the main browsing content.
* UI code specific to the app or to custom tabs can be found in the subclasses. * UI code specific to the app or to custom tabs can be found in the subclasses.
*/ */
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions", "LargeClass")
abstract class BaseBrowserFragment : Fragment(), BackHandler { abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Observer {
protected lateinit var browserStore: BrowserStore protected lateinit var browserStore: BrowserStore
protected lateinit var browserInteractor: BrowserInteractor protected lateinit var browserInteractor: BrowserInteractor
protected lateinit var browserToolbarView: BrowserToolbarView protected lateinit var browserToolbarView: BrowserToolbarView
@ -95,6 +98,9 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler {
var customTabSessionId: String? = null var customTabSessionId: String? = null
private var browserInitialized: Boolean = false
private var initUIJob: Job? = null
@CallSuper @CallSuper
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -127,17 +133,19 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler {
return view return view
} }
@Suppress("ComplexMethod")
@CallSuper @CallSuper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
browserInitialized = initializeUI(view) != null
}
@Suppress("ComplexMethod")
@CallSuper
protected open fun initializeUI(view: View): Session? {
val sessionManager = requireComponents.core.sessionManager val sessionManager = requireComponents.core.sessionManager
getSessionById()?.let { session -> return getSessionById()?.also { session ->
val viewModel = activity!!.run { val viewModel: CreateCollectionViewModel by activityViewModels()
ViewModelProvider(this).get(CreateCollectionViewModel::class.java)
}
val browserToolbarController = DefaultBrowserToolbarController( val browserToolbarController = DefaultBrowserToolbarController(
context!!, context!!,
@ -185,157 +193,179 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler {
browserToolbarView.view.setOnSiteSecurityClickedListener { browserToolbarView.view.setOnSiteSecurityClickedListener {
showQuickSettingsDialog() showQuickSettingsDialog()
} }
}
contextMenuFeature.set( contextMenuFeature.set(
feature = ContextMenuFeature( feature = ContextMenuFeature(
requireFragmentManager(), requireFragmentManager(),
sessionManager, sessionManager,
FenixContextMenuCandidate.defaultCandidates( FenixContextMenuCandidate.defaultCandidates(
requireContext(), requireContext(),
requireComponents.useCases.tabsUseCases, requireComponents.useCases.tabsUseCases,
view,
FenixSnackbarDelegate(
view, view,
if (getSessionById()?.isCustomTabSession() == true) null else nestedScrollQuickAction FenixSnackbarDelegate(
) view,
), if (getSessionById()?.isCustomTabSession() == true) null else nestedScrollQuickAction
view.engineView
),
owner = this,
view = view
)
downloadsFeature.set(
feature = DownloadsFeature(
requireContext().applicationContext,
sessionManager = sessionManager,
fragmentManager = childFragmentManager,
sessionId = customTabSessionId,
downloadManager = FetchDownloadManager(requireContext().applicationContext, DownloadService::class),
onNeedToRequestPermissions = { permissions ->
requestPermissions(permissions, REQUEST_CODE_DOWNLOAD_PERMISSIONS)
}),
owner = this,
view = view
)
appLinksFeature.set(
feature = AppLinksFeature(
requireContext(),
sessionManager = sessionManager,
sessionId = customTabSessionId,
interceptLinkClicks = true,
fragmentManager = requireFragmentManager()
),
owner = this,
view = view
)
promptsFeature.set(
feature = PromptFeature(
fragment = this,
sessionManager = sessionManager,
sessionId = customTabSessionId,
fragmentManager = requireFragmentManager(),
onNeedToRequestPermissions = { permissions ->
requestPermissions(permissions, REQUEST_CODE_PROMPT_PERMISSIONS)
}),
owner = this,
view = view
)
sessionFeature.set(
feature = SessionFeature(
sessionManager,
SessionUseCases(sessionManager),
view.engineView,
customTabSessionId
),
owner = this,
view = view
)
val accentHighContrastColor = ThemeManager.resolveAttribute(R.attr.accentHighContrast, requireContext())
sitePermissionsFeature.set(
feature = SitePermissionsFeature(
context = requireContext(),
sessionManager = sessionManager,
fragmentManager = requireFragmentManager(),
promptsStyling = SitePermissionsFeature.PromptsStyling(
gravity = getAppropriateLayoutGravity(),
shouldWidthMatchParent = true,
positiveButtonBackgroundColor = accentHighContrastColor,
positiveButtonTextColor = R.color.photonWhite
),
sessionId = customTabSessionId
) { permissions ->
requestPermissions(permissions, REQUEST_CODE_APP_PERMISSIONS)
},
owner = this,
view = view
)
fullScreenFeature.set(
feature = FullScreenFeature(
sessionManager,
SessionUseCases(sessionManager),
customTabSessionId
) { inFullScreen ->
if (inFullScreen) {
FenixSnackbar.make(view.rootView, Snackbar.LENGTH_SHORT)
.setText(getString(R.string.full_screen_notification))
.show()
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
activity?.enterToImmersiveMode()
toolbar.visibility = View.GONE
nestedScrollQuickAction.visibility = View.GONE
} else {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
activity?.exitImmersiveModeIfNeeded()
(activity as HomeActivity).let { activity: HomeActivity ->
ThemeManager.applyStatusBarTheme(
activity.window,
activity.themeManager,
activity
) )
} ),
toolbar.visibility = View.VISIBLE view.engineView
nestedScrollQuickAction.visibility = View.VISIBLE ),
} owner = this,
view.swipeRefresh.apply { view = view
val (topMargin, bottomMargin) = if (inFullScreen) 0 to 0 else getEngineMargins() )
(layoutParams as CoordinatorLayout.LayoutParams).setMargins(0, topMargin, 0, bottomMargin)
}
},
owner = this,
view = view
)
if (FeatureFlags.pullToRefreshEnabled) { downloadsFeature.set(
val primaryTextColor = ThemeManager.resolveAttribute(R.attr.primaryText, requireContext()) feature = DownloadsFeature(
view.swipeRefresh.setColorSchemeColors(primaryTextColor) requireContext().applicationContext,
swipeRefreshFeature.set( sessionManager = sessionManager,
feature = SwipeRefreshFeature( fragmentManager = childFragmentManager,
requireComponents.core.sessionManager, sessionId = customTabSessionId,
requireComponents.useCases.sessionUseCases.reload, downloadManager = FetchDownloadManager(requireContext().applicationContext, DownloadService::class),
view.swipeRefresh, onNeedToRequestPermissions = { permissions ->
requestPermissions(permissions, REQUEST_CODE_DOWNLOAD_PERMISSIONS)
}),
owner = this,
view = view
)
appLinksFeature.set(
feature = AppLinksFeature(
requireContext(),
sessionManager = sessionManager,
sessionId = customTabSessionId,
interceptLinkClicks = true,
fragmentManager = requireFragmentManager()
),
owner = this,
view = view
)
promptsFeature.set(
feature = PromptFeature(
fragment = this,
sessionManager = sessionManager,
sessionId = customTabSessionId,
fragmentManager = requireFragmentManager(),
onNeedToRequestPermissions = { permissions ->
requestPermissions(permissions, REQUEST_CODE_PROMPT_PERMISSIONS)
}),
owner = this,
view = view
)
sessionFeature.set(
feature = SessionFeature(
sessionManager,
SessionUseCases(sessionManager),
view.engineView,
customTabSessionId customTabSessionId
), ),
owner = this, owner = this,
view = view view = view
) )
} else {
// Disable pull to refresh val accentHighContrastColor = ThemeManager.resolveAttribute(R.attr.accentHighContrast, requireContext())
view.swipeRefresh.setOnChildScrollUpCallback { _, _ -> true }
sitePermissionsFeature.set(
feature = SitePermissionsFeature(
context = requireContext(),
sessionManager = sessionManager,
fragmentManager = requireFragmentManager(),
promptsStyling = SitePermissionsFeature.PromptsStyling(
gravity = getAppropriateLayoutGravity(),
shouldWidthMatchParent = true,
positiveButtonBackgroundColor = accentHighContrastColor,
positiveButtonTextColor = R.color.photonWhite
),
sessionId = customTabSessionId
) { permissions ->
requestPermissions(permissions, REQUEST_CODE_APP_PERMISSIONS)
},
owner = this,
view = view
)
fullScreenFeature.set(
feature = FullScreenFeature(
sessionManager,
SessionUseCases(sessionManager),
customTabSessionId
) { inFullScreen ->
if (inFullScreen) {
FenixSnackbar.make(view.rootView, Snackbar.LENGTH_SHORT)
.setText(getString(R.string.full_screen_notification))
.show()
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
activity?.enterToImmersiveMode()
toolbar.visibility = View.GONE
nestedScrollQuickAction.visibility = View.GONE
} else {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
activity?.exitImmersiveModeIfNeeded()
(activity as HomeActivity).let { activity: HomeActivity ->
ThemeManager.applyStatusBarTheme(
activity.window,
activity.themeManager,
activity
)
}
toolbar.visibility = View.VISIBLE
nestedScrollQuickAction.visibility = View.VISIBLE
}
view.swipeRefresh.apply {
val (topMargin, bottomMargin) = if (inFullScreen) 0 to 0 else getEngineMargins()
(layoutParams as CoordinatorLayout.LayoutParams).setMargins(0, topMargin, 0, bottomMargin)
}
},
owner = this,
view = view
)
@Suppress("ConstantConditionIf")
if (FeatureFlags.pullToRefreshEnabled) {
val primaryTextColor = ThemeManager.resolveAttribute(R.attr.primaryText, requireContext())
view.swipeRefresh.setColorSchemeColors(primaryTextColor)
swipeRefreshFeature.set(
feature = SwipeRefreshFeature(
requireComponents.core.sessionManager,
requireComponents.useCases.sessionUseCases.reload,
view.swipeRefresh,
customTabSessionId
),
owner = this,
view = view
)
} else {
// Disable pull to refresh
view.swipeRefresh.setOnChildScrollUpCallback { _, _ -> true }
}
(activity as HomeActivity).updateThemeForSession(session)
} }
} }
@CallSuper
override fun onSessionSelected(session: Session) {
super.onSessionSelected(session)
if (!browserInitialized) {
// Initializing a new coroutineScope to avoid ConcurrentModificationException in ObserverRegistry
// This will be removed when ObserverRegistry is deprecated by browser-state.
initUIJob = MainScope().launch {
view?.let {
browserInitialized = initializeUI(it) != null
}
}
}
}
@CallSuper
override fun onStart() {
super.onStart()
requireComponents.core.sessionManager.register(this, this, autoPause = true)
}
@CallSuper @CallSuper
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val session = getSessionById() ?: return
val components = requireComponents val components = requireComponents
val preferredColorScheme = components.core.getPreferredColorScheme() val preferredColorScheme = components.core.getPreferredColorScheme()
@ -343,20 +373,23 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler {
components.core.engine.settings.preferredColorScheme = preferredColorScheme components.core.engine.settings.preferredColorScheme = preferredColorScheme
components.useCases.sessionUseCases.reload() components.useCases.sessionUseCases.reload()
} }
(activity as HomeActivity).updateThemeForSession(session)
(activity as AppCompatActivity).supportActionBar?.hide() (activity as AppCompatActivity).supportActionBar?.hide()
assignSitePermissionsRules() assignSitePermissionsRules()
} }
/** @CallSuper
* Exits full screen mode.
*/
final override fun onPause() { final override fun onPause() {
super.onPause() super.onPause()
fullScreenFeature.onBackPressed() fullScreenFeature.onBackPressed()
} }
@CallSuper
override fun onStop() {
super.onStop()
initUIJob?.cancel()
}
@CallSuper @CallSuper
override fun onBackPressed(): Boolean { override fun onBackPressed(): Boolean {
return findInPageIntegration.onBackPressed() || return findInPageIntegration.onBackPressed() ||
@ -480,8 +513,9 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler {
*/ */
protected fun getSessionById(): Session? { protected fun getSessionById(): Session? {
val sessionManager = context?.components?.core?.sessionManager ?: return null val sessionManager = context?.components?.core?.sessionManager ?: return null
return if (customTabSessionId != null) { val localCustomTabId = customTabSessionId
sessionManager.findSessionById(customTabSessionId!!) return if (localCustomTabId != null) {
sessionManager.findSessionById(localCustomTabId)
} else { } else {
sessionManager.selectedSession sessionManager.selectedSession
} }

View File

@ -14,7 +14,6 @@ import android.widget.RadioButton
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.NavHostFragment.findNavController
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.transition.TransitionInflater import androidx.transition.TransitionInflater
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@ -30,7 +29,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.feature.readerview.ReaderViewFeature import mozilla.components.feature.readerview.ReaderViewFeature
import mozilla.components.feature.session.ThumbnailsFeature import mozilla.components.feature.session.ThumbnailsFeature
import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.lib.state.ext.consumeFrom
@ -59,6 +57,8 @@ import java.net.URL
/** /**
* Fragment used for browsing the web within the main app and external apps. * Fragment used for browsing the web within the main app and external apps.
*/ */
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
class BrowserFragment : BaseBrowserFragment(), BackHandler { class BrowserFragment : BaseBrowserFragment(), BackHandler {
private lateinit var quickActionSheetView: QuickActionSheetView private lateinit var quickActionSheetView: QuickActionSheetView
@ -91,17 +91,12 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
return view return view
} }
@Suppress("LongMethod", "ComplexMethod") override fun initializeUI(view: View): Session? {
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val sessionManager = requireComponents.core.sessionManager val sessionManager = requireComponents.core.sessionManager
getSessionById()?.let { return super.initializeUI(view)?.also { session ->
quickActionSheetView =
QuickActionSheetView(view.nestedScrollQuickAction, browserInteractor) quickActionSheetView = QuickActionSheetView(view.nestedScrollQuickAction, browserInteractor)
customTabSessionId?.let { customTabSessionId -> customTabSessionId?.let { customTabSessionId ->
customTabsIntegration.set( customTabsIntegration.set(
@ -119,57 +114,58 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
view = view) view = view)
} }
thumbnailsFeature.set(
feature = ThumbnailsFeature(
requireContext(),
view.engineView,
requireComponents.core.sessionManager
),
owner = this,
view = view
)
readerViewFeature.set(
feature = ReaderViewFeature(
requireContext(),
requireComponents.core.engine,
requireComponents.core.sessionManager,
view.readerViewControlsBar
) { available ->
if (available) {
requireComponents.analytics.metrics.track(Event.ReaderModeAvailable)
}
browserStore.apply {
dispatch(QuickActionSheetAction.ReadableStateChange(available))
dispatch(
QuickActionSheetAction.ReaderActiveStateChange(
sessionManager.selectedSession?.readerMode ?: false
)
)
}
},
owner = this,
view = view
)
if ((activity as HomeActivity).browsingModeManager.isPrivate) {
// We need to update styles for private mode programmatically for now:
// https://github.com/mozilla-mobile/android-components/issues/3400
themeReaderViewControlsForPrivateMode(view.readerViewControlsBar)
}
updateBookmarkState(session)
consumeFrom(browserStore) { consumeFrom(browserStore) {
quickActionSheetView.update(it) quickActionSheetView.update(it)
browserToolbarView.update(it) browserToolbarView.update(it)
} }
} }
thumbnailsFeature.set(
feature = ThumbnailsFeature(
requireContext(),
view.engineView,
requireComponents.core.sessionManager
),
owner = this,
view = view
)
readerViewFeature.set(
feature = ReaderViewFeature(
requireContext(),
requireComponents.core.engine,
requireComponents.core.sessionManager,
view.readerViewControlsBar
) { available ->
if (available) {
requireComponents.analytics.metrics.track(Event.ReaderModeAvailable)
}
browserStore.apply {
dispatch(QuickActionSheetAction.ReadableStateChange(available))
dispatch(
QuickActionSheetAction.ReaderActiveStateChange(
sessionManager.selectedSession?.readerMode ?: false
)
)
}
},
owner = this,
view = view
)
if ((activity as HomeActivity).browsingModeManager.isPrivate) {
// We need to update styles for private mode programmatically for now:
// https://github.com/mozilla-mobile/android-components/issues/3400
themeReaderViewControlsForPrivateMode(view.readerViewControlsBar)
}
} }
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
subscribeToSession() subscribeToSession()
subscribeToSessions()
subscribeToTabCollections() subscribeToTabCollections()
} }
@ -177,11 +173,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
super.onResume() super.onResume()
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this) requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
getSessionById()?.let { updateBookmarkState(it) }
// See #4387 for why we're popping here
if (getSessionById() == null) findNavController(this).popBackStack(R.id.homeFragment, false)
} }
override fun onBackPressed(): Boolean { override fun onBackPressed(): Boolean {
@ -332,14 +323,9 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
getSessionById()?.register(observer, this, autoPause = true) getSessionById()?.register(observer, this, autoPause = true)
} }
private fun subscribeToSessions() { override fun onSessionSelected(session: Session) {
val observer = object : SessionManager.Observer { super.onSessionSelected(session)
override fun onSessionSelected(session: Session) { updateBookmarkState(session)
(activity as HomeActivity).updateThemeForSession(session)
updateBookmarkState(session)
}
}
requireComponents.core.sessionManager.register(observer, this, autoPause = true)
} }
private suspend fun findBookmarkedURL(session: Session?): Boolean { private suspend fun findBookmarkedURL(session: Session?): Boolean {

View File

@ -10,7 +10,7 @@ import android.view.LayoutInflater
import android.view.View 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.ViewModelProvider import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope 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.Dispatchers import kotlinx.coroutines.Dispatchers
@ -28,7 +28,7 @@ import org.mozilla.fenix.mvi.getManagedEmitter
class CreateCollectionFragment : DialogFragment() { class CreateCollectionFragment : DialogFragment() {
private lateinit var collectionCreationComponent: CollectionCreationComponent private lateinit var collectionCreationComponent: CollectionCreationComponent
private lateinit var viewModel: CreateCollectionViewModel private val viewModel: CreateCollectionViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -43,10 +43,6 @@ class CreateCollectionFragment : DialogFragment() {
): View? { ): View? {
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 {
ViewModelProvider(this).get(CreateCollectionViewModel::class.java)
}
collectionCreationComponent = CollectionCreationComponent( collectionCreationComponent = CollectionCreationComponent(
view.createCollectionWrapper, view.createCollectionWrapper,
ActionBusFactory.get(this), ActionBusFactory.get(this),

View File

@ -10,6 +10,8 @@ import android.content.Intent
import androidx.core.widget.NestedScrollView import androidx.core.widget.NestedScrollView
import androidx.navigation.NavController import androidx.navigation.NavController
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.concept.engine.EngineView import mozilla.components.concept.engine.EngineView
import org.mozilla.fenix.BrowsingModeManager import org.mozilla.fenix.BrowsingModeManager
@ -59,6 +61,8 @@ class DefaultBrowserToolbarController(
) )
} }
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
@SuppressWarnings("ComplexMethod") @SuppressWarnings("ComplexMethod")
override fun handleToolbarItemInteraction(item: ToolbarMenu.Item) { override fun handleToolbarItemInteraction(item: ToolbarMenu.Item) {
val sessionUseCases = context.components.useCases.sessionUseCases val sessionUseCases = context.components.useCases.sessionUseCases

View File

@ -19,11 +19,11 @@ 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.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.FragmentNavigator import androidx.navigation.fragment.FragmentNavigator
import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.NavHostFragment.findNavController
@ -204,15 +204,12 @@ class HomeFragment : Fragment(), AccountObserver {
} }
private fun restoreLayoutState() { private fun restoreLayoutState() {
val homeViewModel = activity?.run { val homeViewModel: HomeScreenViewModel by activityViewModels()
ViewModelProvider(this).get(HomeScreenViewModel::class.java) homeViewModel.layoutManagerState?.also { parcelable ->
}
homeViewModel?.layoutManagerState?.also { parcelable ->
sessionControlComponent.view.layoutManager?.onRestoreInstanceState(parcelable) sessionControlComponent.view.layoutManager?.onRestoreInstanceState(parcelable)
} }
homeLayout?.progress = homeViewModel?.motionLayoutProgress ?: 0F homeLayout?.progress = homeViewModel.motionLayoutProgress
homeViewModel?.layoutManagerState = null homeViewModel.layoutManagerState = null
} }
@SuppressWarnings("LongMethod") @SuppressWarnings("LongMethod")
@ -555,12 +552,10 @@ class HomeFragment : Fragment(), AccountObserver {
override fun onPause() { override fun onPause() {
invokePendingDeleteJobs() invokePendingDeleteJobs()
super.onPause() super.onPause()
val homeViewModel = activity?.run { val homeViewModel: HomeScreenViewModel by activityViewModels()
ViewModelProvider(this).get(HomeScreenViewModel::class.java) homeViewModel.layoutManagerState =
}
homeViewModel?.layoutManagerState =
sessionControlComponent.view.layoutManager?.onSaveInstanceState() sessionControlComponent.view.layoutManager?.onSaveInstanceState()
homeViewModel?.motionLayoutProgress = homeLayout?.progress ?: 0F homeViewModel.motionLayoutProgress = homeLayout?.progress ?: 0F
} }
private fun setupHomeMenu() { private fun setupHomeMenu() {
@ -691,21 +686,18 @@ class HomeFragment : Fragment(), AccountObserver {
val tabs = getListOfSessions().toTabs() val tabs = getListOfSessions().toTabs()
val viewModel = activity?.run { val viewModel: CreateCollectionViewModel by activityViewModels()
ViewModelProvider(this).get(CreateCollectionViewModel::class.java) viewModel.tabs = tabs
}
viewModel?.tabs = tabs
val selectedTabs = val selectedTabs =
tabs.find { tab -> tab.sessionId == selectedTabId } tabs.find { tab -> tab.sessionId == selectedTabId }
?: if (tabs.size == 1) tabs[0] else null ?: if (tabs.size == 1) tabs[0] else null
val selectedSet = if (selectedTabs == null) mutableSetOf() else mutableSetOf(selectedTabs) val selectedSet = if (selectedTabs == null) mutableSetOf() else mutableSetOf(selectedTabs)
viewModel?.selectedTabs = selectedSet viewModel.selectedTabs = selectedSet
viewModel?.tabCollections = viewModel.tabCollections = requireComponents.core.tabCollectionStorage.cachedTabCollections.reversed()
requireComponents.core.tabCollectionStorage.cachedTabCollections.reversed() viewModel.selectedTabCollection = selectedTabCollection
viewModel?.selectedTabCollection = selectedTabCollection viewModel.saveCollectionStep =
viewModel?.saveCollectionStep = step ?: viewModel.getStepForTabsAndCollectionSize()
step ?: viewModel?.getStepForTabsAndCollectionSize() ?: SaveCollectionStep.SelectTabs viewModel.previousFragmentId = R.id.homeFragment
viewModel?.previousFragmentId = R.id.homeFragment
// Only register the observer right before moving to collection creation // Only register the observer right before moving to collection creation
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this) requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)

View File

@ -14,6 +14,7 @@ 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.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.fragment_delete_browsing_data.* import kotlinx.android.synthetic.main.fragment_delete_browsing_data.*
import kotlinx.android.synthetic.main.fragment_delete_browsing_data.view.* import kotlinx.android.synthetic.main.fragment_delete_browsing_data.view.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -114,14 +115,15 @@ class DeleteBrowsingDataFragment : Fragment() {
} }
} }
fun startDeletion() { private fun startDeletion() {
progress_bar.visibility = View.VISIBLE progress_bar.visibility = View.VISIBLE
delete_browsing_data_wrapper.isEnabled = false delete_browsing_data_wrapper.isEnabled = false
delete_browsing_data_wrapper.isClickable = false delete_browsing_data_wrapper.isClickable = false
delete_browsing_data_wrapper.alpha = DISABLED_ALPHA delete_browsing_data_wrapper.alpha = DISABLED_ALPHA
} }
fun finishDeletion() { private fun finishDeletion() {
val popAfter = open_tabs_item.isChecked
progress_bar.visibility = View.GONE progress_bar.visibility = View.GONE
delete_browsing_data_wrapper.isEnabled = true delete_browsing_data_wrapper.isEnabled = true
delete_browsing_data_wrapper.isClickable = true delete_browsing_data_wrapper.isClickable = true
@ -138,6 +140,10 @@ class DeleteBrowsingDataFragment : Fragment() {
FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_SHORT)
.setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar)) .setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar))
.show() .show()
if (popAfter) viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
findNavController().popBackStack(R.id.homeFragment, false)
}
} }
private fun updateDeleteButton() { private fun updateDeleteButton() {

View File

@ -26,6 +26,8 @@ import androidx.navigation.fragment.NavHostFragment.findNavController
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.feature.sitepermissions.SitePermissions
@ -48,6 +50,7 @@ import com.google.android.material.R as MaterialR
private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4 private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4
@ObsoleteCoroutinesApi
@SuppressWarnings("TooManyFunctions") @SuppressWarnings("TooManyFunctions")
class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() { class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
private val safeArguments get() = requireNotNull(arguments) private val safeArguments get() = requireNotNull(arguments)
@ -167,6 +170,8 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
} }
} }
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
getAutoDisposeObservable<QuickSettingsAction>() getAutoDisposeObservable<QuickSettingsAction>()