For #12383 #15407 #12860 - Switch to using shared view model for session to delete on home

pull/159/head^2
ekager 4 years ago
parent 2999f64d0a
commit 7d5c199e51

@ -19,6 +19,7 @@ import androidx.core.net.toUri
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@ -109,6 +110,7 @@ import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.home.HomeScreenViewModel
import org.mozilla.fenix.home.SharedViewModel import org.mozilla.fenix.home.SharedViewModel
import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.utils.allowUndo
@ -205,6 +207,10 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
requireContext().accessibilityManager.addAccessibilityStateChangeListener(this) requireContext().accessibilityManager.addAccessibilityStateChangeListener(this)
} }
private val homeViewModel: HomeScreenViewModel by activityViewModels {
ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
}
@Suppress("ComplexMethod", "LongMethod") @Suppress("ComplexMethod", "LongMethod")
@CallSuper @CallSuper
protected open fun initializeUI(view: View): Session? { protected open fun initializeUI(view: View): Session? {
@ -244,7 +250,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
readerModeController = readerMenuController, readerModeController = readerMenuController,
sessionManager = requireComponents.core.sessionManager, sessionManager = requireComponents.core.sessionManager,
engineView = engineView, engineView = engineView,
browserAnimator = browserAnimator, homeViewModel = homeViewModel,
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) }, customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
onTabCounterClicked = { onTabCounterClicked = {
thumbnailsFeature.get()?.requestScreenshot() thumbnailsFeature.get()?.requestScreenshot()
@ -811,7 +817,9 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
@CallSuper @CallSuper
override fun onSessionSelected(session: Session) { override fun onSessionSelected(session: Session) {
updateThemeForSession(session) if (!this.isRemoving) {
updateThemeForSession(session)
}
if (!browserInitialized) { if (!browserInitialized) {
// Initializing a new coroutineScope to avoid ConcurrentModificationException in ObserverRegistry // Initializing a new coroutineScope to avoid ConcurrentModificationException in ObserverRegistry
// This will be removed when ObserverRegistry is deprecated by browser-state. // This will be removed when ObserverRegistry is deprecated by browser-state.

@ -11,7 +11,6 @@ import mozilla.components.concept.engine.EngineView
import mozilla.components.support.ktx.kotlin.isUrl import mozilla.components.support.ktx.kotlin.isUrl
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserAnimator
import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions
import org.mozilla.fenix.browser.BrowserFragmentDirections import org.mozilla.fenix.browser.BrowserFragmentDirections
import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingMode
@ -22,6 +21,7 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.sessionsOfType import org.mozilla.fenix.ext.sessionsOfType
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.home.HomeScreenViewModel
/** /**
* An interface that handles the view manipulation of the BrowserToolbar, triggered by the Interactor * An interface that handles the view manipulation of the BrowserToolbar, triggered by the Interactor
@ -43,7 +43,7 @@ class DefaultBrowserToolbarController(
private val readerModeController: ReaderModeController, private val readerModeController: ReaderModeController,
private val sessionManager: SessionManager, private val sessionManager: SessionManager,
private val engineView: EngineView, private val engineView: EngineView,
private val browserAnimator: BrowserAnimator, private val homeViewModel: HomeScreenViewModel,
private val customTabSession: Session?, private val customTabSession: Session?,
private val onTabCounterClicked: () -> Unit, private val onTabCounterClicked: () -> Unit,
private val onCloseTab: (Session) -> Unit private val onCloseTab: (Session) -> Unit
@ -110,10 +110,9 @@ class DefaultBrowserToolbarController(
if (sessionManager.sessionsOfType(it.private).count() == 1) { if (sessionManager.sessionsOfType(it.private).count() == 1) {
// The tab tray always returns to normal mode so do that here too // The tab tray always returns to normal mode so do that here too
activity.browsingModeManager.mode = BrowsingMode.Normal activity.browsingModeManager.mode = BrowsingMode.Normal
homeViewModel.sessionToDelete = it.id
navController.navigate( navController.navigate(
BrowserFragmentDirections.actionGlobalHome( BrowserFragmentDirections.actionGlobalHome()
sessionToDelete = it.id
)
) )
} else { } else {
onCloseTab.invoke(it) onCloseTab.invoke(it)

@ -33,7 +33,6 @@ import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -118,8 +117,8 @@ class HomeFragment : Fragment() {
private val args by navArgs<HomeFragmentArgs>() private val args by navArgs<HomeFragmentArgs>()
private lateinit var bundleArgs: Bundle private lateinit var bundleArgs: Bundle
private val homeViewModel: HomeScreenViewModel by viewModels { private val homeViewModel: HomeScreenViewModel by activityViewModels {
ViewModelProvider.AndroidViewModelFactory(requireActivity().application) ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
} }
private val snackbarAnchorView: View? private val snackbarAnchorView: View?
@ -452,7 +451,7 @@ class HomeFragment : Fragment() {
updateTabCounter(it) updateTabCounter(it)
} }
bundleArgs.getString(SESSION_TO_DELETE)?.also { homeViewModel.sessionToDelete?.also {
if (it == ALL_NORMAL_TABS || it == ALL_PRIVATE_TABS) { if (it == ALL_NORMAL_TABS || it == ALL_PRIVATE_TABS) {
removeAllTabsAndShowSnackbar(it) removeAllTabsAndShowSnackbar(it)
} else { } else {
@ -460,6 +459,8 @@ class HomeFragment : Fragment() {
} }
} }
homeViewModel.sessionToDelete = null
updateTabCounter(requireComponents.core.store.state) updateTabCounter(requireComponents.core.store.state)
if (bundleArgs.getBoolean(FOCUS_ON_ADDRESS_BAR)) { if (bundleArgs.getBoolean(FOCUS_ON_ADDRESS_BAR)) {
@ -989,7 +990,6 @@ class HomeFragment : Fragment() {
const val ALL_PRIVATE_TABS = "all_private" const val ALL_PRIVATE_TABS = "all_private"
private const val FOCUS_ON_ADDRESS_BAR = "focusOnAddressBar" private const val FOCUS_ON_ADDRESS_BAR = "focusOnAddressBar"
private const val SESSION_TO_DELETE = "session_to_delete"
private const val ANIMATION_DELAY = 100L private const val ANIMATION_DELAY = 100L
private const val NON_TAB_ITEM_NUM = 3 private const val NON_TAB_ITEM_NUM = 3

@ -8,6 +8,11 @@ import android.os.Parcelable
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
class HomeScreenViewModel : ViewModel() { class HomeScreenViewModel : ViewModel() {
/**
* Used to delete a specific session once the home screen is resumed
*/
var sessionToDelete: String? = null
var layoutManagerState: Parcelable? = null var layoutManagerState: Parcelable? = null
/** /**

@ -16,6 +16,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
@ -41,8 +43,8 @@ import mozilla.components.support.base.feature.UserInteractionHandler
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import mozilla.components.support.ktx.android.view.showKeyboard import mozilla.components.support.ktx.android.view.showKeyboard
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragmentDirections
import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.TabCollectionStorage import org.mozilla.fenix.components.TabCollectionStorage
@ -53,6 +55,7 @@ import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.normalSessionSize import org.mozilla.fenix.ext.normalSessionSize
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.home.HomeScreenViewModel
import org.mozilla.fenix.tabtray.TabTrayDialogFragmentState.Mode import org.mozilla.fenix.tabtray.TabTrayDialogFragmentState.Mode
import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.utils.allowUndo
@ -263,7 +266,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
val session = sessionManager.findSessionById(sessionId) ?: return val session = sessionManager.findSessionById(sessionId) ?: return
// Check if this is the last tab of this session type // Check if this is the last tab of this session type
val isLastOpenTab = store.state.tabs.filter { it.content.private == tab.content.private }.size == 1 val isLastOpenTab =
store.state.tabs.filter { it.content.private == tab.content.private }.size == 1
if (isLastOpenTab) { if (isLastOpenTab) {
dismissTabTrayAndNavigateHome(sessionId) dismissTabTrayAndNavigateHome(sessionId)
return return
@ -282,7 +286,11 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
snackbarMessage, snackbarMessage,
getString(R.string.snackbar_deleted_undo), getString(R.string.snackbar_deleted_undo),
{ {
sessionManager.add(session, isSelected, engineSessionState = tab.engineState.engineSessionState) sessionManager.add(
session,
isSelected,
engineSessionState = tab.engineState.engineSessionState
)
_tabTrayView?.scrollToTab(session.id) _tabTrayView?.scrollToTab(session.id)
}, },
operation = { }, operation = { },
@ -291,8 +299,13 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
) )
} }
private val homeViewModel: HomeScreenViewModel by activityViewModels {
ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
}
private fun dismissTabTrayAndNavigateHome(sessionId: String) { private fun dismissTabTrayAndNavigateHome(sessionId: String) {
val directions = BrowserFragmentDirections.actionGlobalHome(sessionToDelete = sessionId) homeViewModel.sessionToDelete = sessionId
val directions = NavGraphDirections.actionGlobalHome()
findNavController().navigate(directions) findNavController().navigate(directions)
dismissAllowingStateLoss() dismissAllowingStateLoss()
} }

@ -132,11 +132,6 @@
android:name="focusOnAddressBar" android:name="focusOnAddressBar"
android:defaultValue="false" android:defaultValue="false"
app:argType="boolean" /> app:argType="boolean" />
<argument
android:name="session_to_delete"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
</fragment> </fragment>
<dialog <dialog

@ -38,23 +38,39 @@ import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.HomeScreenViewModel
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
class DefaultBrowserToolbarControllerTest { class DefaultBrowserToolbarControllerTest {
@RelaxedMockK private lateinit var activity: HomeActivity @RelaxedMockK
@MockK(relaxUnitFun = true) private lateinit var navController: NavController private lateinit var activity: HomeActivity
@RelaxedMockK private lateinit var onTabCounterClicked: () -> Unit @MockK(relaxUnitFun = true)
@RelaxedMockK private lateinit var onCloseTab: (Session) -> Unit private lateinit var navController: NavController
@RelaxedMockK private lateinit var sessionManager: SessionManager @RelaxedMockK
@MockK(relaxUnitFun = true) private lateinit var engineView: EngineView private lateinit var onTabCounterClicked: () -> Unit
@MockK private lateinit var currentSession: Session @RelaxedMockK
@RelaxedMockK private lateinit var metrics: MetricController private lateinit var onCloseTab: (Session) -> Unit
@RelaxedMockK private lateinit var searchUseCases: SearchUseCases @RelaxedMockK
@RelaxedMockK private lateinit var sessionUseCases: SessionUseCases private lateinit var sessionManager: SessionManager
@RelaxedMockK private lateinit var browserAnimator: BrowserAnimator @MockK(relaxUnitFun = true)
@RelaxedMockK private lateinit var topSitesUseCase: TopSitesUseCases private lateinit var engineView: EngineView
@RelaxedMockK private lateinit var readerModeController: ReaderModeController @MockK
private lateinit var currentSession: Session
@RelaxedMockK
private lateinit var metrics: MetricController
@RelaxedMockK
private lateinit var searchUseCases: SearchUseCases
@RelaxedMockK
private lateinit var sessionUseCases: SessionUseCases
@RelaxedMockK
private lateinit var browserAnimator: BrowserAnimator
@RelaxedMockK
private lateinit var topSitesUseCase: TopSitesUseCases
@RelaxedMockK
private lateinit var readerModeController: ReaderModeController
@RelaxedMockK
private lateinit var homeViewModel: HomeScreenViewModel
@Before @Before
fun setUp() { fun setUp() {
@ -193,7 +209,10 @@ class DefaultBrowserToolbarControllerTest {
val controller = createController() val controller = createController()
controller.handleTabCounterItemInteraction(item) controller.handleTabCounterItemInteraction(item)
verify { navController.navigate(BrowserFragmentDirections.actionGlobalHome(sessionToDelete = "1")) } verify {
homeViewModel.sessionToDelete = "1"
navController.navigate(BrowserFragmentDirections.actionGlobalHome())
}
assertEquals(BrowsingMode.Normal, browsingModeManager.mode) assertEquals(BrowsingMode.Normal, browsingModeManager.mode)
} }
@ -262,7 +281,7 @@ class DefaultBrowserToolbarControllerTest {
navController = navController, navController = navController,
metrics = metrics, metrics = metrics,
engineView = engineView, engineView = engineView,
browserAnimator = browserAnimator, homeViewModel = homeViewModel,
customTabSession = customTabSession, customTabSession = customTabSession,
readerModeController = readerModeController, readerModeController = readerModeController,
sessionManager = sessionManager, sessionManager = sessionManager,

Loading…
Cancel
Save