From 3f723942d438075a1c5258e6af4abaf47f1fa928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Sun, 15 Feb 2026 23:26:16 +0100 Subject: [PATCH] add transcription back after stop recording Transcription runs in the View via Task after saving the memo. Speech authorization is requested when the recording sheet opens. Shows transcribing indicator. Record button disabled during transcription. Co-Authored-By: Claude Opus 4.6 --- VoiceDiary/Views/RecordingView.swift | 44 +++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/VoiceDiary/Views/RecordingView.swift b/VoiceDiary/Views/RecordingView.swift index 61209ec..b40864b 100644 --- a/VoiceDiary/Views/RecordingView.swift +++ b/VoiceDiary/Views/RecordingView.swift @@ -5,6 +5,8 @@ struct RecordingView: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss var viewModel: RecordingViewModel + @State private var transcriptionService = TranscriptionService() + @State private var isTranscribing = false var body: some View { NavigationStack { @@ -15,6 +17,16 @@ struct RecordingView: View { recordButton + if isTranscribing { + HStack(spacing: 8) { + ProgressView() + .controlSize(.small) + Text(String(localized: "memo.transcribing")) + .font(.subheadline) + .foregroundStyle(.secondary) + } + } + Spacer() if let error = viewModel.error { @@ -33,13 +45,18 @@ struct RecordingView: View { Button(String(localized: "general.done")) { if viewModel.isRecording { viewModel.stopRecording() + saveAndTranscribe() } - saveRecordingIfNeeded() dismiss() } } } } + .task { + if transcriptionService.authorizationStatus == .notDetermined { + await transcriptionService.requestAuthorization() + } + } } private var timerDisplay: some View { @@ -55,7 +72,7 @@ struct RecordingView: View { Button { if viewModel.isRecording { viewModel.stopRecording() - saveRecordingIfNeeded() + saveAndTranscribe() } else { viewModel.startRecording() } @@ -76,6 +93,7 @@ struct RecordingView: View { } } } + .disabled(isTranscribing) .accessibilityLabel( viewModel.isRecording ? String(localized: "recording.stop") @@ -84,7 +102,7 @@ struct RecordingView: View { .sensoryFeedback(.impact, trigger: viewModel.isRecording) } - private func saveRecordingIfNeeded() { + private func saveAndTranscribe() { guard let recorded = viewModel.lastRecordedFile else { return } let today = Calendar.current.startOfDay(for: .now) @@ -93,8 +111,26 @@ struct RecordingView: View { let memo = VoiceMemo(audioFileName: recorded.fileName, duration: recorded.duration) memo.entry = entry modelContext.insert(memo) - viewModel.lastRecordedFile = nil + + let audioURL = recorded.url + Task { + await transcribe(memo: memo, audioURL: audioURL) + } + } + + private func transcribe(memo: VoiceMemo, audioURL: URL) async { + guard transcriptionService.authorizationStatus == .authorized else { return } + + isTranscribing = true + defer { isTranscribing = false } + + do { + let transcript = try await transcriptionService.transcribe(audioURL: audioURL) + memo.transcript = transcript + } catch { + viewModel.error = error + } } private func fetchOrCreateEntry(for date: Date) -> DiaryEntry {