Skip to content

Commit b255b52

Browse files
committed
Update feed pagination logic to include aggregated activities
1 parent c38ae51 commit b255b52

File tree

9 files changed

+183
-122
lines changed

9 files changed

+183
-122
lines changed

stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/internal/repository/FeedsRepository.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import io.getstream.feeds.android.client.api.model.FeedId
2323
import io.getstream.feeds.android.client.api.model.FeedMemberData
2424
import io.getstream.feeds.android.client.api.model.FollowData
2525
import io.getstream.feeds.android.client.api.model.ModelUpdates
26+
import io.getstream.feeds.android.client.api.model.PaginationData
2627
import io.getstream.feeds.android.client.api.state.query.FeedQuery
2728
import io.getstream.feeds.android.client.api.state.query.FeedsQuery
2829
import io.getstream.feeds.android.client.internal.model.PaginationResult
@@ -120,14 +121,15 @@ internal interface FeedsRepository {
120121
* @property notificationStatus The notification status for the feed, if available.
121122
*/
122123
internal data class GetOrCreateInfo(
123-
val activities: PaginationResult<ActivityData>,
124+
val pagination: PaginationData,
125+
val activities: List<ActivityData>,
124126
val activitiesQueryConfig: ActivitiesQueryConfig,
127+
val aggregatedActivities: List<AggregatedActivityData>,
125128
val feed: FeedData,
126129
val followers: List<FollowData>,
127130
val following: List<FollowData>,
128131
val followRequests: List<FollowData>,
129132
val members: PaginationResult<FeedMemberData>,
130133
val pinnedActivities: List<ActivityPinData>,
131-
val aggregatedActivities: List<AggregatedActivityData>,
132134
val notificationStatus: NotificationStatusResponse?,
133135
)

stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/internal/repository/FeedsRepositoryImpl.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,12 @@ internal class FeedsRepositoryImpl(private val api: FeedsApi) : FeedsRepository
6363
)
6464
val rawFollowers = response.followers.map { it.toModel() }
6565
GetOrCreateInfo(
66+
pagination = PaginationData(next = response.next, previous = response.prev),
6667
activities =
67-
PaginationResult(
68-
models =
69-
response.activities.map { it.toModel() }.sortedWith(ActivitiesSort.Default),
70-
pagination = PaginationData(next = response.next, previous = response.prev),
71-
),
68+
response.activities.map { it.toModel() }.sortedWith(ActivitiesSort.Default),
7269
activitiesQueryConfig =
7370
QueryConfiguration(filter = query.activityFilter, sort = ActivitiesSort.Default),
71+
aggregatedActivities = response.aggregatedActivities.map { it.toModel() },
7472
feed = response.feed.toModel(),
7573
followers = rawFollowers.filter { it.isFollowerOf(fid) },
7674
following = response.following.map { it.toModel() }.filter { it.isFollowing(fid) },
@@ -81,7 +79,6 @@ internal class FeedsRepositoryImpl(private val api: FeedsApi) : FeedsRepository
8179
pagination = response.memberPagination?.toModel() ?: PaginationData.EMPTY,
8280
),
8381
pinnedActivities = response.pinnedActivities.map { it.toModel() },
84-
aggregatedActivities = response.aggregatedActivities.map { it.toModel() },
8582
notificationStatus = response.notificationStatus,
8683
)
8784
}

stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/internal/state/FeedImpl.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import io.getstream.feeds.android.client.internal.repository.ActivitiesRepositor
3737
import io.getstream.feeds.android.client.internal.repository.BookmarksRepository
3838
import io.getstream.feeds.android.client.internal.repository.CommentsRepository
3939
import io.getstream.feeds.android.client.internal.repository.FeedsRepository
40+
import io.getstream.feeds.android.client.internal.repository.GetOrCreateInfo
4041
import io.getstream.feeds.android.client.internal.repository.PollsRepository
4142
import io.getstream.feeds.android.client.internal.state.event.StateUpdateEvent
4243
import io.getstream.feeds.android.client.internal.state.event.handler.FeedEventHandler
@@ -227,8 +228,15 @@ internal class FeedImpl(
227228
)
228229
return feedsRepository
229230
.getOrCreateFeed(query)
230-
.onSuccess { _state.onQueryMoreActivities(it.activities, it.activitiesQueryConfig) }
231-
.map { it.activities.models }
231+
.onSuccess {
232+
_state.onQueryMoreActivities(
233+
activities = it.activities,
234+
aggregatedActivities = it.aggregatedActivities,
235+
pagination = it.pagination,
236+
queryConfig = it.activitiesQueryConfig,
237+
)
238+
}
239+
.map(GetOrCreateInfo::activities)
232240
}
233241

234242
override suspend fun addBookmark(

stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/internal/state/FeedStateImpl.kt

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import io.getstream.feeds.android.client.api.model.PollVoteData
3232
import io.getstream.feeds.android.client.api.state.FeedState
3333
import io.getstream.feeds.android.client.api.state.query.ActivitiesSort
3434
import io.getstream.feeds.android.client.api.state.query.FeedQuery
35-
import io.getstream.feeds.android.client.internal.model.PaginationResult
3635
import io.getstream.feeds.android.client.internal.model.QueryConfiguration
3736
import io.getstream.feeds.android.client.internal.model.deleteBookmark
3837
import io.getstream.feeds.android.client.internal.model.isFollowRequest
@@ -53,6 +52,7 @@ import io.getstream.feeds.android.client.internal.state.query.ActivitiesQueryCon
5352
import io.getstream.feeds.android.client.internal.utils.mergeSorted
5453
import io.getstream.feeds.android.client.internal.utils.updateIf
5554
import io.getstream.feeds.android.client.internal.utils.upsert
55+
import io.getstream.feeds.android.client.internal.utils.upsertAll
5656
import io.getstream.feeds.android.client.internal.utils.upsertSorted
5757
import io.getstream.feeds.android.network.models.NotificationStatusResponse
5858
import kotlinx.coroutines.flow.MutableStateFlow
@@ -130,10 +130,10 @@ internal class FeedStateImpl(
130130
get() = _activitiesPagination
131131

132132
override fun onQueryFeed(result: GetOrCreateInfo) {
133-
_activities.update { result.activities.models }
134-
_activitiesPagination = result.activities.pagination
135-
activitiesQueryConfig = result.activitiesQueryConfig
133+
_activities.update { result.activities }
136134
_aggregatedActivities.update { result.aggregatedActivities }
135+
_activitiesPagination = result.pagination
136+
activitiesQueryConfig = result.activitiesQueryConfig
137137
_feed.update { result.feed }
138138
_followers.update { result.followers }
139139
_following.update { result.following }
@@ -146,14 +146,19 @@ internal class FeedStateImpl(
146146
}
147147

148148
override fun onQueryMoreActivities(
149-
result: PaginationResult<ActivityData>,
149+
activities: List<ActivityData>,
150+
aggregatedActivities: List<AggregatedActivityData>,
151+
pagination: PaginationData,
150152
queryConfig: ActivitiesQueryConfig,
151153
) {
152-
_activitiesPagination = result.pagination
154+
_activitiesPagination = pagination
153155
activitiesQueryConfig = queryConfig
154156
// Merge the new activities with the existing ones (keeping the sort order)
155157
_activities.update { current ->
156-
current.mergeSorted(result.models, ActivityData::id, activitiesSorting)
158+
current.mergeSorted(activities, ActivityData::id, activitiesSorting)
159+
}
160+
_aggregatedActivities.update { current ->
161+
current.upsertAll(aggregatedActivities, AggregatedActivityData::group)
157162
}
158163
}
159164

@@ -374,7 +379,9 @@ internal interface FeedStateUpdates {
374379

375380
/** Handles the result of a query for more activities. */
376381
fun onQueryMoreActivities(
377-
result: PaginationResult<ActivityData>,
382+
activities: List<ActivityData>,
383+
aggregatedActivities: List<AggregatedActivityData>,
384+
pagination: PaginationData,
378385
queryConfig: ActivitiesQueryConfig,
379386
)
380387

stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/internal/utils/List.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,24 @@ internal fun <T, ID> List<T>.upsertSorted(
216216
update: (old: T) -> T = { element },
217217
): List<T> = upsertSorted(element, idSelector, CompositeComparator(sort), update)
218218

219+
internal fun <T, R> List<T>.upsertAll(that: List<T>, keySelector: (T) -> R): List<T> {
220+
// Using LinkedHashMap instead of e.g. HashMap to preserve order
221+
val toUpsert = that.associateByTo(LinkedHashMap(), keySelector)
222+
val result = ArrayList<T>(this.size + that.size)
223+
224+
// Update what should be updated
225+
forEach { item ->
226+
val key = keySelector(item)
227+
result.add(toUpsert[key] ?: item)
228+
toUpsert.remove(key)
229+
}
230+
231+
// Insert the rest
232+
result.addAll(toUpsert.values)
233+
234+
return result
235+
}
236+
219237
/**
220238
* Merges two sorted arrays while maintaining the sort order and handling duplicates.
221239
*

stream-feeds-android-client/src/test/kotlin/io/getstream/feeds/android/client/internal/repository/FeedsRepositoryImplTest.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,24 +74,21 @@ internal class FeedsRepositoryImplTest {
7474
apiResult = apiResult,
7575
repositoryResult =
7676
GetOrCreateInfo(
77-
activities =
78-
PaginationResult(
79-
models = emptyList(),
80-
pagination = PaginationData(next = "next", previous = "prev"),
81-
),
77+
pagination = PaginationData(next = "next", previous = "prev"),
78+
activities = emptyList(),
8279
activitiesQueryConfig =
8380
QueryConfiguration(
8481
filter = query.activityFilter,
8582
sort = ActivitiesSort.Default,
8683
),
84+
aggregatedActivities = emptyList(),
8785
feed = apiResult.feed.toModel(),
8886
followers = emptyList(),
8987
following = emptyList(),
9088
followRequests = emptyList(),
9189
members =
9290
PaginationResult(models = emptyList(), pagination = PaginationData.EMPTY),
9391
pinnedActivities = emptyList(),
94-
aggregatedActivities = emptyList(),
9592
notificationStatus = null,
9693
),
9794
)

stream-feeds-android-client/src/test/kotlin/io/getstream/feeds/android/client/internal/state/FeedImplTest.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,16 +770,17 @@ internal class FeedImplTest {
770770
val paginationData = PaginationData(next = "cursor")
771771

772772
return GetOrCreateInfo(
773-
activities = PaginationResult(models = activities, pagination = paginationData),
773+
pagination = paginationData,
774+
activities = activities,
774775
activitiesQueryConfig =
775776
QueryConfiguration(filter = null, sort = ActivitiesSort.Default),
777+
aggregatedActivities = emptyList(),
776778
feed = testFeedData,
777779
followers = followers,
778780
following = following,
779781
followRequests = followRequests,
780782
members = PaginationResult(models = members, pagination = paginationData),
781783
pinnedActivities = emptyList(),
782-
aggregatedActivities = emptyList(),
783784
notificationStatus = null,
784785
)
785786
}

stream-feeds-android-client/src/test/kotlin/io/getstream/feeds/android/client/internal/state/FeedStateImplTest.kt

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,42 @@ internal class FeedStateImplTest {
8888
}
8989

9090
@Test
91-
fun `on queryMoreActivities, then merge activities`() = runTest {
92-
val initialActivities = listOf(activityData())
93-
setupInitialState(initialActivities)
91+
fun `on queryMoreActivities, merge with new activities and aggregated activities`() = runTest {
92+
val initialActivities = listOf(activityData("activity-1"))
93+
val initialAggregated =
94+
listOf(
95+
aggregatedActivityData(
96+
group = "group-1",
97+
activities = listOf(activityData("activity-1")),
98+
activityCount = 1,
99+
)
100+
)
101+
setupInitialState(activities = initialActivities, aggregatedActivities = initialAggregated)
94102

95103
val newActivities = listOf(activityData("activity-2"), activityData("activity-3"))
96-
val newPaginationResult =
97-
PaginationResult(
98-
models = newActivities,
99-
pagination = PaginationData(next = "next-cursor-2", previous = null),
104+
val newAggregated =
105+
listOf(
106+
aggregatedActivityData(
107+
group = "group-2",
108+
activities = listOf(activityData("activity-2")),
109+
),
110+
aggregatedActivityData(
111+
group = "group-3",
112+
activities = listOf(activityData("activity-3")),
113+
),
100114
)
115+
val newPagination = PaginationData(next = "next-cursor-2", previous = null)
101116

102-
feedState.onQueryMoreActivities(newPaginationResult, createQueryConfig())
117+
feedState.onQueryMoreActivities(
118+
activities = newActivities,
119+
aggregatedActivities = newAggregated,
120+
pagination = newPagination,
121+
queryConfig = createQueryConfig(),
122+
)
103123

104-
assertEquals(3, feedState.activities.value.size)
105-
assertEquals("next-cursor-2", feedState.activitiesPagination?.next)
124+
assertEquals(newPagination, feedState.activitiesPagination)
125+
assertEquals(initialActivities + newActivities, feedState.activities.value)
126+
assertEquals((initialAggregated + newAggregated), feedState.aggregatedActivities.value)
106127
}
107128

108129
@Test
@@ -583,22 +604,19 @@ internal class FeedStateImplTest {
583604
pinnedActivities: List<ActivityPinData> = emptyList(),
584605
aggregatedActivities: List<AggregatedActivityData> = emptyList(),
585606
): GetOrCreateInfo {
586-
val paginationResult =
587-
PaginationResult(
588-
models = activities,
589-
pagination = PaginationData(next = "next-cursor", previous = null),
590-
)
607+
val pagination = PaginationData(next = "next-cursor", previous = null)
591608
val queryConfig = createQueryConfig()
592609

593610
return GetOrCreateInfo(
594-
activities = paginationResult,
611+
pagination = pagination,
612+
activities = activities,
595613
activitiesQueryConfig = queryConfig,
614+
aggregatedActivities = aggregatedActivities,
596615
feed = feed,
597616
followers = followers,
598617
following = following,
599618
followRequests = followRequests,
600619
pinnedActivities = pinnedActivities,
601-
aggregatedActivities = aggregatedActivities,
602620
notificationStatus = null,
603621
members =
604622
PaginationResult(

0 commit comments

Comments
 (0)