|
|
@ -4,6 +4,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
package org.mozilla.fenix.library.historymetadata
|
|
|
|
package org.mozilla.fenix.library.historymetadata
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
|
|
|
|
import android.content.DialogInterface
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.text.SpannableString
|
|
|
|
import android.text.SpannableString
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.LayoutInflater
|
|
|
@ -12,13 +14,19 @@ import android.view.MenuInflater
|
|
|
|
import android.view.MenuItem
|
|
|
|
import android.view.MenuItem
|
|
|
|
import android.view.View
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
|
|
|
import android.view.ViewGroup
|
|
|
|
import androidx.lifecycle.lifecycleScope
|
|
|
|
import androidx.appcompat.app.AlertDialog
|
|
|
|
import androidx.navigation.fragment.findNavController
|
|
|
|
import androidx.navigation.fragment.findNavController
|
|
|
|
import androidx.navigation.fragment.navArgs
|
|
|
|
import androidx.navigation.fragment.navArgs
|
|
|
|
|
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
|
|
|
|
import kotlinx.coroutines.flow.collect
|
|
|
|
|
|
|
|
import kotlinx.coroutines.flow.map
|
|
|
|
import mozilla.components.lib.state.ext.consumeFrom
|
|
|
|
import mozilla.components.lib.state.ext.consumeFrom
|
|
|
|
|
|
|
|
import mozilla.components.lib.state.ext.flowScoped
|
|
|
|
import mozilla.components.support.base.feature.UserInteractionHandler
|
|
|
|
import mozilla.components.support.base.feature.UserInteractionHandler
|
|
|
|
import org.mozilla.fenix.HomeActivity
|
|
|
|
import org.mozilla.fenix.HomeActivity
|
|
|
|
import org.mozilla.fenix.R
|
|
|
|
import org.mozilla.fenix.R
|
|
|
|
|
|
|
|
import org.mozilla.fenix.addons.showSnackBar
|
|
|
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
|
|
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
|
|
|
import org.mozilla.fenix.components.StoreProvider
|
|
|
|
import org.mozilla.fenix.components.StoreProvider
|
|
|
|
import org.mozilla.fenix.databinding.FragmentHistoryMetadataGroupBinding
|
|
|
|
import org.mozilla.fenix.databinding.FragmentHistoryMetadataGroupBinding
|
|
|
@ -27,16 +35,19 @@ import org.mozilla.fenix.ext.requireComponents
|
|
|
|
import org.mozilla.fenix.ext.setTextColor
|
|
|
|
import org.mozilla.fenix.ext.setTextColor
|
|
|
|
import org.mozilla.fenix.ext.showToolbar
|
|
|
|
import org.mozilla.fenix.ext.showToolbar
|
|
|
|
import org.mozilla.fenix.ext.components
|
|
|
|
import org.mozilla.fenix.ext.components
|
|
|
|
|
|
|
|
import org.mozilla.fenix.ext.toShortUrl
|
|
|
|
import org.mozilla.fenix.library.LibraryPageFragment
|
|
|
|
import org.mozilla.fenix.library.LibraryPageFragment
|
|
|
|
import org.mozilla.fenix.library.history.History
|
|
|
|
import org.mozilla.fenix.library.history.History
|
|
|
|
import org.mozilla.fenix.library.historymetadata.controller.DefaultHistoryMetadataGroupController
|
|
|
|
import org.mozilla.fenix.library.historymetadata.controller.DefaultHistoryMetadataGroupController
|
|
|
|
import org.mozilla.fenix.library.historymetadata.interactor.DefaultHistoryMetadataGroupInteractor
|
|
|
|
import org.mozilla.fenix.library.historymetadata.interactor.DefaultHistoryMetadataGroupInteractor
|
|
|
|
import org.mozilla.fenix.library.historymetadata.interactor.HistoryMetadataGroupInteractor
|
|
|
|
import org.mozilla.fenix.library.historymetadata.interactor.HistoryMetadataGroupInteractor
|
|
|
|
import org.mozilla.fenix.library.historymetadata.view.HistoryMetadataGroupView
|
|
|
|
import org.mozilla.fenix.library.historymetadata.view.HistoryMetadataGroupView
|
|
|
|
|
|
|
|
import org.mozilla.fenix.utils.allowUndo
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Displays a list of history metadata items for a history metadata search group.
|
|
|
|
* Displays a list of history metadata items for a history metadata search group.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
@SuppressWarnings("TooManyFunctions")
|
|
|
|
class HistoryMetadataGroupFragment :
|
|
|
|
class HistoryMetadataGroupFragment :
|
|
|
|
LibraryPageFragment<History.Metadata>(), UserInteractionHandler {
|
|
|
|
LibraryPageFragment<History.Metadata>(), UserInteractionHandler {
|
|
|
|
|
|
|
|
|
|
|
@ -51,6 +62,9 @@ class HistoryMetadataGroupFragment :
|
|
|
|
|
|
|
|
|
|
|
|
private val args by navArgs<HistoryMetadataGroupFragmentArgs>()
|
|
|
|
private val args by navArgs<HistoryMetadataGroupFragmentArgs>()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override val selectedItems: Set<History.Metadata>
|
|
|
|
|
|
|
|
get() = historyMetadataGroupStore.state.items.filter { it.selected }.toSet()
|
|
|
|
|
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
setHasOptionsMenu(true)
|
|
|
|
setHasOptionsMenu(true)
|
|
|
@ -63,10 +77,13 @@ class HistoryMetadataGroupFragment :
|
|
|
|
): View {
|
|
|
|
): View {
|
|
|
|
_binding = FragmentHistoryMetadataGroupBinding.inflate(inflater, container, false)
|
|
|
|
_binding = FragmentHistoryMetadataGroupBinding.inflate(inflater, container, false)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val historyItems = args.historyMetadataItems.filterIsInstance<History.Metadata>()
|
|
|
|
historyMetadataGroupStore = StoreProvider.get(this) {
|
|
|
|
historyMetadataGroupStore = StoreProvider.get(this) {
|
|
|
|
HistoryMetadataGroupFragmentStore(
|
|
|
|
HistoryMetadataGroupFragmentStore(
|
|
|
|
HistoryMetadataGroupFragmentState(
|
|
|
|
HistoryMetadataGroupFragmentState(
|
|
|
|
items = args.historyMetadataItems.filterIsInstance<History.Metadata>()
|
|
|
|
items = historyItems,
|
|
|
|
|
|
|
|
pendingDeletionItems = requireContext().components.appStore.state.pendingDeletionHistoryItems,
|
|
|
|
|
|
|
|
isEmpty = historyItems.isEmpty()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -75,18 +92,26 @@ class HistoryMetadataGroupFragment :
|
|
|
|
controller = DefaultHistoryMetadataGroupController(
|
|
|
|
controller = DefaultHistoryMetadataGroupController(
|
|
|
|
historyStorage = (activity as HomeActivity).components.core.historyStorage,
|
|
|
|
historyStorage = (activity as HomeActivity).components.core.historyStorage,
|
|
|
|
browserStore = (activity as HomeActivity).components.core.store,
|
|
|
|
browserStore = (activity as HomeActivity).components.core.store,
|
|
|
|
|
|
|
|
appStore = requireContext().components.appStore,
|
|
|
|
store = historyMetadataGroupStore,
|
|
|
|
store = historyMetadataGroupStore,
|
|
|
|
selectOrAddUseCase = requireComponents.useCases.tabsUseCases.selectOrAddTab,
|
|
|
|
selectOrAddUseCase = requireComponents.useCases.tabsUseCases.selectOrAddTab,
|
|
|
|
navController = findNavController(),
|
|
|
|
navController = findNavController(),
|
|
|
|
scope = lifecycleScope,
|
|
|
|
searchTerm = args.title,
|
|
|
|
searchTerm = args.title
|
|
|
|
deleteSnackbar = :: deleteSnackbar,
|
|
|
|
|
|
|
|
promptDeleteAll = :: promptDeleteAll,
|
|
|
|
|
|
|
|
allDeletedSnackbar = ::allDeletedSnackbar,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
_historyMetadataGroupView = HistoryMetadataGroupView(
|
|
|
|
_historyMetadataGroupView = HistoryMetadataGroupView(
|
|
|
|
container = binding.historyMetadataGroupLayout,
|
|
|
|
container = binding.historyMetadataGroupLayout,
|
|
|
|
interactor = interactor,
|
|
|
|
interactor = interactor,
|
|
|
|
title = args.title
|
|
|
|
title = args.title,
|
|
|
|
|
|
|
|
onEmptyStateChanged = {
|
|
|
|
|
|
|
|
historyMetadataGroupStore.dispatch(
|
|
|
|
|
|
|
|
HistoryMetadataGroupFragmentAction.ChangeEmptyState(it)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return binding.root
|
|
|
|
return binding.root
|
|
|
@ -97,6 +122,16 @@ class HistoryMetadataGroupFragment :
|
|
|
|
historyMetadataGroupView.update(state)
|
|
|
|
historyMetadataGroupView.update(state)
|
|
|
|
activity?.invalidateOptionsMenu()
|
|
|
|
activity?.invalidateOptionsMenu()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requireContext().components.appStore.flowScoped(viewLifecycleOwner) { flow ->
|
|
|
|
|
|
|
|
flow.map { state -> state.pendingDeletionHistoryItems }.collect { items ->
|
|
|
|
|
|
|
|
historyMetadataGroupStore.dispatch(
|
|
|
|
|
|
|
|
HistoryMetadataGroupFragmentAction.UpdatePendingDeletionItems(
|
|
|
|
|
|
|
|
pendingDeletionItems = items
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onResume() {
|
|
|
|
override fun onResume() {
|
|
|
@ -104,6 +139,14 @@ class HistoryMetadataGroupFragment :
|
|
|
|
showToolbar(args.title)
|
|
|
|
showToolbar(args.title)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun onDestroyView() {
|
|
|
|
|
|
|
|
super.onDestroyView()
|
|
|
|
|
|
|
|
_historyMetadataGroupView = null
|
|
|
|
|
|
|
|
_binding = null
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun onBackPressed(): Boolean = interactor.onBackPressed(selectedItems)
|
|
|
|
|
|
|
|
|
|
|
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
|
|
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
|
|
|
if (selectedItems.isNotEmpty()) {
|
|
|
|
if (selectedItems.isNotEmpty()) {
|
|
|
|
inflater.inflate(R.menu.history_select_multi, menu)
|
|
|
|
inflater.inflate(R.menu.history_select_multi, menu)
|
|
|
@ -157,17 +200,42 @@ class HistoryMetadataGroupFragment :
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onDestroyView() {
|
|
|
|
private fun deleteSnackbar(
|
|
|
|
super.onDestroyView()
|
|
|
|
items: Set<History.Metadata>,
|
|
|
|
_historyMetadataGroupView = null
|
|
|
|
undo: suspend (items: Set<History.Metadata>) -> Unit,
|
|
|
|
_binding = null
|
|
|
|
delete: (Set<History.Metadata>) -> suspend (context: Context) -> Unit
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
CoroutineScope(Dispatchers.IO).allowUndo(
|
|
|
|
|
|
|
|
requireView(),
|
|
|
|
|
|
|
|
getSnackBarMessage(items),
|
|
|
|
|
|
|
|
getString(R.string.snackbar_deleted_undo),
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
undo.invoke(items)
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
delete(items)
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override val selectedItems: Set<History.Metadata>
|
|
|
|
private fun promptDeleteAll(delete: () -> Unit) {
|
|
|
|
get() =
|
|
|
|
AlertDialog.Builder(requireContext()).apply {
|
|
|
|
historyMetadataGroupStore.state.items.filter { it.selected }.toSet()
|
|
|
|
setMessage(R.string.delete_history_group_prompt_message)
|
|
|
|
|
|
|
|
setNegativeButton(R.string.delete_history_group_prompt_cancel) { dialog: DialogInterface, _ ->
|
|
|
|
|
|
|
|
dialog.cancel()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
setPositiveButton(R.string.delete_history_group_prompt_allow) { dialog: DialogInterface, _ ->
|
|
|
|
|
|
|
|
delete.invoke()
|
|
|
|
|
|
|
|
dialog.dismiss()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
create()
|
|
|
|
|
|
|
|
}.show()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onBackPressed(): Boolean = interactor.onBackPressed(selectedItems)
|
|
|
|
private fun allDeletedSnackbar() {
|
|
|
|
|
|
|
|
showSnackBar(
|
|
|
|
|
|
|
|
requireView(),
|
|
|
|
|
|
|
|
getString(R.string.delete_history_group_snackbar)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun showTabTray() {
|
|
|
|
private fun showTabTray() {
|
|
|
|
findNavController().nav(
|
|
|
|
findNavController().nav(
|
|
|
@ -175,4 +243,12 @@ class HistoryMetadataGroupFragment :
|
|
|
|
HistoryMetadataGroupFragmentDirections.actionGlobalTabsTrayFragment()
|
|
|
|
HistoryMetadataGroupFragmentDirections.actionGlobalTabsTrayFragment()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun getSnackBarMessage(historyItems: Set<History.Metadata>): String {
|
|
|
|
|
|
|
|
val historyItem = historyItems.first()
|
|
|
|
|
|
|
|
return String.format(
|
|
|
|
|
|
|
|
requireContext().getString(R.string.history_delete_single_item_snackbar),
|
|
|
|
|
|
|
|
historyItem.url.toShortUrl(requireComponents.publicSuffixList)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|