Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
For #10865 - Implement 3 dot menu for tab tray (#10869)
Browse files Browse the repository at this point in the history
  • Loading branch information
darkwing authored May 27, 2020
1 parent 54cb8f0 commit 2482372
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 7 deletions.
92 changes: 92 additions & 0 deletions app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.navigation.fragment.findNavController
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_browser.*
import kotlinx.android.synthetic.main.fragment_browser.view.*
import kotlinx.android.synthetic.main.tab_header.view.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
Expand Down Expand Up @@ -71,6 +72,7 @@ import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.FindInPageIntegration
import org.mozilla.fenix.components.StoreProvider
Expand All @@ -96,6 +98,7 @@ import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.home.SharedViewModel
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.allowUndo
import org.mozilla.fenix.wifi.SitePermissionsWifiIntegration
import java.lang.ref.WeakReference

Expand All @@ -117,6 +120,9 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
protected val browserToolbarView: BrowserToolbarView
get() = _browserToolbarView!!

private val sessionManager: SessionManager
get() = requireComponents.core.sessionManager

protected val readerViewFeature = ViewBoundFeatureWrapper<ReaderViewFeature>()

private val sessionFeature = ViewBoundFeatureWrapper<SessionFeature>()
Expand Down Expand Up @@ -225,6 +231,75 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
tabTrayDialog.dismiss()
findNavController().navigate(BrowserFragmentDirections.actionGlobalHome())
}

override fun onShareTabsClicked(private: Boolean) {
share(getListOfSessions(private))
}

override fun onCloseAllTabsClicked(private: Boolean) {
val tabs = getListOfSessions(private)

val selectedIndex = sessionManager
.selectedSession?.let { sessionManager.sessions.indexOf(it) } ?: 0

val snapshot = tabs
.map(sessionManager::createSessionSnapshot)
.map {
it.copy(engineSession = null, engineSessionState = it.engineSession?.saveState())
}
.let { SessionManager.Snapshot(it, selectedIndex) }

tabs.forEach {
sessionManager.remove(it)
}

val isPrivate = (activity as HomeActivity).browsingModeManager.mode.isPrivate
val snackbarMessage = if (isPrivate) {
getString(R.string.snackbar_private_tabs_closed)
} else {
getString(R.string.snackbar_tabs_closed)
}

viewLifecycleOwner.lifecycleScope.allowUndo(
requireView(),
snackbarMessage,
getString(R.string.snackbar_deleted_undo),
{
sessionManager.restore(snapshot)
},
operation = { },
anchorView = view.tabs_header
)
}

override fun onSaveToCollectionClicked() {
val tabs = getListOfSessions(false)
val tabIds = tabs.map { it.id }.toList().toTypedArray()
val tabCollectionStorage = (activity as HomeActivity).components.core.tabCollectionStorage
val navController = findNavController()

val step = when {
// Show the SelectTabs fragment if there are multiple opened tabs to select which tabs
// you want to save to a collection.
tabs.size > 1 -> SaveCollectionStep.SelectTabs
// If there is an existing tab collection, show the SelectCollection fragment to save
// the selected tab to a collection of your choice.
tabCollectionStorage.cachedTabCollections.isNotEmpty() ->
SaveCollectionStep.SelectCollection
// Show the NameCollection fragment to create a new collection for the selected tab.
else -> SaveCollectionStep.NameCollection
}

if (navController.currentDestination?.id == R.id.collectionCreationFragment) return

val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment(
tabIds = tabIds,
previousFragmentId = R.id.tabTrayFragment,
saveCollectionStep = step,
selectedTabIds = tabIds
)
navController.nav(R.id.browserFragment, directions)
}
}
}
)
Expand Down Expand Up @@ -965,6 +1040,23 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
}
}

private fun share(tabs: List<Session>) {
val data = tabs.map {
ShareData(url = it.url, title = it.title)
}
val directions = BrowserFragmentDirections.actionGlobalShareFragment(
data = data.toTypedArray()
)
nav(R.id.browserFragment, directions)
}

private fun getListOfSessions(
private: Boolean = (activity as HomeActivity).browsingModeManager.mode.isPrivate
): List<Session> {
return requireComponents.core.sessionManager.sessionsOfType(private = private)
.toList()
}

/*
* Dereference these views when the fragment view is destroyed to prevent memory leaks
*/
Expand Down
83 changes: 81 additions & 2 deletions app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.android.synthetic.main.tab_header.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
Expand All @@ -59,6 +60,7 @@ import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.browser.state.state.MediaState.State.PLAYING
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.sync.AccountObserver
import mozilla.components.concept.sync.AuthType
import mozilla.components.concept.sync.OAuthAccount
Expand All @@ -75,6 +77,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.addons.runIfFragmentIsAttached
import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.PrivateShortcutCreateManager
import org.mozilla.fenix.components.StoreProvider
Expand Down Expand Up @@ -371,6 +374,72 @@ class HomeFragment : Fragment() {
(activity as HomeActivity).browsingModeManager.mode = BrowsingMode.fromBoolean(private)
tabTrayDialog.dismiss()
}

override fun onShareTabsClicked(private: Boolean) {
share(getListOfSessions(private))
}

override fun onCloseAllTabsClicked(private: Boolean) {
val tabs = getListOfSessions(private)

val selectedIndex = sessionManager
.selectedSession?.let { sessionManager.sessions.indexOf(it) } ?: 0

val snapshot = tabs
.map(sessionManager::createSessionSnapshot)
.map { it.copy(engineSession = null, engineSessionState = it.engineSession?.saveState()) }
.let { SessionManager.Snapshot(it, selectedIndex) }

tabs.forEach {
sessionManager.remove(it)
}

val isPrivate = (activity as HomeActivity).browsingModeManager.mode.isPrivate
val snackbarMessage = if (isPrivate) {
getString(R.string.snackbar_private_tabs_closed)
} else {
getString(R.string.snackbar_tabs_closed)
}

viewLifecycleOwner.lifecycleScope.allowUndo(
requireView(),
snackbarMessage,
getString(R.string.snackbar_deleted_undo),
{
sessionManager.restore(snapshot)
},
operation = { },
anchorView = view.tabs_header
)
}

override fun onSaveToCollectionClicked() {
val tabs = getListOfSessions(false)
val tabIds = tabs.map { it.id }.toList().toTypedArray()
val tabCollectionStorage = (activity as HomeActivity).components.core.tabCollectionStorage
val navController = findNavController()

val step = when {
// Show the SelectTabs fragment if there are multiple opened tabs to select which tabs
// you want to save to a collection.
tabs.size > 1 -> SaveCollectionStep.SelectTabs
// If there is an existing tab collection, show the SelectCollection fragment to save
// the selected tab to a collection of your choice.
tabCollectionStorage.cachedTabCollections.isNotEmpty() -> SaveCollectionStep.SelectCollection
// Show the NameCollection fragment to create a new collection for the selected tab.
else -> SaveCollectionStep.NameCollection
}

if (navController.currentDestination?.id == R.id.collectionCreationFragment) return

val directions = HomeFragmentDirections.actionHomeFragmentToCreateCollectionFragment(
tabIds = tabIds,
previousFragmentId = R.id.tabTrayFragment,
saveCollectionStep = step,
selectedTabIds = tabIds
)
navController.nav(R.id.homeFragment, directions)
}
}
}

Expand Down Expand Up @@ -846,8 +915,8 @@ class HomeFragment : Fragment() {
}
}

private fun getListOfSessions(): List<Session> {
return sessionManager.sessionsOfType(private = browsingModeManager.mode.isPrivate)
private fun getListOfSessions(private: Boolean = browsingModeManager.mode.isPrivate): List<Session> {
return sessionManager.sessionsOfType(private = private)
.filter { session: Session -> session.id != pendingSessionDeletion?.sessionId }
.toList()
}
Expand Down Expand Up @@ -1022,6 +1091,16 @@ class HomeFragment : Fragment() {
}
}

private fun share(tabs: List<Session>) {
val data = tabs.map {
ShareData(url = it.url, title = it.title)
}
val directions = HomeFragmentDirections.actionGlobalShareFragment(
data = data.toTypedArray()
)
nav(R.id.homeFragment, directions)
}

companion object {
private const val ANIMATION_DELAY = 100L

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import kotlinx.android.synthetic.main.component_tabstray.view.*
import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.*
import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.view.*
import mozilla.components.concept.tabstray.Tab
import mozilla.components.lib.state.ext.consumeFrom
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
Expand All @@ -25,6 +26,9 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), TabTrayInteractor {
interface Interactor {
fun onTabSelected(tab: Tab)
fun onNewTabTapped(private: Boolean)
fun onShareTabsClicked(private: Boolean)
fun onSaveToCollectionClicked()
fun onCloseAllTabsClicked(private: Boolean)
}

private lateinit var tabTrayView: TabTrayView
Expand All @@ -49,7 +53,9 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), TabTrayInteractor {
(activity as HomeActivity).browsingModeManager.mode.isPrivate
)

tabLayout.setOnClickListener { dismissAllowingStateLoss() }
tabLayout.setOnClickListener {
dismissAllowingStateLoss()
}

view.tabLayout.setOnApplyWindowInsetsListener { v, insets ->
v.updatePadding(
Expand All @@ -64,6 +70,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), TabTrayInteractor {

insets
}

consumeFrom(requireComponents.core.store) { tabTrayView.updateState(it) }
}

override fun onTabClosed(tab: Tab) {
Expand Down Expand Up @@ -108,6 +116,18 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), TabTrayInteractor {
dismissAllowingStateLoss()
}

override fun onShareTabsClicked(private: Boolean) {
interactor?.onShareTabsClicked(private)
}

override fun onSaveToCollectionClicked() {
interactor?.onSaveToCollectionClicked()
}

override fun onCloseAllTabsClicked(private: Boolean) {
interactor?.onCloseAllTabsClicked(private)
}

companion object {
private const val ELEVATION = 80f
}
Expand Down
Loading

0 comments on commit 2482372

Please sign in to comment.