From cacd38f339f287800ae5858df299b35f6c04fa35 Mon Sep 17 00:00:00 2001 From: Beingpax Date: Fri, 24 Oct 2025 22:31:47 +0545 Subject: [PATCH] Fix SwiftData pagination race by isolating on MainActor --- .../xcshareddata/swiftpm/Package.resolved | 2 +- VoiceInk/Views/TranscriptionHistoryView.swift | 65 +++++++++---------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/VoiceInk.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/VoiceInk.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5f675a5..aad3205 100644 --- a/VoiceInk.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/VoiceInk.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -7,7 +7,7 @@ "location" : "https://github.com/FluidInference/FluidAudio", "state" : { "branch" : "main", - "revision" : "a8f3bc7a3be7a93d7d5d412fdf71ae7922e92d09" + "revision" : "eec3d961f7bfab3d161dd39aeebfc861fcfb25b8" } }, { diff --git a/VoiceInk/Views/TranscriptionHistoryView.swift b/VoiceInk/Views/TranscriptionHistoryView.swift index ebd49d0..1545401 100644 --- a/VoiceInk/Views/TranscriptionHistoryView.swift +++ b/VoiceInk/Views/TranscriptionHistoryView.swift @@ -95,7 +95,9 @@ struct TranscriptionHistoryView: View { if hasMoreContent { Button(action: { - loadMoreContent() + Task { + await loadMoreContent() + } }) { HStack(spacing: 8) { if isLoading { @@ -279,6 +281,7 @@ struct TranscriptionHistoryView: View { ) } + @MainActor private func loadInitialContent() async { isLoading = true defer { isLoading = false } @@ -290,50 +293,44 @@ struct TranscriptionHistoryView: View { // Fetch initial page without a cursor let items = try modelContext.fetch(cursorQueryDescriptor()) - await MainActor.run { - displayedTranscriptions = items - // Update cursor to the timestamp of the last item - lastTimestamp = items.last?.timestamp - // If we got fewer items than the page size, there are no more items - hasMoreContent = items.count == pageSize - } + displayedTranscriptions = items + // Update cursor to the timestamp of the last item + lastTimestamp = items.last?.timestamp + // If we got fewer items than the page size, there are no more items + hasMoreContent = items.count == pageSize } catch { print("Error loading transcriptions: \(error)") } } - private func loadMoreContent() { + @MainActor + private func loadMoreContent() async { guard !isLoading, hasMoreContent, let lastTimestamp = lastTimestamp else { return } - Task { - isLoading = true - defer { isLoading = false } + isLoading = true + defer { isLoading = false } + + do { + // Fetch next page using the cursor + let newItems = try modelContext.fetch(cursorQueryDescriptor(after: lastTimestamp)) - do { - // Fetch next page using the cursor - let newItems = try modelContext.fetch(cursorQueryDescriptor(after: lastTimestamp)) - - await MainActor.run { - // Append new items to the displayed list - displayedTranscriptions.append(contentsOf: newItems) - // Update cursor to the timestamp of the last new item - self.lastTimestamp = newItems.last?.timestamp - // If we got fewer items than the page size, there are no more items - hasMoreContent = newItems.count == pageSize - } - } catch { - print("Error loading more transcriptions: \(error)") - } + // Append new items to the displayed list + displayedTranscriptions.append(contentsOf: newItems) + // Update cursor to the timestamp of the last new item + self.lastTimestamp = newItems.last?.timestamp + // If we got fewer items than the page size, there are no more items + hasMoreContent = newItems.count == pageSize + } catch { + print("Error loading more transcriptions: \(error)") } } - private func resetPagination() async { - await MainActor.run { - displayedTranscriptions = [] - lastTimestamp = nil - hasMoreContent = true - isLoading = false - } + @MainActor + private func resetPagination() { + displayedTranscriptions = [] + lastTimestamp = nil + hasMoreContent = true + isLoading = false } private func deleteTranscription(_ transcription: Transcription) {