diff --git a/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt b/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt index 90f17434fb..2a88c2be6e 100644 --- a/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt +++ b/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt @@ -13,6 +13,8 @@ import org.mozilla.fenix.library.history.History import org.mozilla.fenix.library.history.toHistoryMetadata import org.mozilla.fenix.perf.runBlockingIncrement +private const val BUFFER_TIME = 15000 /* 15 seconds in ms */ + /** * An Interface for providing a paginated list of [History]. */ @@ -35,7 +37,7 @@ class DefaultPagedHistoryProvider( private val showHistorySearchGroups: Boolean = FeatureFlags.showHistorySearchGroups, ) : PagedHistoryProvider { - private var historyGroups: List? = null + @Volatile private var historyGroups: List? = null @Suppress("LongMethod") override fun getHistory( @@ -52,7 +54,6 @@ class DefaultPagedHistoryProvider( // We need to refetch all the history metadata if the offset resets back at 0 // in the case of a pull to refresh. if (historyGroups == null || offset == 0L) { - historyGroups = historyStorage.getHistoryMetadataSince(Long.MIN_VALUE) .sortedByDescending { it.createdAt } .filter { it.key.searchTerm != null } @@ -90,6 +91,36 @@ class DefaultPagedHistoryProvider( } } + /** + * Returns the [History.Regular] corresponding to the given [History.Metadata] item. + * + * @param historyMetadata The [History.Metadata] to match. + * @return the [History.Regular] corresponding to the given [History.Metadata] item or null. + */ + suspend fun getMatchingHistory(historyMetadata: History.Metadata): VisitInfo? { + val history = historyStorage.getDetailedVisits( + start = historyMetadata.visitedAt - BUFFER_TIME, + end = historyMetadata.visitedAt, + excludeTypes = listOf( + VisitType.NOT_A_VISIT, + VisitType.DOWNLOAD, + VisitType.REDIRECT_TEMPORARY, + VisitType.RELOAD, + VisitType.EMBED, + VisitType.FRAMED_LINK, + VisitType.REDIRECT_PERMANENT + ) + ) + return history.lastOrNull { it.url == historyMetadata.url } + } + + /** + * Clears the history groups to refetch the most history metadata after any changes. + */ + fun clearHistoryGroups() { + historyGroups = null + } + @Suppress("MagicNumber") private suspend fun getHistoryAndSearchGroups( offset: Long, @@ -115,7 +146,7 @@ class DefaultPagedHistoryProvider( // History metadata items are recorded after their associated visited info, we add an // additional buffer time to the most recent visit to account for a history group // appearing as the most recent item. - val visitedAtBuffer = if (offset == 0L) 15000 else 0 /* 15 seconds in ms */ + val visitedAtBuffer = if (offset == 0L) BUFFER_TIME else 0 // Get the history groups that fit within the range of visited times in the current history // items. @@ -129,8 +160,8 @@ class DefaultPagedHistoryProvider( } val historyMetadata = historyGroupsInOffset.flatMap { it.items } - // Add all items that are not in a group filtering out any matches with a history metadata - // item. + // Add all history items that are not in a group filtering out any matches with a history + // metadata item. result.addAll(history.filter { item -> historyMetadata.find { it.url == item.url } == null }) // Filter history metadata items with no view time and dedupe by url. diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryController.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryController.kt index 7e033e69e7..5586a75042 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryController.kt @@ -33,7 +33,7 @@ class DefaultHistoryController( private val openToBrowser: (item: History.Regular) -> Unit, private val displayDeleteAll: () -> Unit, private val invalidateOptionsMenu: () -> Unit, - private val deleteHistoryItems: (Set) -> Unit, + private val deleteHistoryItems: (Set) -> Unit, private val syncHistory: suspend () -> Unit, private val metrics: MetricController ) : HistoryController { @@ -59,15 +59,11 @@ class DefaultHistoryController( return } - if (item is History.Regular) { - store.dispatch(HistoryFragmentAction.AddItemForRemoval(item)) - } + store.dispatch(HistoryFragmentAction.AddItemForRemoval(item)) } override fun handleDeselect(item: History) { - if (item is History.Regular) { - store.dispatch(HistoryFragmentAction.RemoveItemForRemoval(item)) - } + store.dispatch(HistoryFragmentAction.RemoveItemForRemoval(item)) } override fun handleBackPressed(): Boolean { @@ -88,9 +84,7 @@ class DefaultHistoryController( } override fun handleDeleteSome(items: Set) { - items.filterIsInstance().let { - deleteHistoryItems.invoke(it.toSet()) - } + deleteHistoryItems.invoke(items) } override fun handleRequestSync() { diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt index a79cbdbd0b..4bc1754354 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt @@ -53,6 +53,8 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { private lateinit var historyStore: HistoryFragmentStore private lateinit var historyInteractor: HistoryInteractor private lateinit var viewModel: HistoryViewModel + private lateinit var historyProvider: DefaultPagedHistoryProvider + private var undoScope: CoroutineScope? = null private var pendingHistoryDeletionJob: (suspend () -> Unit)? = null @@ -65,7 +67,7 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View { _binding = FragmentHistoryBinding.inflate(inflater, container, false) val view = binding.root @@ -110,9 +112,9 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - viewModel = HistoryViewModel( - historyProvider = DefaultPagedHistoryProvider(requireComponents.core.historyStorage) - ) + historyProvider = DefaultPagedHistoryProvider(requireComponents.core.historyStorage) + + viewModel = HistoryViewModel(historyProvider) viewModel.userHasHistory.observe( this, @@ -126,7 +128,7 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { setHasOptionsMenu(true) } - private fun deleteHistoryItems(items: Set) { + private fun deleteHistoryItems(items: Set) { updatePendingHistoryToDelete(items) undoScope = CoroutineScope(IO) undoScope?.allowUndo( @@ -178,8 +180,28 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.share_history_multi_select -> { val selectedHistory = historyStore.state.mode.selectedItems - val shareTabs = selectedHistory.map { ShareData(url = it.url, title = it.title) } + val shareTabs = mutableListOf() + + for (history in selectedHistory) { + when (history) { + is History.Regular -> { + shareTabs.add(ShareData(url = history.url, title = history.title)) + } + is History.Group -> { + shareTabs.addAll( + history.items.map { metadata -> + ShareData(url = metadata.url, title = metadata.title) + } + ) + } + else -> { + // no-op, There is no [History.Metadata] in the HistoryFragment. + } + } + } + share(shareTabs) + true } R.id.delete_history_multi_select -> { @@ -227,15 +249,19 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { ) } - private fun getMultiSelectSnackBarMessage(historyItems: Set): String { + private fun getMultiSelectSnackBarMessage(historyItems: Set): String { return if (historyItems.size > 1) { getString(R.string.history_delete_multiple_items_snackbar) } else { + val historyItem = historyItems.first() + String.format( - requireContext().getString( - R.string.history_delete_single_item_snackbar - ), - historyItems.first().url.toShortUrl(requireComponents.publicSuffixList) + requireContext().getString(R.string.history_delete_single_item_snackbar), + if (historyItem is History.Regular) { + historyItem.url.toShortUrl(requireComponents.publicSuffixList) + } else { + historyItem.title + } ) } } @@ -318,14 +344,35 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { ) } - private fun getDeleteHistoryItemsOperation(items: Set): (suspend () -> Unit) { + private fun getDeleteHistoryItemsOperation(items: Set): (suspend () -> Unit) { return { CoroutineScope(IO).launch { historyStore.dispatch(HistoryFragmentAction.EnterDeletionMode) context?.components?.run { for (item in items) { analytics.metrics.track(Event.HistoryItemRemoved) - core.historyStorage.deleteVisit(item.url, item.visitedAt) + + if (item is History.Regular) { + core.historyStorage.deleteVisit( + url = item.url, + timestamp = item.visitedAt + ) + } else if (item is History.Group) { + for (historyMetadata in item.items) { + historyProvider.getMatchingHistory(historyMetadata)?.let { + core.historyStorage.deleteVisit( + url = it.url, + timestamp = it.visitTime + ) + } + } + + core.historyStorage.deleteHistoryMetadata( + searchTerm = item.title + ) + + historyProvider.clearHistoryGroups() + } } } historyStore.dispatch(HistoryFragmentAction.ExitDeletionMode) @@ -334,13 +381,13 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { } } - private fun updatePendingHistoryToDelete(items: Set) { + private fun updatePendingHistoryToDelete(items: Set) { pendingHistoryDeletionJob = getDeleteHistoryItemsOperation(items) val ids = items.map { item -> item.visitedAt }.toSet() historyStore.dispatch(HistoryFragmentAction.AddPendingDeletionSet(ids)) } - private fun undoPendingDeletion(items: Set) { + private fun undoPendingDeletion(items: Set) { pendingHistoryDeletionJob = null val ids = items.map { item -> item.visitedAt }.toSet() historyStore.dispatch(HistoryFragmentAction.UndoPendingDeletionSet(ids)) diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragmentStore.kt index 5860661bf3..587e292f80 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragmentStore.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragmentStore.kt @@ -105,8 +105,8 @@ class HistoryFragmentStore(initialState: HistoryFragmentState) : */ sealed class HistoryFragmentAction : Action { object ExitEditMode : HistoryFragmentAction() - data class AddItemForRemoval(val item: History.Regular) : HistoryFragmentAction() - data class RemoveItemForRemoval(val item: History.Regular) : HistoryFragmentAction() + data class AddItemForRemoval(val item: History) : HistoryFragmentAction() + data class RemoveItemForRemoval(val item: History) : HistoryFragmentAction() data class AddPendingDeletionSet(val itemIds: Set) : HistoryFragmentAction() data class UndoPendingDeletionSet(val itemIds: Set) : HistoryFragmentAction() object EnterDeletionMode : HistoryFragmentAction() @@ -127,11 +127,11 @@ data class HistoryFragmentState( val isDeletingItems: Boolean ) : State { sealed class Mode { - open val selectedItems = emptySet() + open val selectedItems = emptySet() object Normal : Mode() object Syncing : Mode() - data class Editing(override val selectedItems: Set) : Mode() + data class Editing(override val selectedItems: Set) : Mode() } } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt index e81bb1d102..8e4a177282 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/viewholders/HistoryListItemViewHolder.kt @@ -53,8 +53,6 @@ class HistoryListItemViewHolder( binding.historyLayout.visibility = View.VISIBLE } - binding.historyLayout.overflowView.isVisible = item !is History.Group - binding.historyLayout.titleView.text = item.title binding.historyLayout.urlView.text = Do exhaustive when (item) { diff --git a/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt b/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt index d103364d25..fdf68108f4 100644 --- a/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt @@ -12,6 +12,7 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -35,7 +36,8 @@ import org.mozilla.fenix.library.historymetadata.view.HistoryMetadataGroupView /** * Displays a list of history metadata items for a history metadata search group. */ -class HistoryMetadataGroupFragment : LibraryPageFragment(), UserInteractionHandler { +class HistoryMetadataGroupFragment : + LibraryPageFragment(), UserInteractionHandler { private lateinit var historyMetadataGroupStore: HistoryMetadataGroupFragmentStore private lateinit var interactor: HistoryMetadataGroupInteractor @@ -43,6 +45,8 @@ class HistoryMetadataGroupFragment : LibraryPageFragment(), Us private var _historyMetadataGroupView: HistoryMetadataGroupView? = null private val historyMetadataGroupView: HistoryMetadataGroupView get() = _historyMetadataGroupView!! + private var _binding: FragmentHistoryMetadataGroupBinding? = null + private val binding get() = _binding!! private val args by navArgs() @@ -54,9 +58,9 @@ class HistoryMetadataGroupFragment : LibraryPageFragment(), Us override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - val binding = FragmentHistoryMetadataGroupBinding.inflate(inflater, container, false) + savedInstanceState: Bundle?, + ): View { + _binding = FragmentHistoryMetadataGroupBinding.inflate(inflater, container, false) historyMetadataGroupStore = StoreProvider.get(this) { HistoryMetadataGroupFragmentStore( @@ -70,7 +74,9 @@ class HistoryMetadataGroupFragment : LibraryPageFragment(), Us controller = DefaultHistoryMetadataGroupController( activity = activity as HomeActivity, store = historyMetadataGroupStore, - navController = findNavController() + navController = findNavController(), + scope = lifecycleScope, + searchTerm = args.title ) ) @@ -117,7 +123,7 @@ class HistoryMetadataGroupFragment : LibraryPageFragment(), Us true } R.id.delete_history_multi_select -> { - interactor.onDeleteMenuItem(selectedItems) + interactor.onDelete(selectedItems) true } R.id.open_history_in_new_tabs_multi_select -> { @@ -152,10 +158,12 @@ class HistoryMetadataGroupFragment : LibraryPageFragment(), Us override fun onDestroyView() { super.onDestroyView() _historyMetadataGroupView = null + _binding = null } - override val selectedItems: Set get() = - historyMetadataGroupStore.state.items.filter { it.selected }.toSet() + override val selectedItems: Set + get() = + historyMetadataGroupStore.state.items.filter { it.selected }.toSet() override fun onBackPressed(): Boolean = interactor.onBackPressed(selectedItems) diff --git a/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStore.kt index b3825e6c9c..b267f1f707 100644 --- a/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStore.kt +++ b/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStore.kt @@ -29,6 +29,8 @@ sealed class HistoryMetadataGroupFragmentAction : Action { data class Select(val item: History.Metadata) : HistoryMetadataGroupFragmentAction() data class Deselect(val item: History.Metadata) : HistoryMetadataGroupFragmentAction() object DeselectAll : HistoryMetadataGroupFragmentAction() + data class Delete(val item: History.Metadata) : HistoryMetadataGroupFragmentAction() + object DeleteAll : HistoryMetadataGroupFragmentAction() } /** @@ -82,5 +84,12 @@ private fun historyStateReducer( items = state.items.toMutableList() .map { it.copy(selected = false) } ) + is HistoryMetadataGroupFragmentAction.Delete -> { + val items = state.items.toMutableList() + items.remove(action.item) + state.copy(items = items) + } + is HistoryMetadataGroupFragmentAction.DeleteAll -> + state.copy(items = emptyList()) } } diff --git a/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt b/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt index dd64d60367..a42bd00ded 100644 --- a/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt @@ -5,9 +5,12 @@ package org.mozilla.fenix.library.historymetadata.controller import androidx.navigation.NavController +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import mozilla.components.concept.engine.prompt.ShareData import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.ext.components import org.mozilla.fenix.library.history.History import org.mozilla.fenix.library.historymetadata.HistoryMetadataGroupFragmentAction import org.mozilla.fenix.library.historymetadata.HistoryMetadataGroupFragmentDirections @@ -53,6 +56,16 @@ interface HistoryMetadataGroupController { * @param items The set of [History]s to share. */ fun handleShare(items: Set) + + /** + * Deletes the given history metadata [items] from storage. + */ + fun handleDelete(items: Set) + + /** + * Deletes all the history metadata items in this group. + */ + fun handleDeleteAll() } /** @@ -62,6 +75,8 @@ class DefaultHistoryMetadataGroupController( private val activity: HomeActivity, private val store: HistoryMetadataGroupFragmentStore, private val navController: NavController, + private val scope: CoroutineScope, + private val searchTerm: String, ) : HistoryMetadataGroupController { override fun handleOpen(item: History.Metadata) { @@ -97,4 +112,20 @@ class DefaultHistoryMetadataGroupController( ) ) } + + override fun handleDelete(items: Set) { + scope.launch { + items.forEach { + store.dispatch(HistoryMetadataGroupFragmentAction.Delete(it)) + activity.components.core.historyStorage.deleteHistoryMetadata(it.historyMetadataKey) + } + } + } + + override fun handleDeleteAll() { + scope.launch { + store.dispatch(HistoryMetadataGroupFragmentAction.DeleteAll) + activity.components.core.historyStorage.deleteHistoryMetadata(searchTerm) + } + } } diff --git a/app/src/main/java/org/mozilla/fenix/library/historymetadata/interactor/HistoryMetadataGroupInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/historymetadata/interactor/HistoryMetadataGroupInteractor.kt index 4af92e3abe..9e8953404f 100644 --- a/app/src/main/java/org/mozilla/fenix/library/historymetadata/interactor/HistoryMetadataGroupInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/library/historymetadata/interactor/HistoryMetadataGroupInteractor.kt @@ -21,15 +21,15 @@ interface HistoryMetadataGroupInteractor : SelectionInteractor fun onBackPressed(items: Set): Boolean /** - * Deletes the given set of history [items] that are selected. Called when a user clicks on the - * "Delete" menu item. + * Deletes the given set of history metadata [items]. Called when a user clicks on the + * "Delete" menu item or the "x" button associated with a history metadata item. * * @param items The set of [History]s to delete. */ - fun onDeleteMenuItem(items: Set) + fun onDelete(items: Set) /** - * Deletes the all the history items in the history metadata group. Called when a user clicks + * Deletes all the history items in the history metadata group. Called when a user clicks * on the "Delete history" menu item. */ fun onDeleteAllMenuItem() @@ -66,12 +66,12 @@ class DefaultHistoryMetadataGroupInteractor( return controller.handleBackPressed(items) } - override fun onDeleteMenuItem(items: Set) { - // no-op + override fun onDelete(items: Set) { + controller.handleDelete(items) } override fun onDeleteAllMenuItem() { - // no-op + controller.handleDeleteAll() } override fun onShareMenuItem(items: Set) { diff --git a/app/src/main/java/org/mozilla/fenix/library/historymetadata/view/HistoryMetadataGroupItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/historymetadata/view/HistoryMetadataGroupItemViewHolder.kt index cb536f32e3..1f5c9fc65d 100644 --- a/app/src/main/java/org/mozilla/fenix/library/historymetadata/view/HistoryMetadataGroupItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/historymetadata/view/HistoryMetadataGroupItemViewHolder.kt @@ -27,6 +27,14 @@ class HistoryMetadataGroupItemViewHolder( private var item: History.Metadata? = null + init { + binding.historyLayout.overflowView.setImageResource(R.drawable.ic_close) + binding.historyLayout.overflowView.setOnClickListener { + val item = this.item ?: return@setOnClickListener + interactor.onDelete(setOf(item)) + } + } + fun bind(item: History.Metadata) { binding.historyLayout.titleView.text = item.title binding.historyLayout.urlView.text = item.url @@ -38,8 +46,6 @@ class HistoryMetadataGroupItemViewHolder( binding.historyLayout.loadFavicon(item.url) } - binding.historyLayout.overflowView.setImageResource(R.drawable.ic_close) - if (selectionHolder.selectedItems.isEmpty()) { binding.historyLayout.overflowView.showAndEnable() } else { diff --git a/app/src/test/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStoreTest.kt b/app/src/test/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStoreTest.kt index 69a7751933..8552851bb9 100644 --- a/app/src/test/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStoreTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragmentStoreTest.kt @@ -82,4 +82,25 @@ class HistoryMetadataGroupFragmentStoreTest { assertFalse(store.state.items[0].selected) assertFalse(store.state.items[1].selected) } + + @Test + fun `Test deleting an item in HistoryMetadataGroupFragmentStore`() = runBlocking { + val items = listOf(mozillaHistoryMetadataItem, firefoxHistoryMetadataItem) + + store.dispatch(HistoryMetadataGroupFragmentAction.UpdateHistoryItems(items)).join() + store.dispatch(HistoryMetadataGroupFragmentAction.Delete(mozillaHistoryMetadataItem)).join() + + assertEquals(1, store.state.items.size) + assertEquals(firefoxHistoryMetadataItem, store.state.items.first()) + } + + @Test + fun `Test deleting all items in HistoryMetadataGroupFragmentStore`() = runBlocking { + val items = listOf(mozillaHistoryMetadataItem, firefoxHistoryMetadataItem) + + store.dispatch(HistoryMetadataGroupFragmentAction.UpdateHistoryItems(items)).join() + store.dispatch(HistoryMetadataGroupFragmentAction.DeleteAll).join() + + assertEquals(0, store.state.items.size) + } } diff --git a/app/src/test/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupControllerTest.kt b/app/src/test/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupControllerTest.kt index 064722edf9..a579d1ad77 100644 --- a/app/src/test/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupControllerTest.kt @@ -5,13 +5,19 @@ package org.mozilla.fenix.library.historymetadata.controller import androidx.navigation.NavController +import io.mockk.coVerify +import io.mockk.every import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineDispatcher +import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.runBlockingTest +import mozilla.components.browser.storage.sync.PlacesHistoryStorage import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.concept.storage.HistoryMetadataKey import mozilla.components.support.test.rule.MainCoroutineRule +import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before @@ -20,6 +26,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.directionsEq import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.library.history.History @@ -32,6 +39,7 @@ import org.mozilla.fenix.library.historymetadata.HistoryMetadataGroupFragmentSto class HistoryMetadataGroupControllerTest { private val testDispatcher = TestCoroutineDispatcher() + private val scope = TestCoroutineScope() @get:Rule val coroutinesTestRule = MainCoroutineRule(testDispatcher) @@ -39,14 +47,17 @@ class HistoryMetadataGroupControllerTest { private val activity: HomeActivity = mockk(relaxed = true) private val store: HistoryMetadataGroupFragmentStore = mockk(relaxed = true) private val navController: NavController = mockk(relaxed = true) + private val historyStorage: PlacesHistoryStorage = mockk(relaxed = true) + private val searchTerm = "mozilla" + private val historyMetadataKey = HistoryMetadataKey("http://www.mozilla.com", searchTerm, null) private val mozillaHistoryMetadataItem = History.Metadata( id = 0, title = "Mozilla", url = "mozilla.org", visitedAt = 0, totalViewTime = 1, - historyMetadataKey = HistoryMetadataKey("http://www.mozilla.com", "mozilla", null) + historyMetadataKey = historyMetadataKey ) private val firefoxHistoryMetadataItem = History.Metadata( id = 0, @@ -54,7 +65,7 @@ class HistoryMetadataGroupControllerTest { url = "firefox.com", visitedAt = 0, totalViewTime = 1, - historyMetadataKey = HistoryMetadataKey("http://www.firefox.com", "mozilla", null) + historyMetadataKey = historyMetadataKey ) private lateinit var controller: DefaultHistoryMetadataGroupController @@ -64,8 +75,17 @@ class HistoryMetadataGroupControllerTest { controller = DefaultHistoryMetadataGroupController( activity = activity, store = store, - navController = navController + navController = navController, + scope = scope, + searchTerm = "mozilla" ) + + every { activity.components.core.historyStorage } returns historyStorage + } + + @After + fun cleanUp() { + scope.cleanupTestCoroutines() } @Test @@ -132,4 +152,26 @@ class HistoryMetadataGroupControllerTest { ) } } + + @Test + fun handleDelete() = testDispatcher.runBlockingTest { + controller.handleDelete(setOf(mozillaHistoryMetadataItem, firefoxHistoryMetadataItem)) + + coVerify { + store.dispatch(HistoryMetadataGroupFragmentAction.Delete(mozillaHistoryMetadataItem)) + store.dispatch(HistoryMetadataGroupFragmentAction.Delete(firefoxHistoryMetadataItem)) + historyStorage.deleteHistoryMetadata(mozillaHistoryMetadataItem.historyMetadataKey) + historyStorage.deleteHistoryMetadata(firefoxHistoryMetadataItem.historyMetadataKey) + } + } + + @Test + fun handleDeleteAll() = testDispatcher.runBlockingTest { + controller.handleDeleteAll() + + coVerify { + store.dispatch(HistoryMetadataGroupFragmentAction.DeleteAll) + historyStorage.deleteHistoryMetadata(searchTerm) + } + } }