Skip to content

Commit

Permalink
Deduplicate posts in the feed (#1613)
Browse files Browse the repository at this point in the history
* Deduplicate posts in the feed

* Fix formatting
  • Loading branch information
MV-GH authored Aug 7, 2024
1 parent ce99dfb commit c29f769
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 15 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ dependencies {
implementation("androidx.profileinstaller:profileinstaller")
baselineProfile(project(":benchmarks"))

implementation("it.vercruysse.lemmyapi:lemmy-api:0.3.3-SNAPSHOT")
implementation("it.vercruysse.lemmyapi:lemmy-api:0.3.4-SNAPSHOT")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")

// For custom logging plugin
Expand Down
28 changes: 15 additions & 13 deletions app/src/main/java/com/jerboa/feed/FeedController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ open class FeedController<T> {

val feed: List<T> = items

fun updateAll(
open fun updateAll(
selector: (List<T>) -> List<Int>,
transformer: (T) -> T,
) {
Expand All @@ -17,7 +17,7 @@ open class FeedController<T> {
}
}

fun safeUpdate(
open fun safeUpdate(
index: Int,
transformer: (T) -> T,
) {
Expand All @@ -29,7 +29,7 @@ open class FeedController<T> {
safeUpdate(index, transformer(items[index]))
}

fun safeUpdate(
open fun safeUpdate(
selector: (List<T>) -> Int,
transformer: (T) -> T,
) {
Expand All @@ -44,7 +44,7 @@ open class FeedController<T> {
* Example: a network request to update an item succeeded after the list has changed.
* So, we ignore it
*/
fun safeUpdate(
open fun safeUpdate(
index: Int,
new: T,
) {
Expand All @@ -55,26 +55,28 @@ open class FeedController<T> {
}
}

fun init(newItems: List<T>) {
items.clear()
items.addAll(newItems)
open fun init(newItems: List<T>) {
clear()
addAll(newItems)
}

fun get(index: Int): T? = items.getOrNull(index)
open fun get(index: Int): T? = items.getOrNull(index)

fun add(item: T) = items.add(item)
open fun add(item: T) = items.add(item)

fun remove(item: T) = items.remove(item)
open fun remove(item: T) = items.remove(item)

fun removeAt(index: Int) {
open fun removeAt(index: Int) {
if (isValidIndex(index)) {
items.removeAt(index)
}
}

fun clear() = items.clear()
open fun clear() = items.clear()

fun addAll(newItems: List<T>) = items.addAll(newItems)
open fun addAll(newItems: List<T>) {
items.addAll(newItems)
}

protected inline fun <E> Iterable<E>.indexesOf(predicate: (E) -> Boolean) =
mapIndexedNotNull { index, elem ->
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/jerboa/feed/PostController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import it.vercruysse.lemmyapi.datatypes.HidePost
import it.vercruysse.lemmyapi.datatypes.Person
import it.vercruysse.lemmyapi.datatypes.PostView

open class PostController : FeedController<PostView>() {
open class PostController : UniqueFeedController<PostView>() {
fun findAndUpdatePost(updatedPostView: PostView) {
safeUpdate({ posts ->
posts.indexOfFirst {
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/java/com/jerboa/feed/UniqueFeedController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.jerboa.feed

import it.vercruysse.lemmyapi.Identity

open class UniqueFeedController<T : Identity> : FeedController<T>() {
private val ids = mutableSetOf<Long>()

override fun add(item: T): Boolean {
if (ids.add(item.id)) {
items.add(item)
return true
}
return false
}

override fun addAll(newItems: List<T>) {
newItems.forEach {
if (ids.add(it.id)) {
items.add(it)
}
}
}

override fun clear() {
super.clear()
ids.clear()
}

override fun remove(item: T): Boolean {
ids.remove(item.id)
return super.remove(item)
}
}
82 changes: 82 additions & 0 deletions app/src/test/java/com/jerboa/feed/UniqueFeedControllerTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.jerboa.feed

import it.vercruysse.lemmyapi.Identity
import org.junit.Assert.*
import org.junit.Test

class UniqueFeedControllerTest {
private data class PostView(
override val id: Long,
) : Identity

@Test
fun `Should not add duplicate posts`() {
val controller = UniqueFeedController<PostView>()
controller.add(PostView(1))
assertEquals(1, controller.feed.size)
controller.add(PostView(1))
assertEquals(1, controller.feed.size)
controller.add(PostView(2))
assertEquals(2, controller.feed.size)
}

@Test
fun `Should remove post`() {
val controller = UniqueFeedController<PostView>()
controller.add(PostView(1))
assertEquals(1, controller.feed.size)
controller.remove(PostView(1))
assertEquals(0, controller.feed.size)
}

@Test
fun `Post removal should clear id`() {
val controller = UniqueFeedController<PostView>()
controller.add(PostView(1))
assertEquals(1, controller.feed.size)
controller.remove(PostView(1))
assertTrue(controller.feed.isEmpty())
controller.add(PostView(1))
assertEquals(1, controller.feed.size)
}

@Test
fun `Should clear all posts`() {
val controller = UniqueFeedController<PostView>()
controller.add(PostView(1))
controller.add(PostView(2))
assertEquals(2, controller.feed.size)
controller.clear()
assertTrue(controller.feed.isEmpty())
}

@Test
fun `Clear should clear ids`() {
val controller = UniqueFeedController<PostView>()
controller.add(PostView(1))
controller.add(PostView(2))
assertEquals(2, controller.feed.size)
controller.clear()
assertTrue(controller.feed.isEmpty())
controller.add(PostView(1))
controller.add(PostView(2))
assertEquals(2, controller.feed.size)
}

@Test
fun `Add all should not add duplicates`() {
val controller = UniqueFeedController<PostView>()
controller.addAll(listOf(PostView(1), PostView(2), PostView(1)))
assertEquals(2, controller.feed.size)
}

@Test
fun `Init should clear ids`() {
val controller = UniqueFeedController<PostView>()
controller.add(PostView(1))
controller.add(PostView(2))
assertEquals(2, controller.feed.size)
controller.init(listOf(PostView(1), PostView(2)))
assertEquals(2, controller.feed.size)
}
}

0 comments on commit c29f769

Please sign in to comment.