Skip to content

Commit 0b18189

Browse files
authored
Migrate Activity to consuming and firing state update events (#91)
* Migrate Activity to consuming state update events * Let Activity fire state update events instead of updating the state directly
1 parent ce494c8 commit 0b18189

File tree

11 files changed

+267
-372
lines changed

11 files changed

+267
-372
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ internal class FeedsClientImpl(
224224
commentsRepository = commentsRepository,
225225
pollsRepository = pollsRepository,
226226
subscriptionManager = stateEventsSubscriptionManager,
227-
socketSubscriptionManager = feedsEventsSubscriptionManager,
228227
commentList =
229228
ActivityCommentListImpl(
230229
query =

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

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,17 @@ import io.getstream.feeds.android.client.api.model.PollData
2525
import io.getstream.feeds.android.client.api.model.PollOptionData
2626
import io.getstream.feeds.android.client.api.model.PollVoteData
2727
import io.getstream.feeds.android.client.api.model.ThreadedCommentData
28+
import io.getstream.feeds.android.client.api.model.addOption
29+
import io.getstream.feeds.android.client.api.model.removeOption
2830
import io.getstream.feeds.android.client.api.model.request.ActivityAddCommentRequest
31+
import io.getstream.feeds.android.client.api.model.updateOption
2932
import io.getstream.feeds.android.client.api.state.Activity
3033
import io.getstream.feeds.android.client.api.state.ActivityState
3134
import io.getstream.feeds.android.client.internal.repository.ActivitiesRepository
3235
import io.getstream.feeds.android.client.internal.repository.CommentsRepository
3336
import io.getstream.feeds.android.client.internal.repository.PollsRepository
3437
import io.getstream.feeds.android.client.internal.state.event.StateUpdateEvent
3538
import io.getstream.feeds.android.client.internal.state.event.handler.ActivityEventHandler
36-
import io.getstream.feeds.android.client.internal.subscribe.FeedsEventListener
3739
import io.getstream.feeds.android.client.internal.subscribe.StateUpdateEventListener
3840
import io.getstream.feeds.android.client.internal.subscribe.onEvent
3941
import io.getstream.feeds.android.client.internal.utils.flatMap
@@ -62,8 +64,6 @@ import io.getstream.feeds.android.network.models.UpdatePollRequest
6264
* @property pollsRepository The repository used to fetch and manage polls.
6365
* @property commentList The list of comments associated with this activity.
6466
* @property subscriptionManager The manager for state update subscriptions.
65-
* @property socketSubscriptionManager The manager for WebSocket subscriptions to receive real-time
66-
* updates.
6767
*/
6868
internal class ActivityImpl(
6969
override val activityId: String,
@@ -74,7 +74,6 @@ internal class ActivityImpl(
7474
private val pollsRepository: PollsRepository,
7575
private val commentList: ActivityCommentListImpl,
7676
private val subscriptionManager: StreamSubscriptionManager<StateUpdateEventListener>,
77-
socketSubscriptionManager: StreamSubscriptionManager<FeedsEventListener>,
7877
) : Activity {
7978

8079
private val _state: ActivityStateImpl = ActivityStateImpl(currentUserId, commentList.state)
@@ -83,15 +82,17 @@ internal class ActivityImpl(
8382
ActivityEventHandler(fid = fid, activityId = activityId, state = _state)
8483

8584
init {
86-
socketSubscriptionManager.subscribe(eventHandler)
85+
subscriptionManager.subscribe(eventHandler)
8786
}
8887

8988
override val state: ActivityState
9089
get() = _state
9190

9291
override suspend fun get(): Result<ActivityData> {
9392
val activity =
94-
activitiesRepository.getActivity(activityId).onSuccess { _state.onActivityUpdated(it) }
93+
activitiesRepository.getActivity(activityId).onSuccess {
94+
subscriptionManager.onEvent(StateUpdateEvent.ActivityUpdated(fid.rawValue, it))
95+
}
9596
// Query the comments as well (state will be updated automatically)
9697
queryComments()
9798
return activity
@@ -135,7 +136,9 @@ internal class ActivityImpl(
135136
.deleteComment(commentId, hardDelete)
136137
.onSuccess { (comment, activity) ->
137138
subscriptionManager.onEvent(StateUpdateEvent.CommentDeleted(comment))
138-
_state.onActivityUpdated(activity)
139+
subscriptionManager.onEvent(
140+
StateUpdateEvent.ActivityUpdated(fid.rawValue, activity)
141+
)
139142
}
140143
.map {}
141144
}
@@ -180,105 +183,133 @@ internal class ActivityImpl(
180183
override suspend fun pin(): Result<Unit> {
181184
return activitiesRepository
182185
.pin(activityId, fid)
183-
.onSuccess { _state.onActivityUpdated(it) }
186+
.onSuccess {
187+
subscriptionManager.onEvent(StateUpdateEvent.ActivityUpdated(fid.rawValue, it))
188+
}
184189
.map { Unit }
185190
}
186191

187192
override suspend fun unpin(): Result<Unit> {
188193
return activitiesRepository
189194
.unpin(activityId, fid)
190-
.onSuccess { _state.onActivityUpdated(it) }
195+
.onSuccess {
196+
subscriptionManager.onEvent(StateUpdateEvent.ActivityUpdated(fid.rawValue, it))
197+
}
191198
.map { Unit }
192199
}
193200

194201
override suspend fun closePoll(): Result<PollData> {
195-
return pollId().flatMap { pollId ->
196-
pollsRepository.closePoll(pollId = pollId).onSuccess { _state.onPollUpdated(it) }
202+
return poll().flatMap { poll ->
203+
pollsRepository.closePoll(pollId = poll.id).onSuccess {
204+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, it))
205+
}
197206
}
198207
}
199208

200209
override suspend fun deletePoll(userId: String?): Result<Unit> {
201-
return pollId().flatMap { pollId ->
202-
pollsRepository.deletePoll(pollId = pollId, userId = userId).onSuccess {
203-
_state.onPollDeleted(pollId)
210+
return poll().flatMap { poll ->
211+
pollsRepository.deletePoll(pollId = poll.id, userId = userId).onSuccess {
212+
subscriptionManager.onEvent(StateUpdateEvent.PollDeleted(fid.rawValue, poll.id))
204213
}
205214
}
206215
}
207216

208217
override suspend fun getPoll(userId: String?): Result<PollData> {
209-
return pollId().flatMap { pollId ->
210-
pollsRepository.getPoll(pollId = pollId, userId = userId).onSuccess {
211-
_state.onPollUpdated(it)
218+
return poll().flatMap { poll ->
219+
pollsRepository.getPoll(pollId = poll.id, userId = userId).onSuccess {
220+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, it))
212221
}
213222
}
214223
}
215224

216225
override suspend fun updatePollPartial(request: UpdatePollPartialRequest): Result<PollData> {
217-
return pollId().flatMap { pollId ->
218-
pollsRepository.updatePollPartial(pollId, request).onSuccess {
219-
_state.onPollUpdated(it)
226+
return poll().flatMap { poll ->
227+
pollsRepository.updatePollPartial(poll.id, request).onSuccess {
228+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, it))
220229
}
221230
}
222231
}
223232

224233
override suspend fun updatePoll(request: UpdatePollRequest): Result<PollData> {
225-
return pollsRepository.updatePoll(request).onSuccess { _state.onPollUpdated(it) }
234+
return pollsRepository.updatePoll(request).onSuccess {
235+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, it))
236+
}
226237
}
227238

228239
override suspend fun createPollOption(
229240
request: CreatePollOptionRequest
230241
): Result<PollOptionData> {
231-
return pollId().flatMap { pollId ->
232-
pollsRepository.createPollOption(pollId, request).onSuccess {
233-
_state.onOptionCreated(it)
242+
return poll().flatMap { poll ->
243+
pollsRepository.createPollOption(poll.id, request).onSuccess {
244+
val newPoll = poll.addOption(it)
245+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, newPoll))
234246
}
235247
}
236248
}
237249

238250
override suspend fun deletePollOption(optionId: String, userId: String?): Result<Unit> {
239-
return pollId().flatMap { pollId ->
251+
return poll().flatMap { poll ->
240252
pollsRepository
241-
.deletePollOption(pollId = pollId, optionId = optionId, userId = userId)
242-
.onSuccess { _state.onOptionDeleted(optionId) }
253+
.deletePollOption(pollId = poll.id, optionId = optionId, userId = userId)
254+
.onSuccess {
255+
val newPoll = poll.removeOption(optionId)
256+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, newPoll))
257+
}
243258
}
244259
}
245260

246261
override suspend fun getPollOption(optionId: String, userId: String?): Result<PollOptionData> {
247-
return pollId().flatMap { pollId ->
262+
return poll().flatMap { poll ->
248263
pollsRepository
249-
.getPollOption(pollId = pollId, optionId = optionId, userId = userId)
250-
.onSuccess { _state.onOptionUpdated(it) }
264+
.getPollOption(pollId = poll.id, optionId = optionId, userId = userId)
265+
.onSuccess {
266+
val newPoll = poll.updateOption(it)
267+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, newPoll))
268+
}
251269
}
252270
}
253271

254272
override suspend fun updatePollOption(
255273
request: UpdatePollOptionRequest
256274
): Result<PollOptionData> {
257-
return pollId().flatMap { pollId ->
258-
pollsRepository.updatePollOption(pollId, request).onSuccess {
259-
_state.onOptionUpdated(it)
275+
return poll().flatMap { poll ->
276+
pollsRepository.updatePollOption(poll.id, request).onSuccess {
277+
val newPoll = poll.updateOption(it)
278+
subscriptionManager.onEvent(StateUpdateEvent.PollUpdated(fid.rawValue, newPoll))
260279
}
261280
}
262281
}
263282

264283
override suspend fun castPollVote(request: CastPollVoteRequest): Result<PollVoteData?> {
265-
return pollId().flatMap { pollId ->
284+
return poll().flatMap { poll ->
266285
pollsRepository
267-
.castPollVote(activityId = activityId, pollId = pollId, request = request)
268-
.onSuccess { it?.let { vote -> _state.onPollVoteCasted(vote, pollId) } }
286+
.castPollVote(activityId = activityId, pollId = poll.id, request = request)
287+
.onSuccess {
288+
it?.let { vote ->
289+
subscriptionManager.onEvent(
290+
StateUpdateEvent.PollVoteCasted(fid.rawValue, poll.id, vote)
291+
)
292+
}
293+
}
269294
}
270295
}
271296

272297
override suspend fun deletePollVote(voteId: String, userId: String?): Result<PollVoteData?> {
273-
return pollId().flatMap { pollId ->
298+
return poll().flatMap { poll ->
274299
pollsRepository
275300
.deletePollVote(
276301
activityId = activityId,
277-
pollId = pollId,
302+
pollId = poll.id,
278303
voteId = voteId,
279304
userId = userId,
280305
)
281-
.onSuccess { it?.let { vote -> _state.onPollVoteRemoved(vote, pollId) } }
306+
.onSuccess {
307+
it?.let { vote ->
308+
subscriptionManager.onEvent(
309+
StateUpdateEvent.PollVoteRemoved(fid.rawValue, poll.id, vote)
310+
)
311+
}
312+
}
282313
}
283314
}
284315

@@ -291,11 +322,11 @@ internal class ActivityImpl(
291322
}
292323
}
293324

294-
private suspend fun pollId(): Result<String> {
325+
private suspend fun poll(): Result<PollData> {
295326
return ensureActivityLoaded().flatMap {
296327
val poll = it.poll
297328
if (poll != null) {
298-
Result.success(poll.id)
329+
Result.success(poll)
299330
} else {
300331
Result.failure(IllegalStateException("Activity does not have a poll"))
301332
}

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

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,16 @@ import io.getstream.feeds.android.client.api.model.ActivityData
1919
import io.getstream.feeds.android.client.api.model.BookmarkData
2020
import io.getstream.feeds.android.client.api.model.FeedsReactionData
2121
import io.getstream.feeds.android.client.api.model.PollData
22-
import io.getstream.feeds.android.client.api.model.PollOptionData
2322
import io.getstream.feeds.android.client.api.model.PollVoteData
2423
import io.getstream.feeds.android.client.api.model.ThreadedCommentData
2524
import io.getstream.feeds.android.client.api.model.addBookmark
26-
import io.getstream.feeds.android.client.api.model.addOption
2725
import io.getstream.feeds.android.client.api.model.addReaction
2826
import io.getstream.feeds.android.client.api.model.castVote
2927
import io.getstream.feeds.android.client.api.model.deleteBookmark
30-
import io.getstream.feeds.android.client.api.model.removeOption
3128
import io.getstream.feeds.android.client.api.model.removeReaction
3229
import io.getstream.feeds.android.client.api.model.removeVote
3330
import io.getstream.feeds.android.client.api.model.setClosed
3431
import io.getstream.feeds.android.client.api.model.update
35-
import io.getstream.feeds.android.client.api.model.updateOption
3632
import io.getstream.feeds.android.client.api.state.ActivityCommentListState
3733
import io.getstream.feeds.android.client.api.state.ActivityState
3834
import kotlinx.coroutines.flow.MutableStateFlow
@@ -95,48 +91,32 @@ internal class ActivityStateImpl(
9591
}
9692

9793
override fun onPollClosed(poll: PollData) {
98-
if (_poll.value?.id != poll.id) return
99-
updatePoll(PollData::setClosed)
94+
updatePoll(poll.id, PollData::setClosed)
10095
}
10196

10297
override fun onPollDeleted(pollId: String) {
103-
if (_poll.value?.id != pollId) return
104-
updatePoll { null }
98+
updatePoll(pollId) { null }
10599
}
106100

107101
override fun onPollUpdated(poll: PollData) {
108-
if (_poll.value?.id != poll.id) return
109-
updatePoll { update(poll) }
110-
}
111-
112-
override fun onOptionCreated(option: PollOptionData) {
113-
updatePoll { addOption(option) }
114-
}
115-
116-
override fun onOptionDeleted(optionId: String) {
117-
updatePoll { removeOption(optionId) }
118-
}
119-
120-
override fun onOptionUpdated(option: PollOptionData) {
121-
updatePoll { updateOption(option) }
102+
updatePoll(poll.id) { update(poll) }
122103
}
123104

124105
override fun onPollVoteCasted(vote: PollVoteData, pollId: String) {
125-
if (_poll.value?.id != pollId) return
126-
updatePoll { castVote(vote, currentUserId) }
106+
updatePoll(pollId) { castVote(vote, currentUserId) }
127107
}
128108

129109
override fun onPollVoteChanged(vote: PollVoteData, pollId: String) {
130-
if (_poll.value?.id != pollId) return
131-
updatePoll { castVote(vote, currentUserId) }
110+
updatePoll(pollId) { castVote(vote, currentUserId) }
132111
}
133112

134113
override fun onPollVoteRemoved(vote: PollVoteData, pollId: String) {
135-
if (_poll.value?.id != pollId) return
136-
updatePoll { removeVote(vote, currentUserId) }
114+
updatePoll(pollId) { removeVote(vote, currentUserId) }
137115
}
138116

139-
private fun updatePoll(update: PollData.() -> PollData?) {
117+
private fun updatePoll(pollId: String, update: PollData.() -> PollData?) {
118+
if (_poll.value?.id != pollId) return
119+
140120
var updated: PollData? = null
141121
_poll.update { current -> current?.let(update).also { updated = it } }
142122
_activity.update { current -> current?.copy(poll = updated) }
@@ -216,27 +196,6 @@ internal interface ActivityStateUpdates {
216196
*/
217197
fun onPollUpdated(poll: PollData)
218198

219-
/**
220-
* Called when a new poll option is created.
221-
*
222-
* @param option The newly created poll option data.
223-
*/
224-
fun onOptionCreated(option: PollOptionData)
225-
226-
/**
227-
* Called when a poll option is deleted.
228-
*
229-
* @param optionId The poll option ID that was deleted.
230-
*/
231-
fun onOptionDeleted(optionId: String)
232-
233-
/**
234-
* Called when a poll option is updated.
235-
*
236-
* @param option The updated poll option data.
237-
*/
238-
fun onOptionUpdated(option: PollOptionData)
239-
240199
/**
241200
* Called when a vote is casted on the poll.
242201
*

0 commit comments

Comments
 (0)