diff --git a/Sources/VoiceMemo/AudioRecorder.swift b/Sources/VoiceMemo/AudioRecorder.swift index 080d489..a1395d8 100644 --- a/Sources/VoiceMemo/AudioRecorder.swift +++ b/Sources/VoiceMemo/AudioRecorder.swift @@ -10,6 +10,7 @@ class AudioRecorder: NSObject, ObservableObject, SCStreamOutput, SCStreamDelegat @Published var availableApps: [SCRunningApplication] = [] @Published var selectedApp: SCRunningApplication? @Published var latestTask: MeetingTask? + @Published var recordingDuration: TimeInterval = 0 var lastUploadedURL: URL? { if let urlStr = latestTask?.ossUrl { @@ -19,6 +20,7 @@ class AudioRecorder: NSObject, ObservableObject, SCStreamOutput, SCStreamDelegat } private var notificationObserver: NSObjectProtocol? + private var timer: Timer? private var settings: SettingsStore private var recordingId: String? @@ -115,6 +117,14 @@ class AudioRecorder: NSObject, ObservableObject, SCStreamOutput, SCStreamDelegat isFirstRemoteBuffer = true isFirstMicBuffer = true self.recordingStartTime = Date() + self.recordingDuration = 0 + + DispatchQueue.main.async { + self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { [weak self] _ in + guard let self = self, let startTime = self.recordingStartTime else { return } + self.recordingDuration = Date().timeIntervalSince(startTime) + } + } // Generate URLs let formatter = DateFormatter() @@ -323,6 +333,11 @@ class AudioRecorder: NSObject, ObservableObject, SCStreamOutput, SCStreamDelegat func stopRecording() { Task { + await MainActor.run { + self.timer?.invalidate() + self.timer = nil + } + settings.log("Stop recording") // 1. Stop System Audio try? await stream?.stopCapture() diff --git a/Sources/VoiceMemo/Views/RecordingView.swift b/Sources/VoiceMemo/Views/RecordingView.swift index cc13fb1..d67f30f 100644 --- a/Sources/VoiceMemo/Views/RecordingView.swift +++ b/Sources/VoiceMemo/Views/RecordingView.swift @@ -150,9 +150,10 @@ struct RecordingView: View { HStack(spacing: 8) { Image(systemName: "stop.fill") .font(.title3) - Text("Stop Recording") + Text("Stop Recording (\(formatDuration(recorder.recordingDuration)))") .font(.headline) .fontWeight(.bold) + .monospacedDigit() } .foregroundColor(.white) .padding(.vertical, 10) @@ -198,4 +199,12 @@ struct RecordingView: View { } .background(Color(nsColor: .windowBackgroundColor)) // Light gray background } + + private func formatDuration(_ duration: TimeInterval) -> String { + let formatter = DateComponentsFormatter() + formatter.allowedUnits = [.minute, .second] + formatter.unitsStyle = .positional + formatter.zeroFormattingBehavior = .pad + return formatter.string(from: duration) ?? "00:00" + } }