For #16629 - Fix for collection snackbar View button (#16679)

upstream-sync
Codrut Topliceanu 4 years ago committed by GitHub
parent 8a579ee62b
commit 79d1c08402
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -247,7 +247,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
} }
private val collectionStorageObserver = object : TabCollectionStorage.Observer { private val collectionStorageObserver = object : TabCollectionStorage.Observer {
override fun onCollectionCreated(title: String, sessions: List<Session>) { override fun onCollectionCreated(title: String, sessions: List<Session>, id: Long?) {
showTabSavedToCollectionSnackbar(sessions.size, true) showTabSavedToCollectionSnackbar(sessions.size, true)
} }

@ -40,7 +40,7 @@ class TabCollectionStorage(
/** /**
* A collection has been created * A collection has been created
*/ */
fun onCollectionCreated(title: String, sessions: List<Session>) = Unit fun onCollectionCreated(title: String, sessions: List<Session>, id: Long?) = Unit
/** /**
* Tab(s) have been added to collection * Tab(s) have been added to collection
@ -63,8 +63,8 @@ class TabCollectionStorage(
} }
suspend fun createCollection(title: String, sessions: List<Session>) = ioScope.launch { suspend fun createCollection(title: String, sessions: List<Session>) = ioScope.launch {
collectionStorage.createCollection(title, sessions) val id = collectionStorage.createCollection(title, sessions)
notifyObservers { onCollectionCreated(title, sessions) } notifyObservers { onCollectionCreated(title, sessions, id) }
}.join() }.join()
suspend fun addTabsToCollection(tabCollection: TabCollection, sessions: List<Session>) = ioScope.launch { suspend fun addTabsToCollection(tabCollection: TabCollection, sessions: List<Session>) = ioScope.launch {

@ -39,6 +39,7 @@ import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_home.privateBrowsingButton import kotlinx.android.synthetic.main.fragment_home.privateBrowsingButton
import kotlinx.android.synthetic.main.fragment_home.search_engine_icon import kotlinx.android.synthetic.main.fragment_home.search_engine_icon
@ -62,10 +63,8 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.menu.view.MenuButton import mozilla.components.browser.menu.view.MenuButton
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.SessionManager
import mozilla.components.browser.state.selector.findTab import mozilla.components.browser.state.selector.findTab
import mozilla.components.browser.state.selector.getNormalOrPrivateTabs
import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.selector.normalTabs
import mozilla.components.browser.state.selector.privateTabs import mozilla.components.browser.state.selector.privateTabs
import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.BrowserState
@ -137,14 +136,6 @@ class HomeFragment : Fragment() {
private val browsingModeManager get() = (activity as HomeActivity).browsingModeManager private val browsingModeManager get() = (activity as HomeActivity).browsingModeManager
private val collectionStorageObserver = object : TabCollectionStorage.Observer { private val collectionStorageObserver = object : TabCollectionStorage.Observer {
override fun onCollectionCreated(title: String, sessions: List<Session>) {
scrollAndAnimateCollection()
}
override fun onTabsAdded(tabCollection: TabCollection, sessions: List<Session>) {
scrollAndAnimateCollection(tabCollection)
}
override fun onCollectionRenamed(tabCollection: TabCollection, title: String) { override fun onCollectionRenamed(tabCollection: TabCollection, title: String) {
lifecycleScope.launch(Main) { lifecycleScope.launch(Main) {
view?.sessionControlRecyclerView?.adapter?.notifyDataSetChanged() view?.sessionControlRecyclerView?.adapter?.notifyDataSetChanged()
@ -170,6 +161,7 @@ class HomeFragment : Fragment() {
get() = _sessionControlInteractor!! get() = _sessionControlInteractor!!
private var sessionControlView: SessionControlView? = null private var sessionControlView: SessionControlView? = null
private var appBarLayout: AppBarLayout? = null
private lateinit var currentMode: CurrentMode private lateinit var currentMode: CurrentMode
private val topSitesFeature = ViewBoundFeatureWrapper<TopSitesFeature>() private val topSitesFeature = ViewBoundFeatureWrapper<TopSitesFeature>()
@ -267,6 +259,8 @@ class HomeFragment : Fragment() {
updateSessionControlView(view) updateSessionControlView(view)
appBarLayout = view.homeAppBar
activity.themeManager.applyStatusBarTheme(activity) activity.themeManager.applyStatusBarTheme(activity)
return view return view
} }
@ -442,6 +436,12 @@ class HomeFragment : Fragment() {
if (bundleArgs.getBoolean(FOCUS_ON_ADDRESS_BAR)) { if (bundleArgs.getBoolean(FOCUS_ON_ADDRESS_BAR)) {
navigateToSearch() navigateToSearch()
} else if (bundleArgs.getLong(FOCUS_ON_COLLECTION, -1) >= 0) {
// No need to scroll to async'd loaded TopSites if we want to scroll to collections.
homeViewModel.shouldScrollToTopSites = false
/* Triggered when the user has added a tab to a collection and has tapped
* the View action on the [TabsTrayDialogFragment] snackbar.*/
scrollAndAnimateCollection(bundleArgs.getLong(FOCUS_ON_COLLECTION, -1))
} }
} }
@ -848,31 +848,23 @@ class HomeFragment : Fragment() {
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this) requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
} }
/**
* This method will find and scroll to the row of the specified collection Id.
* */
private fun scrollAndAnimateCollection( private fun scrollAndAnimateCollection(
changedCollection: TabCollection? = null collectionIdToSelect: Long = -1
) { ) {
if (view != null) { if (view != null && collectionIdToSelect >= 0) {
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
val recyclerView = sessionControlView!!.view val recyclerView = sessionControlView!!.view
delay(ANIM_SCROLL_DELAY) delay(ANIM_SCROLL_DELAY)
val tabsSize = store.state val indexOfCollection =
.getNormalOrPrivateTabs(browsingModeManager.mode.isPrivate) NON_COLLECTION_ITEM_NUM + findIndexOfSpecificCollection(collectionIdToSelect)
.size
var indexOfCollection = tabsSize + NON_TAB_ITEM_NUM
changedCollection?.let { changedCollection ->
requireComponents.core.tabCollectionStorage.cachedTabCollections
.filterIndexed { index, tabCollection ->
if (tabCollection.id == changedCollection.id) {
indexOfCollection = tabsSize + NON_TAB_ITEM_NUM + index
return@filterIndexed true
}
false
}
}
val lastVisiblePosition = val lastVisiblePosition =
(recyclerView.layoutManager as? LinearLayoutManager)?.findLastCompletelyVisibleItemPosition() (recyclerView.layoutManager as? LinearLayoutManager)?.findLastCompletelyVisibleItemPosition()
?: 0 ?: 0
if (lastVisiblePosition < indexOfCollection) { if (lastVisiblePosition < indexOfCollection) {
val onScrollListener = object : RecyclerView.OnScrollListener() { val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged( override fun onScrollStateChanged(
@ -881,6 +873,7 @@ class HomeFragment : Fragment() {
) { ) {
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
if (newState == SCROLL_STATE_IDLE) { if (newState == SCROLL_STATE_IDLE) {
appBarLayout?.setExpanded(false)
animateCollection(indexOfCollection) animateCollection(indexOfCollection)
recyclerView.removeOnScrollListener(this) recyclerView.removeOnScrollListener(this)
} }
@ -889,12 +882,34 @@ class HomeFragment : Fragment() {
recyclerView.addOnScrollListener(onScrollListener) recyclerView.addOnScrollListener(onScrollListener)
recyclerView.smoothScrollToPosition(indexOfCollection) recyclerView.smoothScrollToPosition(indexOfCollection)
} else { } else {
appBarLayout?.setExpanded(false)
animateCollection(indexOfCollection) animateCollection(indexOfCollection)
} }
} }
} }
} }
/**
* Returns index of the collection with the specified id.
* */
private fun findIndexOfSpecificCollection(
changedCollectionId: Long
): Int {
var result = 0
requireComponents.core.tabCollectionStorage.cachedTabCollections
.filterIndexed { index, tabCollection ->
if (tabCollection.id == changedCollectionId) {
result = index
return@filterIndexed true
}
false
}
return result
}
/**
* Will highlight the border of the collection with the specified index.
* */
private fun animateCollection(indexOfCollection: Int) { private fun animateCollection(indexOfCollection: Int) {
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
val viewHolder = val viewHolder =
@ -921,24 +936,6 @@ class HomeFragment : Fragment() {
border?.animate()?.alpha(1.0F)?.setStartDelay(ANIM_ON_SCREEN_DELAY) border?.animate()?.alpha(1.0F)?.setStartDelay(ANIM_ON_SCREEN_DELAY)
?.setDuration(FADE_ANIM_DURATION) ?.setDuration(FADE_ANIM_DURATION)
?.setListener(listener)?.start() ?.setListener(listener)?.start()
}.invokeOnCompletion {
showSavedSnackbar()
}
}
private fun showSavedSnackbar() {
viewLifecycleOwner.lifecycleScope.launch {
delay(ANIM_SNACKBAR_DELAY)
view?.let { view ->
FenixSnackbar.make(
view = view,
duration = Snackbar.LENGTH_LONG,
isDisplayedWithBrowserToolbar = false
)
.setText(view.context.getString(R.string.create_collection_tabs_saved_new_collection))
.setAnchorView(snackbarAnchorView)
.show()
}
} }
} }
@ -983,13 +980,18 @@ 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 FOCUS_ON_COLLECTION = "focusOnCollection"
private const val ANIMATION_DELAY = 100L private const val ANIMATION_DELAY = 100L
private const val NON_TAB_ITEM_NUM = 3 /**
* Represents the number of items in [sessionControlView] that are NOT part of
* the list of collections. At the moment these are topSites pager, collections header.
* */
private const val NON_COLLECTION_ITEM_NUM = 2
private const val ANIM_SCROLL_DELAY = 100L private const val ANIM_SCROLL_DELAY = 100L
private const val ANIM_ON_SCREEN_DELAY = 200L private const val ANIM_ON_SCREEN_DELAY = 200L
private const val FADE_ANIM_DURATION = 150L private const val FADE_ANIM_DURATION = 150L
private const val ANIM_SNACKBAR_DELAY = 100L
private const val CFR_WIDTH_DIVIDER = 1.7 private const val CFR_WIDTH_DIVIDER = 1.7
private const val CFR_Y_OFFSET = -20 private const val CFR_Y_OFFSET = -20
} }

@ -86,12 +86,15 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
else null else null
private val collectionStorageObserver = object : TabCollectionStorage.Observer { private val collectionStorageObserver = object : TabCollectionStorage.Observer {
override fun onCollectionCreated(title: String, sessions: List<Session>) { override fun onCollectionCreated(title: String, sessions: List<Session>, id: Long?) {
showCollectionSnackbar(sessions.size, true) showCollectionSnackbar(sessions.size, true, collectionToSelect = id)
} }
override fun onTabsAdded(tabCollection: TabCollection, sessions: List<Session>) { override fun onTabsAdded(tabCollection: TabCollection, sessions: List<Session>) {
showCollectionSnackbar(sessions.size) showCollectionSnackbar(
sessions.size,
collectionToSelect = tabCollection.id
)
} }
} }
@ -354,7 +357,11 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this) requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
} }
private fun showCollectionSnackbar(tabSize: Int, isNewCollection: Boolean = false) { private fun showCollectionSnackbar(
tabSize: Int,
isNewCollection: Boolean = false,
collectionToSelect: Long?
) {
view.let { view.let {
val messageStringRes = when { val messageStringRes = when {
isNewCollection -> { isNewCollection -> {
@ -378,7 +385,10 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
.setAction(requireContext().getString(R.string.create_collection_view)) { .setAction(requireContext().getString(R.string.create_collection_view)) {
dismissAllowingStateLoss() dismissAllowingStateLoss()
findNavController().navigate( findNavController().navigate(
TabTrayDialogFragmentDirections.actionGlobalHome(focusOnAddressBar = false) TabTrayDialogFragmentDirections.actionGlobalHome(
focusOnAddressBar = false,
focusOnCollection = collectionToSelect ?: -1L
)
) )
} }

@ -138,6 +138,10 @@
android:name="focusOnAddressBar" android:name="focusOnAddressBar"
android:defaultValue="false" android:defaultValue="false"
app:argType="boolean" /> app:argType="boolean" />
<argument
android:name="focusOnCollection"
android:defaultValue="-1L"
app:argType="long" />
</fragment> </fragment>
<dialog <dialog

Loading…
Cancel
Save