Skip to content

Commit ebdf485

Browse files
committed
Queue vote actions while requests run
1 parent 990616e commit ebdf485

File tree

1 file changed

+85
-41
lines changed

1 file changed

+85
-41
lines changed

DesignSystem/Sources/DesignSystem/Components/PostDisplayView.swift

Lines changed: 85 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ public struct PostDisplayView: View {
2727
@State private var displayedUpvoted: Bool
2828
@State private var displayedBookmarked: Bool
2929
@State private var displayedVoteLinks: VoteLinks?
30+
@State private var pendingVoteIntent: VoteIntent?
31+
32+
private enum VoteIntent {
33+
case upvote
34+
case unvote
35+
}
3036

3137
public init(
3238
post: Post,
@@ -127,6 +133,11 @@ public struct PostDisplayView: View {
127133
displayedUpvoted = newValue
128134
}
129135
}
136+
.onChange(of: votingState?.canUnvote) { _ in
137+
if let voteLinks = post.voteLinks {
138+
displayedVoteLinks = voteLinks
139+
}
140+
}
130141
}
131142

132143
private var upvotePill: some View {
@@ -221,58 +232,91 @@ public struct PostDisplayView: View {
221232

222233
private func makeUpvoteAction() -> (() -> Void)? {
223234
return {
224-
guard !isSubmittingUpvote else { return }
225-
226-
let isCurrentlyUpvoted = displayedUpvoted
227235
let currentVoteLinks = displayedVoteLinks ?? post.voteLinks
228236
let canUnvote = currentVoteLinks?.unvote != nil
237+
let intent: VoteIntent = (displayedUpvoted && canUnvote) ? .unvote : .upvote
238+
Task { @MainActor in
239+
handleVoteIntent(intent)
240+
}
241+
}
242+
}
229243

230-
// If already upvoted and can unvote, perform unvote
231-
if isCurrentlyUpvoted && canUnvote {
232-
guard let onUnvoteTap else { return }
233-
isSubmittingUpvote = true
234-
let previousScore = displayedScore
235-
let previousUpvoted = displayedUpvoted
236-
let previousVoteLinks = currentVoteLinks
237-
displayedUpvoted = false
238-
displayedScore -= 1
239-
displayedVoteLinks = VoteLinks(upvote: previousVoteLinks?.upvote, unvote: nil)
240-
Task {
241-
let success = await onUnvoteTap()
242-
await MainActor.run {
243-
if !success {
244-
displayedScore = previousScore
245-
displayedUpvoted = previousUpvoted
246-
displayedVoteLinks = previousVoteLinks
247-
}
248-
isSubmittingUpvote = false
244+
@MainActor
245+
private func handleVoteIntent(_ intent: VoteIntent) {
246+
if isSubmittingUpvote {
247+
pendingVoteIntent = intent
248+
return
249+
}
250+
executeVoteIntent(intent)
251+
}
252+
253+
@MainActor
254+
private func executeVoteIntent(_ intent: VoteIntent) {
255+
pendingVoteIntent = nil
256+
257+
let currentVoteLinks = displayedVoteLinks ?? post.voteLinks
258+
let previousScore = displayedScore
259+
let previousUpvoted = displayedUpvoted
260+
let previousVoteLinks = currentVoteLinks
261+
262+
switch intent {
263+
case .unvote:
264+
guard let onUnvoteTap else { return }
265+
guard displayedUpvoted else { return }
266+
267+
isSubmittingUpvote = true
268+
displayedUpvoted = false
269+
displayedScore -= 1
270+
displayedVoteLinks = VoteLinks(upvote: previousVoteLinks?.upvote, unvote: nil)
271+
272+
Task {
273+
let success = await onUnvoteTap()
274+
await MainActor.run {
275+
if !success {
276+
displayedScore = previousScore
277+
displayedUpvoted = previousUpvoted
278+
displayedVoteLinks = previousVoteLinks
249279
}
280+
isSubmittingUpvote = false
281+
processPendingVoteIntentIfNeeded()
250282
}
251-
} else {
252-
// Perform upvote
253-
guard let onUpvoteTap else { return }
254-
isSubmittingUpvote = true
255-
let previousScore = displayedScore
256-
let previousUpvoted = displayedUpvoted
257-
let previousVoteLinks = currentVoteLinks
258-
displayedUpvoted = true
259-
displayedScore += 1
260-
displayedVoteLinks = derivedVoteLinks(afterUpvoteFrom: previousVoteLinks)
261-
Task {
262-
let success = await onUpvoteTap()
263-
await MainActor.run {
264-
if !success {
265-
displayedScore = previousScore
266-
displayedUpvoted = previousUpvoted
267-
displayedVoteLinks = previousVoteLinks
268-
}
269-
isSubmittingUpvote = false
283+
}
284+
285+
case .upvote:
286+
guard let onUpvoteTap else { return }
287+
guard !displayedUpvoted else { return }
288+
guard currentVoteLinks?.upvote != nil else { return }
289+
290+
isSubmittingUpvote = true
291+
displayedUpvoted = true
292+
displayedScore += 1
293+
displayedVoteLinks = derivedVoteLinks(afterUpvoteFrom: previousVoteLinks)
294+
295+
Task {
296+
let success = await onUpvoteTap()
297+
await MainActor.run {
298+
if !success {
299+
displayedScore = previousScore
300+
displayedUpvoted = previousUpvoted
301+
displayedVoteLinks = previousVoteLinks
302+
} else {
303+
displayedVoteLinks = derivedVoteLinks(afterUpvoteFrom: displayedVoteLinks ?? previousVoteLinks)
270304
}
305+
isSubmittingUpvote = false
306+
processPendingVoteIntentIfNeeded()
271307
}
272308
}
273309
}
274310
}
275311

312+
@MainActor
313+
private func processPendingVoteIntentIfNeeded() {
314+
if let nextIntent = pendingVoteIntent {
315+
pendingVoteIntent = nil
316+
handleVoteIntent(nextIntent)
317+
}
318+
}
319+
276320
private func derivedVoteLinks(afterUpvoteFrom voteLinks: VoteLinks?) -> VoteLinks? {
277321
guard let voteLinks else { return nil }
278322
if voteLinks.unvote != nil {

0 commit comments

Comments
 (0)