diff --git a/bitchat/Features/voice/VoiceNotePlaybackController.swift b/bitchat/Features/voice/VoiceNotePlaybackController.swift index de475e51..1ce463f7 100644 --- a/bitchat/Features/voice/VoiceNotePlaybackController.swift +++ b/bitchat/Features/voice/VoiceNotePlaybackController.swift @@ -16,12 +16,14 @@ final class VoiceNotePlaybackController: NSObject, ObservableObject, AVAudioPlay init(url: URL) { self.url = url super.init() - // Load duration asynchronously to avoid blocking main thread - loadDurationAsync() + // Don't load anything eagerly - wait until user interaction or view is fully displayed } - private func loadDurationAsync() { - DispatchQueue.global(qos: .userInitiated).async { [weak self] in + func loadDuration() { + // Only load if not already loaded + guard duration == 0 else { return } + + DispatchQueue.global(qos: .utility).async { [weak self] in guard let self = self else { return } do { let player = try AVAudioPlayer(contentsOf: self.url) @@ -44,7 +46,8 @@ final class VoiceNotePlaybackController: NSObject, ObservableObject, AVAudioPlay stop() self.url = url player = nil - loadDurationAsync() + duration = 0 + // Duration will be loaded on demand when needed } func togglePlayback() { diff --git a/bitchat/Views/Media/VoiceNoteView.swift b/bitchat/Views/Media/VoiceNoteView.swift index cba1ba5b..4e0b2e5b 100644 --- a/bitchat/Views/Media/VoiceNoteView.swift +++ b/bitchat/Views/Media/VoiceNoteView.swift @@ -100,10 +100,13 @@ struct VoiceNoteView: View { .stroke(borderColor, lineWidth: 1) ) .onAppear { - WaveformCache.shared.waveform(for: url, completion: { bins in - self.waveform = bins - }) - // No need to call playback.replaceURL - already initialized with correct URL + // Defer both duration and waveform loading to let UI settle after message appears + DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { + playback.loadDuration() + WaveformCache.shared.waveform(for: url, completion: { bins in + self.waveform = bins + }) + } } .onChange(of: url) { newValue in WaveformCache.shared.waveform(for: newValue, completion: { bins in