Fix #8651 - Add new menu actions for a history item
We'll now also support: - Copy url - Share to another FXA device - Open in new tab - Open in private tabmaster
parent
b77f92f9d1
commit
a1cdd31f0c
|
@ -6,25 +6,40 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.library.history
|
package org.mozilla.fenix.library.history
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.res.Resources
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import mozilla.components.concept.engine.prompt.ShareData
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
|
|
||||||
interface HistoryController {
|
interface HistoryController {
|
||||||
fun handleOpen(item: HistoryItem)
|
fun handleOpen(item: HistoryItem, mode: BrowsingMode? = null)
|
||||||
fun handleSelect(item: HistoryItem)
|
fun handleSelect(item: HistoryItem)
|
||||||
fun handleDeselect(item: HistoryItem)
|
fun handleDeselect(item: HistoryItem)
|
||||||
fun handleBackPressed(): Boolean
|
fun handleBackPressed(): Boolean
|
||||||
fun handleModeSwitched()
|
fun handleModeSwitched()
|
||||||
fun handleDeleteAll()
|
fun handleDeleteAll()
|
||||||
fun handleDeleteSome(items: Set<HistoryItem>)
|
fun handleDeleteSome(items: Set<HistoryItem>)
|
||||||
|
fun handleCopyUrl(item: HistoryItem)
|
||||||
|
fun handleShare(item: HistoryItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultHistoryController(
|
class DefaultHistoryController(
|
||||||
private val store: HistoryFragmentStore,
|
private val store: HistoryFragmentStore,
|
||||||
private val openToBrowser: (item: HistoryItem) -> Unit,
|
private val navController: NavController,
|
||||||
|
private val resources: Resources,
|
||||||
|
private val snackbar: FenixSnackbar,
|
||||||
|
private val clipboardManager: ClipboardManager,
|
||||||
|
private val openToBrowser: (item: HistoryItem, mode: BrowsingMode?) -> Unit,
|
||||||
private val displayDeleteAll: () -> Unit,
|
private val displayDeleteAll: () -> Unit,
|
||||||
private val invalidateOptionsMenu: () -> Unit,
|
private val invalidateOptionsMenu: () -> Unit,
|
||||||
private val deleteHistoryItems: (Set<HistoryItem>) -> Unit
|
private val deleteHistoryItems: (Set<HistoryItem>) -> Unit
|
||||||
) : HistoryController {
|
) : HistoryController {
|
||||||
override fun handleOpen(item: HistoryItem) {
|
override fun handleOpen(item: HistoryItem, mode: BrowsingMode?) {
|
||||||
openToBrowser(item)
|
openToBrowser(item, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleSelect(item: HistoryItem) {
|
override fun handleSelect(item: HistoryItem) {
|
||||||
|
@ -55,4 +70,21 @@ class DefaultHistoryController(
|
||||||
override fun handleDeleteSome(items: Set<HistoryItem>) {
|
override fun handleDeleteSome(items: Set<HistoryItem>) {
|
||||||
deleteHistoryItems.invoke(items)
|
deleteHistoryItems.invoke(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handleCopyUrl(item: HistoryItem) {
|
||||||
|
val urlClipData = ClipData.newPlainText(item.url, item.url)
|
||||||
|
clipboardManager.primaryClip = urlClipData
|
||||||
|
with(snackbar) {
|
||||||
|
setText(resources.getString(R.string.url_copied))
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleShare(item: HistoryItem) {
|
||||||
|
navController.navigate(
|
||||||
|
HistoryFragmentDirections.actionHistoryFragmentToShareFragment(
|
||||||
|
data = arrayOf(ShareData(url = item.url, title = item.title))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.library.history
|
package org.mozilla.fenix.library.history
|
||||||
|
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -15,6 +17,7 @@ import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
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_history.view.*
|
import kotlinx.android.synthetic.main.fragment_history.view.*
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
@ -27,6 +30,7 @@ import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.components.Components
|
import org.mozilla.fenix.components.Components
|
||||||
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.StoreProvider
|
import org.mozilla.fenix.components.StoreProvider
|
||||||
import org.mozilla.fenix.components.history.createSynchronousPagedHistoryProvider
|
import org.mozilla.fenix.components.history.createSynchronousPagedHistoryProvider
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
@ -58,6 +62,10 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
|
||||||
}
|
}
|
||||||
val historyController: HistoryController = DefaultHistoryController(
|
val historyController: HistoryController = DefaultHistoryController(
|
||||||
historyStore,
|
historyStore,
|
||||||
|
findNavController(),
|
||||||
|
resources,
|
||||||
|
FenixSnackbar.make(view, FenixSnackbar.LENGTH_LONG),
|
||||||
|
activity?.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager,
|
||||||
::openItem,
|
::openItem,
|
||||||
::displayDeleteAllDialog,
|
::displayDeleteAllDialog,
|
||||||
::invalidateOptionsMenu,
|
::invalidateOptionsMenu,
|
||||||
|
@ -183,8 +191,11 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean = historyView.onBackPressed()
|
override fun onBackPressed(): Boolean = historyView.onBackPressed()
|
||||||
|
|
||||||
private fun openItem(item: HistoryItem) {
|
private fun openItem(item: HistoryItem, mode: BrowsingMode? = null) {
|
||||||
requireComponents.analytics.metrics.track(Event.HistoryItemOpened)
|
requireComponents.analytics.metrics.track(Event.HistoryItemOpened)
|
||||||
|
|
||||||
|
mode?.let { (activity as HomeActivity).browsingModeManager.mode = it }
|
||||||
|
|
||||||
(activity as HomeActivity).openToBrowserAndLoad(
|
(activity as HomeActivity).openToBrowserAndLoad(
|
||||||
searchTermOrURL = item.url,
|
searchTermOrURL = item.url,
|
||||||
newTab = true,
|
newTab = true,
|
||||||
|
|
|
@ -4,10 +4,13 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.library.history
|
package org.mozilla.fenix.library.history
|
||||||
|
|
||||||
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interactor for the history screen
|
* Interactor for the history screen
|
||||||
* Provides implementations for the HistoryViewInteractor
|
* Provides implementations for the HistoryViewInteractor
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("TooManyFunctions")
|
||||||
class HistoryInteractor(
|
class HistoryInteractor(
|
||||||
private val historyController: HistoryController
|
private val historyController: HistoryController
|
||||||
) : HistoryViewInteractor {
|
) : HistoryViewInteractor {
|
||||||
|
@ -31,6 +34,22 @@ class HistoryInteractor(
|
||||||
historyController.handleModeSwitched()
|
historyController.handleModeSwitched()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCopyPressed(item: HistoryItem) {
|
||||||
|
historyController.handleCopyUrl(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharePressed(item: HistoryItem) {
|
||||||
|
historyController.handleShare(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOpenInNormalTab(item: HistoryItem) {
|
||||||
|
historyController.handleOpen(item, BrowsingMode.Normal)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOpenInPrivateTab(item: HistoryItem) {
|
||||||
|
historyController.handleOpen(item, BrowsingMode.Private)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDeleteAll() {
|
override fun onDeleteAll() {
|
||||||
historyController.handleDeleteAll()
|
historyController.handleDeleteAll()
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,29 @@ class HistoryItemMenu(
|
||||||
private val onItemTapped: (Item) -> Unit = {}
|
private val onItemTapped: (Item) -> Unit = {}
|
||||||
) : LibraryItemMenu {
|
) : LibraryItemMenu {
|
||||||
sealed class Item {
|
sealed class Item {
|
||||||
|
object Copy : Item()
|
||||||
|
object Share : Item()
|
||||||
|
object OpenInNewTab : Item()
|
||||||
|
object OpenInPrivateTab : Item()
|
||||||
object Delete : Item()
|
object Delete : Item()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val menuBuilder by lazy { BrowserMenuBuilder(menuItems) }
|
override val menuBuilder by lazy { BrowserMenuBuilder(menuItems) }
|
||||||
|
|
||||||
private val menuItems by lazy {
|
private val menuItems by lazy {
|
||||||
listOf(
|
listOfNotNull(
|
||||||
|
SimpleBrowserMenuItem(context.getString(R.string.history_menu_copy_button)) {
|
||||||
|
onItemTapped.invoke(Item.Copy)
|
||||||
|
},
|
||||||
|
SimpleBrowserMenuItem(context.getString(R.string.history_menu_share_button)) {
|
||||||
|
onItemTapped.invoke(Item.Share)
|
||||||
|
},
|
||||||
|
SimpleBrowserMenuItem(context.getString(R.string.history_menu_open_in_new_tab_button)) {
|
||||||
|
onItemTapped.invoke(Item.OpenInNewTab)
|
||||||
|
},
|
||||||
|
SimpleBrowserMenuItem(context.getString(R.string.history_menu_open_in_private_tab_button)) {
|
||||||
|
onItemTapped.invoke(Item.OpenInPrivateTab)
|
||||||
|
},
|
||||||
SimpleBrowserMenuItem(
|
SimpleBrowserMenuItem(
|
||||||
context.getString(R.string.history_delete_item),
|
context.getString(R.string.history_delete_item),
|
||||||
textColorResource = ThemeManager.resolveAttribute(R.attr.destructive, context)
|
textColorResource = ThemeManager.resolveAttribute(R.attr.destructive, context)
|
||||||
|
|
|
@ -33,6 +33,34 @@ interface HistoryViewInteractor : SelectionInteractor<HistoryItem> {
|
||||||
*/
|
*/
|
||||||
fun onModeSwitched()
|
fun onModeSwitched()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the URL of a history item to the copy-paste buffer.
|
||||||
|
*
|
||||||
|
* @param item the history item to copy the URL from
|
||||||
|
*/
|
||||||
|
fun onCopyPressed(item: HistoryItem)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the share sheet for a history item.
|
||||||
|
*
|
||||||
|
* @param item the history item to share
|
||||||
|
*/
|
||||||
|
fun onSharePressed(item: HistoryItem)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a history item in a new tab.
|
||||||
|
*
|
||||||
|
* @param item the history item to open in a new tab
|
||||||
|
*/
|
||||||
|
fun onOpenInNormalTab(item: HistoryItem)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a history item in a private tab.
|
||||||
|
*
|
||||||
|
* @param item the history item to open in a private tab
|
||||||
|
*/
|
||||||
|
fun onOpenInPrivateTab(item: HistoryItem)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when delete all is tapped
|
* Called when delete all is tapped
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,6 +11,7 @@ import kotlinx.android.synthetic.main.library_site_item.view.*
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.hideAndDisable
|
import org.mozilla.fenix.ext.hideAndDisable
|
||||||
import org.mozilla.fenix.ext.showAndEnable
|
import org.mozilla.fenix.ext.showAndEnable
|
||||||
|
import org.mozilla.fenix.lib.Do
|
||||||
import org.mozilla.fenix.library.SelectionHolder
|
import org.mozilla.fenix.library.SelectionHolder
|
||||||
import org.mozilla.fenix.library.history.HistoryFragmentState
|
import org.mozilla.fenix.library.history.HistoryFragmentState
|
||||||
import org.mozilla.fenix.library.history.HistoryInteractor
|
import org.mozilla.fenix.library.history.HistoryInteractor
|
||||||
|
@ -98,7 +99,12 @@ class HistoryListItemViewHolder(
|
||||||
private fun setupMenu() {
|
private fun setupMenu() {
|
||||||
val historyMenu = HistoryItemMenu(itemView.context) {
|
val historyMenu = HistoryItemMenu(itemView.context) {
|
||||||
val item = this.item ?: return@HistoryItemMenu
|
val item = this.item ?: return@HistoryItemMenu
|
||||||
when (it) {
|
|
||||||
|
Do exhaustive when (it) {
|
||||||
|
HistoryItemMenu.Item.Copy -> historyInteractor.onCopyPressed(item)
|
||||||
|
HistoryItemMenu.Item.Share -> historyInteractor.onSharePressed(item)
|
||||||
|
HistoryItemMenu.Item.OpenInNewTab -> historyInteractor.onOpenInNormalTab(item)
|
||||||
|
HistoryItemMenu.Item.OpenInPrivateTab -> historyInteractor.onOpenInPrivateTab(item)
|
||||||
HistoryItemMenu.Item.Delete -> historyInteractor.onDeleteSome(setOf(item))
|
HistoryItemMenu.Item.Delete -> historyInteractor.onDeleteSome(setOf(item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,6 +454,14 @@
|
||||||
<string name="history_delete_all_dialog">Are you sure you want to clear your history?</string>
|
<string name="history_delete_all_dialog">Are you sure you want to clear your history?</string>
|
||||||
<!-- Text for positive action to delete history in deleting history dialog -->
|
<!-- Text for positive action to delete history in deleting history dialog -->
|
||||||
<string name="history_clear_dialog">Clear</string>
|
<string name="history_clear_dialog">Clear</string>
|
||||||
|
<!-- History overflow menu copy button -->
|
||||||
|
<string name="history_menu_copy_button">Copy</string>
|
||||||
|
<!-- History overflow menu share button -->
|
||||||
|
<string name="history_menu_share_button">Share</string>
|
||||||
|
<!-- History overflow menu open in new tab button -->
|
||||||
|
<string name="history_menu_open_in_new_tab_button">Open in new tab</string>
|
||||||
|
<!-- History overflow menu open in private tab button -->
|
||||||
|
<string name="history_menu_open_in_private_tab_button">Open in private tab</string>
|
||||||
<!-- Text for the button to delete a single history item -->
|
<!-- Text for the button to delete a single history item -->
|
||||||
<string name="history_delete_item">Delete</string>
|
<string name="history_delete_item">Delete</string>
|
||||||
<!-- History multi select title in app bar
|
<!-- History multi select title in app bar
|
||||||
|
|
Loading…
Reference in New Issue