mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-19 09:25:34 +00:00
[fenix] Sort history metadata on home and allow limiting results
This commit is contained in:
parent
ae40da34f8
commit
d4a454442b
@ -17,6 +17,8 @@ import org.mozilla.fenix.home.HomeFragmentAction
|
|||||||
import org.mozilla.fenix.home.HomeFragmentStore
|
import org.mozilla.fenix.home.HomeFragmentStore
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
|
private const val DEFAULT_MAX_RESULTS = 9
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View-bound feature that retrieves a list of history metadata and dispatches updates to the
|
* View-bound feature that retrieves a list of history metadata and dispatches updates to the
|
||||||
* [HomeFragmentStore].
|
* [HomeFragmentStore].
|
||||||
@ -25,12 +27,15 @@ import kotlin.math.max
|
|||||||
* @param historyMetadataStorage The storage manages [HistoryMetadata].
|
* @param historyMetadataStorage The storage manages [HistoryMetadata].
|
||||||
* @param scope The [CoroutineScope] used to retrieve a list of history metadata.
|
* @param scope The [CoroutineScope] used to retrieve a list of history metadata.
|
||||||
* @param ioDispatcher The [CoroutineDispatcher] for performing read/write operations.
|
* @param ioDispatcher The [CoroutineDispatcher] for performing read/write operations.
|
||||||
|
* @param maxResults The maximum number of metadata groups that should be added to
|
||||||
|
* the store and displayed on the [HomeFragment].
|
||||||
*/
|
*/
|
||||||
class HistoryMetadataFeature(
|
class HistoryMetadataFeature(
|
||||||
private val homeStore: HomeFragmentStore,
|
private val homeStore: HomeFragmentStore,
|
||||||
private val historyMetadataStorage: HistoryMetadataStorage,
|
private val historyMetadataStorage: HistoryMetadataStorage,
|
||||||
private val scope: CoroutineScope,
|
private val scope: CoroutineScope,
|
||||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||||
|
private val maxResults: Int = DEFAULT_MAX_RESULTS
|
||||||
) : LifecycleAwareFeature {
|
) : LifecycleAwareFeature {
|
||||||
|
|
||||||
private var job: Job? = null
|
private var job: Job? = null
|
||||||
@ -38,7 +43,7 @@ class HistoryMetadataFeature(
|
|||||||
override fun start() {
|
override fun start() {
|
||||||
job = scope.launch(ioDispatcher) {
|
job = scope.launch(ioDispatcher) {
|
||||||
// For now, group the queried list of [HistoryMetadata] according to their search term.
|
// For now, group the queried list of [HistoryMetadata] according to their search term.
|
||||||
// This feature will later be used to generate more groups.
|
// This feature will later be used to generate different groups and highlights.
|
||||||
val historyMetadata = historyMetadataStorage.getHistoryMetadataSince(Long.MIN_VALUE)
|
val historyMetadata = historyMetadataStorage.getHistoryMetadataSince(Long.MIN_VALUE)
|
||||||
.filter { it.totalViewTime > 0 && it.key.searchTerm != null }
|
.filter { it.totalViewTime > 0 && it.key.searchTerm != null }
|
||||||
.groupBy { it.key.searchTerm!! }
|
.groupBy { it.key.searchTerm!! }
|
||||||
@ -63,6 +68,8 @@ class HistoryMetadataFeature(
|
|||||||
historyMetadata = data
|
historyMetadata = data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.sortedByDescending { it.lastUpdated() }
|
||||||
|
.take(maxResults)
|
||||||
|
|
||||||
homeStore.dispatch(HomeFragmentAction.HistoryMetadataChange(historyMetadata))
|
homeStore.dispatch(HomeFragmentAction.HistoryMetadataChange(historyMetadata))
|
||||||
}
|
}
|
||||||
|
@ -18,3 +18,6 @@ data class HistoryMetadataGroup(
|
|||||||
val historyMetadata: List<HistoryMetadata>,
|
val historyMetadata: List<HistoryMetadata>,
|
||||||
val expanded: Boolean = false
|
val expanded: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The last updated time of the group is based on the most recently updated item in the group
|
||||||
|
fun HistoryMetadataGroup.lastUpdated(): Long = historyMetadata.maxOf { it.updatedAt }
|
||||||
|
@ -134,11 +134,12 @@ class HistoryMetadataFeatureTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `GIVEN history metadata WHEN different groups contain entries with same url THEN entries are not deduped`() =
|
fun `GIVEN history metadata WHEN different groups contain entries with same url THEN entries are not deduped`() =
|
||||||
testDispatcher.runBlockingTest {
|
testDispatcher.runBlockingTest {
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
val historyEntry1 = HistoryMetadata(
|
val historyEntry1 = HistoryMetadata(
|
||||||
key = HistoryMetadataKey("http://www.mozilla.com", "mozilla", null),
|
key = HistoryMetadataKey("http://www.mozilla.com", "mozilla", null),
|
||||||
title = "mozilla",
|
title = "mozilla",
|
||||||
createdAt = System.currentTimeMillis(),
|
createdAt = now,
|
||||||
updatedAt = System.currentTimeMillis(),
|
updatedAt = now + 3,
|
||||||
totalViewTime = 10,
|
totalViewTime = 10,
|
||||||
documentType = DocumentType.Regular,
|
documentType = DocumentType.Regular,
|
||||||
previewImageUrl = null
|
previewImageUrl = null
|
||||||
@ -147,8 +148,8 @@ class HistoryMetadataFeatureTest {
|
|||||||
val historyEntry2 = HistoryMetadata(
|
val historyEntry2 = HistoryMetadata(
|
||||||
key = HistoryMetadataKey("http://firefox.com", "mozilla", null),
|
key = HistoryMetadataKey("http://firefox.com", "mozilla", null),
|
||||||
title = "firefox",
|
title = "firefox",
|
||||||
createdAt = System.currentTimeMillis(),
|
createdAt = now,
|
||||||
updatedAt = System.currentTimeMillis(),
|
updatedAt = now + 2,
|
||||||
totalViewTime = 20,
|
totalViewTime = 20,
|
||||||
documentType = DocumentType.Regular,
|
documentType = DocumentType.Regular,
|
||||||
previewImageUrl = null
|
previewImageUrl = null
|
||||||
@ -157,8 +158,8 @@ class HistoryMetadataFeatureTest {
|
|||||||
val historyEntry3 = HistoryMetadata(
|
val historyEntry3 = HistoryMetadata(
|
||||||
key = HistoryMetadataKey("http://www.mozilla.com", "firefox", null),
|
key = HistoryMetadataKey("http://www.mozilla.com", "firefox", null),
|
||||||
title = "mozilla",
|
title = "mozilla",
|
||||||
createdAt = System.currentTimeMillis(),
|
createdAt = now,
|
||||||
updatedAt = System.currentTimeMillis(),
|
updatedAt = now + 1,
|
||||||
totalViewTime = 30,
|
totalViewTime = 30,
|
||||||
documentType = DocumentType.Regular,
|
documentType = DocumentType.Regular,
|
||||||
previewImageUrl = null
|
previewImageUrl = null
|
||||||
@ -187,12 +188,128 @@ class HistoryMetadataFeatureTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startHistoryMetadataFeature() {
|
@Test
|
||||||
|
fun `GIVEN history metadata WHEN multiple groups exist THEN groups are sorted descending by last updated timestamp`() =
|
||||||
|
testDispatcher.runBlockingTest {
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val historyEntry1 = HistoryMetadata(
|
||||||
|
key = HistoryMetadataKey("http://www.mozilla.com", "mozilla", null),
|
||||||
|
title = "mozilla",
|
||||||
|
createdAt = now,
|
||||||
|
updatedAt = now + 1,
|
||||||
|
totalViewTime = 10,
|
||||||
|
documentType = DocumentType.Regular,
|
||||||
|
previewImageUrl = null
|
||||||
|
)
|
||||||
|
|
||||||
|
val historyEntry2 = HistoryMetadata(
|
||||||
|
key = HistoryMetadataKey("http://firefox.com", "mozilla", null),
|
||||||
|
title = "firefox",
|
||||||
|
createdAt = now,
|
||||||
|
updatedAt = now + 2,
|
||||||
|
totalViewTime = 20,
|
||||||
|
documentType = DocumentType.Regular,
|
||||||
|
previewImageUrl = null
|
||||||
|
)
|
||||||
|
|
||||||
|
val historyEntry3 = HistoryMetadata(
|
||||||
|
key = HistoryMetadataKey("http://www.mozilla.com", "firefox", null),
|
||||||
|
title = "mozilla",
|
||||||
|
createdAt = now,
|
||||||
|
updatedAt = now + 3,
|
||||||
|
totalViewTime = 30,
|
||||||
|
documentType = DocumentType.Regular,
|
||||||
|
previewImageUrl = null
|
||||||
|
)
|
||||||
|
|
||||||
|
val expectedHistoryGroup1 = HistoryMetadataGroup(
|
||||||
|
title = "mozilla",
|
||||||
|
historyMetadata = listOf(historyEntry1, historyEntry2)
|
||||||
|
)
|
||||||
|
|
||||||
|
val expectedHistoryGroup2 = HistoryMetadataGroup(
|
||||||
|
title = "firefox",
|
||||||
|
historyMetadata = listOf(historyEntry3)
|
||||||
|
)
|
||||||
|
|
||||||
|
coEvery { historyMetadataStorage.getHistoryMetadataSince(any()) }.coAnswers {
|
||||||
|
listOf(
|
||||||
|
historyEntry1, historyEntry2, historyEntry3
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
startHistoryMetadataFeature()
|
||||||
|
|
||||||
|
middleware.assertLastAction(HomeFragmentAction.HistoryMetadataChange::class) {
|
||||||
|
assertEquals(listOf(expectedHistoryGroup2, expectedHistoryGroup1), it.historyMetadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN history metadata WHEN multiple groups exist THEN no more than the configured maximum number of results are added to the store`() =
|
||||||
|
testDispatcher.runBlockingTest {
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val historyEntry1 = HistoryMetadata(
|
||||||
|
key = HistoryMetadataKey("http://www.mozilla.com", "mozilla", null),
|
||||||
|
title = "mozilla",
|
||||||
|
createdAt = now,
|
||||||
|
updatedAt = now + 1,
|
||||||
|
totalViewTime = 10,
|
||||||
|
documentType = DocumentType.Regular,
|
||||||
|
previewImageUrl = null
|
||||||
|
)
|
||||||
|
|
||||||
|
val historyEntry2 = HistoryMetadata(
|
||||||
|
key = HistoryMetadataKey("http://firefox.com", "firefox", null),
|
||||||
|
title = "firefox",
|
||||||
|
createdAt = now,
|
||||||
|
updatedAt = now + 2,
|
||||||
|
totalViewTime = 20,
|
||||||
|
documentType = DocumentType.Regular,
|
||||||
|
previewImageUrl = null
|
||||||
|
)
|
||||||
|
|
||||||
|
val historyEntry3 = HistoryMetadata(
|
||||||
|
key = HistoryMetadataKey("http://getpocket.com", "pocket", null),
|
||||||
|
title = "pocket",
|
||||||
|
createdAt = now,
|
||||||
|
updatedAt = now + 3,
|
||||||
|
totalViewTime = 30,
|
||||||
|
documentType = DocumentType.Regular,
|
||||||
|
previewImageUrl = null
|
||||||
|
)
|
||||||
|
|
||||||
|
val expectedHistoryGroup1 = HistoryMetadataGroup(
|
||||||
|
title = "firefox",
|
||||||
|
historyMetadata = listOf(historyEntry2)
|
||||||
|
)
|
||||||
|
|
||||||
|
val expectedHistoryGroup2 = HistoryMetadataGroup(
|
||||||
|
title = "pocket",
|
||||||
|
historyMetadata = listOf(historyEntry3)
|
||||||
|
)
|
||||||
|
|
||||||
|
coEvery { historyMetadataStorage.getHistoryMetadataSince(any()) }.coAnswers {
|
||||||
|
listOf(
|
||||||
|
historyEntry1, historyEntry2, historyEntry3
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
startHistoryMetadataFeature(maxResults = 2)
|
||||||
|
|
||||||
|
// Should not get more than maxResults number of groups back
|
||||||
|
middleware.assertLastAction(HomeFragmentAction.HistoryMetadataChange::class) {
|
||||||
|
assertEquals(listOf(expectedHistoryGroup2, expectedHistoryGroup1), it.historyMetadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startHistoryMetadataFeature(maxResults: Int = 10) {
|
||||||
val feature = HistoryMetadataFeature(
|
val feature = HistoryMetadataFeature(
|
||||||
homeStore,
|
homeStore,
|
||||||
historyMetadataStorage,
|
historyMetadataStorage,
|
||||||
CoroutineScope(testDispatcher),
|
CoroutineScope(testDispatcher),
|
||||||
testDispatcher
|
testDispatcher,
|
||||||
|
maxResults
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(emptyList<HistoryMetadataGroup>(), homeStore.state.historyMetadata)
|
assertEquals(emptyList<HistoryMetadataGroup>(), homeStore.state.historyMetadata)
|
||||||
|
Loading…
Reference in New Issue
Block a user