Skip to content

Commit abec033

Browse files
authored
Unify handling for some comment-related events (#128)
* Only pass the current element in the upsertSorted update lambda * Unify comment added & updated handling for ActivityCommentList & CommentReplyList * Merge CommentReactionAdded + CommentReactionUpdated into CommentReactionUpserted * Merge ActivityReactionAdded + ActivityReactionUpdated into ActivityReactionUpserted * Update doc * Fix newly added tests * Align param naming
1 parent 6857dfb commit abec033

32 files changed

+287
-535
lines changed

stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/internal/model/ThreadedCommentOperations.kt

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package io.getstream.feeds.android.client.internal.model
1818
import io.getstream.feeds.android.client.api.model.CommentData
1919
import io.getstream.feeds.android.client.api.model.FeedsReactionData
2020
import io.getstream.feeds.android.client.api.model.ThreadedCommentData
21-
import io.getstream.feeds.android.client.api.model.toModel
2221
import io.getstream.feeds.android.client.api.state.query.CommentsSortDataFields
2322
import io.getstream.feeds.android.client.internal.utils.upsert
2423
import io.getstream.feeds.android.client.internal.utils.upsertSorted
@@ -151,16 +150,52 @@ internal inline fun ThreadedCommentData.changeReactions(
151150
}
152151

153152
/**
154-
* Adds a reply to the comment, updating the replies list and reply count.
153+
* Searches for the parent comment of the given [reply] and upserts it in the replies list.
155154
*
156-
* @param comment The reply comment to add.
155+
* @param reply The reply comment to upsert.
156+
* @param comparator The comparator used to maintain the sort order of replies.
157+
* @return A new [ThreadedCommentData] instance with the updated replies.
158+
*/
159+
internal fun ThreadedCommentData.upsertNestedReply(
160+
reply: CommentData,
161+
comparator: Comparator<CommentsSortDataFields>,
162+
): ThreadedCommentData =
163+
when {
164+
// If this comment is the parent, upsert the reply directly
165+
id == reply.parentId -> upsertReply(reply, comparator)
166+
// If this comment has no replies, return it unchanged
167+
replies.isNullOrEmpty() -> this
168+
// If this comment has replies, recursively search through them
169+
else -> {
170+
val updatedReplies =
171+
replies.map { replyComment -> replyComment.upsertNestedReply(reply, comparator) }
172+
copy(replies = updatedReplies)
173+
}
174+
}
175+
176+
/**
177+
* Adds or updates a reply in the replies list and updates the reply count accordingly.
178+
*
179+
* @param reply The reply comment to upsert.
157180
* @return A new [ThreadedCommentData] instance with the updated replies and reply count.
158181
*/
159-
internal fun ThreadedCommentData.addReply(
160-
comment: ThreadedCommentData,
182+
private fun ThreadedCommentData.upsertReply(
183+
reply: CommentData,
161184
comparator: Comparator<CommentsSortDataFields>,
162185
): ThreadedCommentData {
163-
val replies = this.replies.orEmpty().upsertSorted(comment, ThreadedCommentData::id, comparator)
164-
val replyCount = this.replyCount + 1
165-
return this.copy(replies = replies, replyCount = replyCount)
186+
val currentReplies = replies.orEmpty()
187+
val updatedReplies =
188+
currentReplies.upsertSorted(
189+
element = ThreadedCommentData(reply),
190+
idSelector = ThreadedCommentData::id,
191+
comparator = comparator,
192+
update = { it.update(reply) },
193+
)
194+
val updatedCount =
195+
if (updatedReplies.size > currentReplies.size) {
196+
replyCount + 1
197+
} else {
198+
replyCount
199+
}
200+
return copy(replies = updatedReplies, replyCount = updatedCount)
166201
}

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

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@ import io.getstream.feeds.android.client.api.model.ThreadedCommentData
2222
import io.getstream.feeds.android.client.api.state.ActivityCommentListState
2323
import io.getstream.feeds.android.client.api.state.query.ActivityCommentsQuery
2424
import io.getstream.feeds.android.client.internal.model.PaginationResult
25-
import io.getstream.feeds.android.client.internal.model.addReply
2625
import io.getstream.feeds.android.client.internal.model.removeReaction
2726
import io.getstream.feeds.android.client.internal.model.update
27+
import io.getstream.feeds.android.client.internal.model.upsertNestedReply
2828
import io.getstream.feeds.android.client.internal.model.upsertReaction
2929
import io.getstream.feeds.android.client.internal.state.query.toComparator
3030
import io.getstream.feeds.android.client.internal.utils.mergeSorted
3131
import io.getstream.feeds.android.client.internal.utils.treeRemoveFirst
32-
import io.getstream.feeds.android.client.internal.utils.treeUpdateFirst
3332
import io.getstream.feeds.android.client.internal.utils.upsertSorted
3433
import kotlinx.coroutines.flow.MutableStateFlow
3534
import kotlinx.coroutines.flow.StateFlow
@@ -72,33 +71,26 @@ internal class ActivityCommentListStateImpl(
7271
}
7372
}
7473

75-
override fun onCommentAdded(comment: ThreadedCommentData) {
74+
override fun onCommentUpserted(comment: CommentData) {
7675
if (comment.parentId == null) {
7776
// If the comment is a top-level comment, add it directly
7877
_comments.update { current ->
79-
current.upsertSorted(comment, ThreadedCommentData::id, commentsComparator)
78+
current.upsertSorted(
79+
element = ThreadedCommentData(comment),
80+
idSelector = ThreadedCommentData::id,
81+
comparator = commentsComparator,
82+
update = { it.update(comment) },
83+
)
8084
}
8185
} else {
8286
// If it's a reply, find the parent and add it to the parent's replies
8387
// Update the comments list by searching for the parent in all top-level comments
8488
_comments.update { current ->
85-
current.map { parent -> addNestedReply(parent, comment) }
89+
current.map { parent -> parent.upsertNestedReply(comment, commentsComparator) }
8690
}
8791
}
8892
}
8993

90-
override fun onCommentUpdated(comment: CommentData) {
91-
_comments.update { current ->
92-
current.treeUpdateFirst(
93-
matcher = { it.id == comment.id },
94-
childrenSelector = { it.replies.orEmpty() },
95-
updateElement = { it.update(comment) },
96-
updateChildren = { parent, children -> parent.copy(replies = children) },
97-
comparator = commentsComparator,
98-
)
99-
}
100-
}
101-
10294
override fun onCommentRemoved(commentId: String) {
10395
_comments.update { current ->
10496
current.treeRemoveFirst(
@@ -119,24 +111,6 @@ internal class ActivityCommentListStateImpl(
119111
_comments.update { current -> current.map { removeCommentReaction(it, comment, reaction) } }
120112
}
121113

122-
private fun addNestedReply(
123-
parent: ThreadedCommentData,
124-
reply: ThreadedCommentData,
125-
): ThreadedCommentData {
126-
// If this comment is the parent, add the reply directly
127-
if (parent.id == reply.parentId) {
128-
return parent.addReply(reply, commentsComparator)
129-
}
130-
// If this comment has replies, recursively search through them
131-
val replies = parent.replies
132-
if (!replies.isNullOrEmpty()) {
133-
val updatedReplies = replies.map { replyComment -> addNestedReply(replyComment, reply) }
134-
return parent.copy(replies = updatedReplies)
135-
}
136-
// No matching parent found in this subtree, return unchanged
137-
return parent
138-
}
139-
140114
private fun upsertCommentReaction(
141115
comment: ThreadedCommentData,
142116
update: CommentData,
@@ -194,25 +168,18 @@ internal interface ActivityCommentListStateUpdates {
194168
fun onQueryMoreComments(result: PaginationResult<ThreadedCommentData>)
195169

196170
/**
197-
* Handles the addition of a new comment.
198-
*
199-
* @param comment The comment that was added.
200-
*/
201-
fun onCommentAdded(comment: ThreadedCommentData)
202-
203-
/**
204-
* Handles the update of an existing comment.
171+
* Handles the removal of a comment.
205172
*
206-
* @param comment The updated comment data.
173+
* @param commentId The ID of the comment that was removed.
207174
*/
208-
fun onCommentUpdated(comment: CommentData)
175+
fun onCommentRemoved(commentId: String)
209176

210177
/**
211-
* Handles the removal of a comment.
178+
* Handles the addition or update of a comment.
212179
*
213-
* @param commentId The ID of the comment that was removed.
180+
* @param comment The comment that was added or updated.
214181
*/
215-
fun onCommentRemoved(commentId: String)
182+
fun onCommentUpserted(comment: CommentData)
216183

217184
/**
218185
* Handles the addition or update of a reaction to a comment.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ internal class ActivityImpl(
164164
.addCommentReaction(commentId, request)
165165
.onSuccess { (reaction, comment) ->
166166
subscriptionManager.onEvent(
167-
StateUpdateEvent.CommentReactionAdded(fid.rawValue, comment, reaction)
167+
StateUpdateEvent.CommentReactionUpserted(fid.rawValue, comment, reaction)
168168
)
169169
}
170170
.map { it.first }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ internal class CommentListStateImpl(
7979
element = comment,
8080
idSelector = CommentData::id,
8181
comparator = comparator,
82-
update = CommentData::update,
82+
update = { it.update(comment) },
8383
)
8484
}
8585
}

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

Lines changed: 10 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import io.getstream.feeds.android.client.api.model.ThreadedCommentData
2222
import io.getstream.feeds.android.client.api.state.CommentReplyListState
2323
import io.getstream.feeds.android.client.api.state.query.CommentRepliesQuery
2424
import io.getstream.feeds.android.client.internal.model.PaginationResult
25-
import io.getstream.feeds.android.client.internal.model.addReply
2625
import io.getstream.feeds.android.client.internal.model.removeReaction
2726
import io.getstream.feeds.android.client.internal.model.update
27+
import io.getstream.feeds.android.client.internal.model.upsertNestedReply
2828
import io.getstream.feeds.android.client.internal.model.upsertReaction
2929
import io.getstream.feeds.android.client.internal.state.query.toComparator
3030
import kotlinx.coroutines.flow.MutableStateFlow
@@ -66,14 +66,6 @@ internal class CommentReplyListStateImpl(
6666
_replies.update { current -> current + result.models }
6767
}
6868

69-
override fun onCommentAdded(comment: ThreadedCommentData) {
70-
if (comment.parentId == null) {
71-
// Comment is not a reply, ignore it
72-
return
73-
}
74-
_replies.update { current -> current.map { addNestedReply(it, comment) } }
75-
}
76-
7769
override fun onCommentRemoved(commentId: String) {
7870
if (commentId == query.commentId) {
7971
// If the deleted comment is the parent comment, we clear the entire state
@@ -96,8 +88,12 @@ internal class CommentReplyListStateImpl(
9688
}
9789
}
9890

99-
override fun onCommentUpdated(comment: CommentData) {
100-
_replies.update { current -> current.map { parent -> updateNestedReply(parent, comment) } }
91+
override fun onCommentUpserted(comment: CommentData) {
92+
if (comment.parentId == null) {
93+
// Comment is not a reply, ignore it
94+
return
95+
}
96+
_replies.update { current -> current.map { it.upsertNestedReply(comment, comparator) } }
10197
}
10298

10399
override fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData) {
@@ -112,22 +108,6 @@ internal class CommentReplyListStateImpl(
112108
}
113109
}
114110

115-
private fun addNestedReply(
116-
parent: ThreadedCommentData,
117-
reply: ThreadedCommentData,
118-
): ThreadedCommentData {
119-
// If this comment is the parent, add the reply directly
120-
if (parent.id == reply.parentId) {
121-
return parent.addReply(reply, comparator)
122-
}
123-
// If the parent has no replies, return it unchanged
124-
if (parent.replies.isNullOrEmpty()) {
125-
return parent
126-
}
127-
// Otherwise, recursively search for the parent in the replies
128-
return parent.copy(replies = parent.replies.map { child -> addNestedReply(child, reply) })
129-
}
130-
131111
private fun removeNestedReply(
132112
comment: ThreadedCommentData,
133113
commentIdToRemove: String,
@@ -148,24 +128,6 @@ internal class CommentReplyListStateImpl(
148128
)
149129
}
150130

151-
private fun updateNestedReply(
152-
parent: ThreadedCommentData,
153-
updatedComment: CommentData,
154-
): ThreadedCommentData {
155-
// If this comment is the parent, update it directly
156-
if (parent.id == updatedComment.id) {
157-
return parent.update(updatedComment)
158-
}
159-
// If the parent has no replies, return it unchanged
160-
if (parent.replies.isNullOrEmpty()) {
161-
return parent
162-
}
163-
// Otherwise, recursively search for the comment to update in the replies
164-
return parent.copy(
165-
replies = parent.replies.map { child -> updateNestedReply(child, updatedComment) }
166-
)
167-
}
168-
169131
private fun addNestedReplyReaction(
170132
parent: ThreadedCommentData,
171133
comment: CommentData,
@@ -223,13 +185,6 @@ internal interface CommentReplyListStateUpdates {
223185
*/
224186
fun onQueryMoreReplies(result: PaginationResult<ThreadedCommentData>)
225187

226-
/**
227-
* Handles the addition of a new comment reply.
228-
*
229-
* @param comment The comment data for the newly added reply.
230-
*/
231-
fun onCommentAdded(comment: ThreadedCommentData)
232-
233188
/**
234189
* Handles the removal of a comment reply.
235190
*
@@ -238,11 +193,11 @@ internal interface CommentReplyListStateUpdates {
238193
fun onCommentRemoved(commentId: String)
239194

240195
/**
241-
* Handles the update of an existing comment reply.
196+
* Handles the addition or update of a new comment reply.
242197
*
243-
* @param comment The updated comment data for the reply.
198+
* @param comment The comment data for the newly added reply.
244199
*/
245-
fun onCommentUpdated(comment: CommentData)
200+
fun onCommentUpserted(comment: CommentData)
246201

247202
/**
248203
* Handles the addition of a reaction to a comment reply.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ internal class FeedImpl(
379379
.addActivityReaction(activityId, request)
380380
.onSuccess { (reaction, activity) ->
381381
subscriptionManager.onEvent(
382-
StateUpdateEvent.ActivityReactionAdded(fid.rawValue, activity, reaction)
382+
StateUpdateEvent.ActivityReactionUpserted(fid.rawValue, activity, reaction)
383383
)
384384
}
385385
.map { it.first }
@@ -407,7 +407,7 @@ internal class FeedImpl(
407407
.addCommentReaction(commentId, request)
408408
.onSuccess { (reaction, comment) ->
409409
subscriptionManager.onEvent(
410-
StateUpdateEvent.CommentReactionAdded(fid.rawValue, comment, reaction)
410+
StateUpdateEvent.CommentReactionUpserted(fid.rawValue, comment, reaction)
411411
)
412412
}
413413
.map { it.first }

0 commit comments

Comments
 (0)