Skip to content

Commit f83cde2

Browse files
gpuntoCopilotaleksandar-apostolovVelikovPetar
authored
Handle enforce unique for reactions (#129)
* Handle enforceUnique for comment reactions for ActivityCommentList * Handle enforceUnique for comment reactions for CommentList & CommentReplyList * Handle enforceUnique for comment reactions for ActivityList * Handle enforceUnique for comment reactions for Feed * Handle enforceUnique for comment reactions for Activity * Handle enforceUnique for comment reactions for CommentReactionList * Handle enforceUnique for activity reactions for Activity * Handle enforceUnique for activity reactions for Feed * Handle enforceUnique for activity reactions for ActivityList * Make userReactionsGroupId internal * Update stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/internal/utils/List.kt Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Aleksandar Apostolov <[email protected]> Co-authored-by: Petar Velikov <[email protected]>
1 parent 7325633 commit f83cde2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+593
-109
lines changed

stream-feeds-android-client/src/main/kotlin/io/getstream/feeds/android/client/api/model/FeedsReactionData.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public data class FeedsReactionData(
3838
) {
3939

4040
/** Unique identifier for the reaction. */
41-
public val id: String
42-
get() = "${activityId}${commentId}${user.id}${type}"
41+
public val id: String = "${activityId}${commentId}${user.id}${type}"
42+
43+
/** Identifier for grouping a user's reactions. */
44+
internal val userReactionsGroupId: String = "${activityId}${commentId}${user.id}"
4345
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,9 @@ internal fun ActivityData.upsertReaction(
185185
updated: ActivityData,
186186
reaction: FeedsReactionData,
187187
currentUserId: String,
188+
enforceUnique: Boolean,
188189
): ActivityData =
189-
changeReactions(updated, reaction, currentUserId) { upsert(reaction, FeedsReactionData::id) }
190+
changeReactions(updated, reaction, currentUserId) { upsertReaction(reaction, enforceUnique) }
190191

191192
/**
192193
* Merges the receiver activity with [updated] and updates own reactions using the provided
@@ -232,10 +233,11 @@ internal fun ActivityData.upsertCommentReaction(
232233
updated: CommentData,
233234
reaction: FeedsReactionData,
234235
currentUserId: String,
236+
enforceUnique: Boolean,
235237
): ActivityData =
236238
copy(
237239
comments =
238240
comments.updateIf({ it.id == updated.id }) { comment ->
239-
comment.upsertReaction(updated, reaction, currentUserId)
241+
comment.upsertReaction(updated, reaction, currentUserId, enforceUnique)
240242
}
241243
)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ package io.getstream.feeds.android.client.internal.model
1717

1818
import io.getstream.feeds.android.client.api.model.CommentData
1919
import io.getstream.feeds.android.client.api.model.FeedsReactionData
20-
import io.getstream.feeds.android.client.api.model.toModel
21-
import io.getstream.feeds.android.client.internal.utils.upsert
2220
import io.getstream.feeds.android.network.models.CommentResponse
2321

2422
/** Converts a [CommentResponse] to a [CommentData] model. */
@@ -84,14 +82,16 @@ internal fun CommentData.removeReaction(
8482
* @param reaction The reaction to be added.
8583
* @param currentUserId The ID of the current user, used to determine if the reaction belongs to
8684
* them.
85+
* @param enforceUnique Whether to replace existing reactions by the same user.
8786
* @return A new [CommentData] instance with the updated reactions and counts.
8887
*/
8988
internal fun CommentData.upsertReaction(
9089
updated: CommentData,
9190
reaction: FeedsReactionData,
9291
currentUserId: String,
92+
enforceUnique: Boolean,
9393
): CommentData =
94-
changeReactions(updated, reaction, currentUserId) { upsert(reaction, FeedsReactionData::id) }
94+
changeReactions(updated, reaction, currentUserId) { upsertReaction(reaction, enforceUnique) }
9595

9696
internal inline fun CommentData.changeReactions(
9797
updated: CommentData,

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package io.getstream.feeds.android.client.internal.model
1717

1818
import io.getstream.feeds.android.client.api.model.FeedsReactionData
19+
import io.getstream.feeds.android.client.internal.utils.insertUniqueBy
20+
import io.getstream.feeds.android.client.internal.utils.upsert
1921
import io.getstream.feeds.android.network.models.FeedsReactionResponse
2022

2123
/**
@@ -32,3 +34,17 @@ internal fun FeedsReactionResponse.toModel(): FeedsReactionData =
3234
updatedAt = updatedAt,
3335
user = user.toModel(),
3436
)
37+
38+
/**
39+
* Inserts or updates a reaction in the list. If [enforceUnique] is true, it ensures that only one
40+
* reaction per user exists in the list.
41+
*/
42+
internal fun List<FeedsReactionData>.upsertReaction(
43+
reaction: FeedsReactionData,
44+
enforceUnique: Boolean,
45+
): List<FeedsReactionData> =
46+
if (enforceUnique) {
47+
insertUniqueBy(reaction, FeedsReactionData::userReactionsGroupId)
48+
} else {
49+
upsert(reaction, FeedsReactionData::id)
50+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ internal fun ThreadedCommentData.upsertReaction(
118118
updated: CommentData,
119119
reaction: FeedsReactionData,
120120
currentUserId: String,
121+
enforceUnique: Boolean,
121122
): ThreadedCommentData =
122-
changeReactions(updated, reaction, currentUserId) { upsert(reaction, FeedsReactionData::id) }
123+
changeReactions(updated, reaction, currentUserId) { upsertReaction(reaction, enforceUnique) }
123124

124125
/**
125126
* Merges the receiver comment with [updated] and updates own reactions using the provided

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,14 @@ internal class ActivityCommentListStateImpl(
103103
}
104104
}
105105

106-
override fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData) {
107-
_comments.update { current -> current.map { upsertCommentReaction(it, comment, reaction) } }
106+
override fun onCommentReactionUpserted(
107+
comment: CommentData,
108+
reaction: FeedsReactionData,
109+
enforceUnique: Boolean,
110+
) {
111+
_comments.update { current ->
112+
current.map { upsertCommentReaction(it, comment, reaction, enforceUnique) }
113+
}
108114
}
109115

110116
override fun onCommentReactionRemoved(comment: CommentData, reaction: FeedsReactionData) {
@@ -115,18 +121,21 @@ internal class ActivityCommentListStateImpl(
115121
comment: ThreadedCommentData,
116122
update: CommentData,
117123
reaction: FeedsReactionData,
124+
enforceUnique: Boolean,
118125
): ThreadedCommentData {
119126
if (comment.id == update.id) {
120127
// If this comment matches the target, upsert the reaction
121-
return comment.upsertReaction(update, reaction, currentUserId)
128+
return comment.upsertReaction(update, reaction, currentUserId, enforceUnique)
122129
}
123130
if (comment.replies.isNullOrEmpty()) {
124131
// If there are no replies, return unchanged
125132
return comment
126133
}
127134
// Recursively search through replies
128135
val updatedReplies =
129-
comment.replies.map { reply -> upsertCommentReaction(reply, update, reaction) }
136+
comment.replies.map { reply ->
137+
upsertCommentReaction(reply, update, reaction, enforceUnique)
138+
}
130139
return comment.copy(replies = updatedReplies)
131140
}
132141

@@ -186,8 +195,13 @@ internal interface ActivityCommentListStateUpdates {
186195
*
187196
* @param comment The comment the reaction belongs to.
188197
* @param reaction The reaction data that was added.
198+
* @param enforceUnique Whether to replace existing reactions by the same user.
189199
*/
190-
fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData)
200+
fun onCommentReactionUpserted(
201+
comment: CommentData,
202+
reaction: FeedsReactionData,
203+
enforceUnique: Boolean,
204+
)
191205

192206
/**
193207
* Handles the removal of a reaction from a comment.

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,12 @@ internal class ActivityImpl(
164164
.addCommentReaction(commentId, request)
165165
.onSuccess { (reaction, comment) ->
166166
subscriptionManager.onEvent(
167-
StateUpdateEvent.CommentReactionUpserted(fid.rawValue, comment, reaction)
167+
StateUpdateEvent.CommentReactionUpserted(
168+
fid = fid.rawValue,
169+
comment = comment,
170+
reaction = reaction,
171+
enforceUnique = request.enforceUnique == true,
172+
)
168173
)
169174
}
170175
.map { it.first }

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,14 @@ internal class ActivityListStateImpl(
144144
}
145145
}
146146

147-
override fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData) {
147+
override fun onCommentReactionUpserted(
148+
comment: CommentData,
149+
reaction: FeedsReactionData,
150+
enforceUnique: Boolean,
151+
) {
148152
_activities.update { current ->
149153
current.updateIf({ it.id == comment.objectId }) { activity ->
150-
activity.upsertCommentReaction(comment, reaction, currentUserId)
154+
activity.upsertCommentReaction(comment, reaction, currentUserId, enforceUnique)
151155
}
152156
}
153157
}
@@ -182,10 +186,14 @@ internal class ActivityListStateImpl(
182186
}
183187
}
184188

185-
override fun onReactionUpserted(reaction: FeedsReactionData, activity: ActivityData) {
189+
override fun onReactionUpserted(
190+
reaction: FeedsReactionData,
191+
activity: ActivityData,
192+
enforceUnique: Boolean,
193+
) {
186194
_activities.update { current ->
187195
current.updateIf({ it.id == reaction.activityId }) {
188-
it.upsertReaction(activity, reaction, currentUserId)
196+
it.upsertReaction(activity, reaction, currentUserId, enforceUnique)
189197
}
190198
}
191199
}
@@ -276,8 +284,13 @@ internal interface ActivityListStateUpdates {
276284
*
277285
* @param comment The comment the reaction belongs to.
278286
* @param reaction The reaction that was added or updated.
287+
* @param enforceUnique Whether to replace existing reactions by the same user.
279288
*/
280-
fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData)
289+
fun onCommentReactionUpserted(
290+
comment: CommentData,
291+
reaction: FeedsReactionData,
292+
enforceUnique: Boolean,
293+
)
281294

282295
/**
283296
* Called when a poll is deleted.
@@ -314,8 +327,13 @@ internal interface ActivityListStateUpdates {
314327
*
315328
* @param reaction The reaction that was added.
316329
* @param activity The activity the reaction belongs to.
330+
* @param enforceUnique Whether to replace existing reactions by the same user.
317331
*/
318-
fun onReactionUpserted(reaction: FeedsReactionData, activity: ActivityData)
332+
fun onReactionUpserted(
333+
reaction: FeedsReactionData,
334+
activity: ActivityData,
335+
enforceUnique: Boolean,
336+
)
319337

320338
/**
321339
* Called when a reaction is removed from an activity.

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

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,14 @@ internal class ActivityStateImpl(
8383
}
8484
}
8585

86-
override fun onReactionUpserted(reaction: FeedsReactionData, activity: ActivityData) {
87-
_activity.update { current -> current?.upsertReaction(activity, reaction, currentUserId) }
86+
override fun onReactionUpserted(
87+
reaction: FeedsReactionData,
88+
activity: ActivityData,
89+
enforceUnique: Boolean,
90+
) {
91+
_activity.update { current ->
92+
current?.upsertReaction(activity, reaction, currentUserId, enforceUnique)
93+
}
8894
}
8995

9096
override fun onReactionRemoved(reaction: FeedsReactionData, activity: ActivityData) {
@@ -113,9 +119,13 @@ internal class ActivityStateImpl(
113119
}
114120
}
115121

116-
override fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData) {
122+
override fun onCommentReactionUpserted(
123+
comment: CommentData,
124+
reaction: FeedsReactionData,
125+
enforceUnique: Boolean,
126+
) {
117127
_activity.update { current ->
118-
current?.upsertCommentReaction(comment, reaction, currentUserId)
128+
current?.upsertCommentReaction(comment, reaction, currentUserId, enforceUnique)
119129
}
120130
}
121131

@@ -175,8 +185,13 @@ internal interface ActivityStateUpdates {
175185
*
176186
* @param reaction The reaction that was added or updated.
177187
* @param activity The activity the reaction belongs to.
188+
* @param enforceUnique Whether to replace existing reactions by the same user.
178189
*/
179-
fun onReactionUpserted(reaction: FeedsReactionData, activity: ActivityData)
190+
fun onReactionUpserted(
191+
reaction: FeedsReactionData,
192+
activity: ActivityData,
193+
enforceUnique: Boolean,
194+
)
180195

181196
/**
182197
* Called when a reaction is removed from the activity.
@@ -227,8 +242,13 @@ internal interface ActivityStateUpdates {
227242
*
228243
* @param comment The comment to which the reaction was added or updated.
229244
* @param reaction The reaction that was added or updated.
245+
* @param enforceUnique Whether to replace existing reactions by the same user.
230246
*/
231-
fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData)
247+
fun onCommentReactionUpserted(
248+
comment: CommentData,
249+
reaction: FeedsReactionData,
250+
enforceUnique: Boolean,
251+
)
232252

233253
/**
234254
* Called when the associated poll is deleted.

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,14 @@ internal class CommentListStateImpl(
9696
}
9797
}
9898

99-
override fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData) {
99+
override fun onCommentReactionUpserted(
100+
comment: CommentData,
101+
reaction: FeedsReactionData,
102+
enforceUnique: Boolean,
103+
) {
100104
_comments.update { current ->
101105
current.updateIf({ it.id == comment.id }) {
102-
it.upsertReaction(comment, reaction, currentUserId)
106+
it.upsertReaction(comment, reaction, currentUserId, enforceUnique)
103107
}
104108
}
105109
}
@@ -146,6 +150,11 @@ internal interface CommentListStateUpdates {
146150
*
147151
* @param comment The comment to which the reaction was added or updated.
148152
* @param reaction The reaction that was added or updated.
153+
* @param enforceUnique Whether to replace existing reactions by the same user.
149154
*/
150-
fun onCommentReactionUpserted(comment: CommentData, reaction: FeedsReactionData)
155+
fun onCommentReactionUpserted(
156+
comment: CommentData,
157+
reaction: FeedsReactionData,
158+
enforceUnique: Boolean,
159+
)
151160
}

0 commit comments

Comments
 (0)