Skip to content

Commit 128d0b7

Browse files
committed
fixes to audio preview
1 parent 73d7d9d commit 128d0b7

File tree

1 file changed

+69
-6
lines changed

1 file changed

+69
-6
lines changed

Django Files/Views/Preview.swift

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,9 @@ struct AudioPlayerView: View {
321321
.foregroundColor(.gray)
322322
.padding(.bottom)
323323

324+
// Speaker Toggle
325+
326+
324327
// Time and Progress
325328
HStack {
326329
Text(playerViewModel.currentTimeString)
@@ -341,6 +344,9 @@ struct AudioPlayerView: View {
341344

342345
// Playback Controls
343346
HStack(spacing: 30) {
347+
Button(action: {}) {
348+
349+
}
344350
Button(action: { playerViewModel.skipBackward() }) {
345351
Image(systemName: "gobackward.15")
346352
.font(.title2)
@@ -355,6 +361,12 @@ struct AudioPlayerView: View {
355361
Image(systemName: "goforward.15")
356362
.font(.title2)
357363
}
364+
Button(action: { playerViewModel.toggleSpeaker() }) {
365+
Image(systemName: playerViewModel.isSpeakerOn ? "speaker.wave.2.fill" : "speaker.wave.2")
366+
.font(.title2)
367+
.foregroundColor(playerViewModel.isSpeakerOn ? .blue : .gray)
368+
}
369+
.padding(.bottom, 5)
358370
}
359371
}
360372
.onAppear {
@@ -370,13 +382,43 @@ struct AudioPlayerView: View {
370382
class AudioPlayerViewModel: ObservableObject {
371383
private var player: AVPlayer?
372384
private var timeObserver: Any?
385+
private var playerItemObserver: NSKeyValueObservation?
373386

374387
@Published var isPlaying = false
375388
@Published var progress: Double = 0
376389
@Published var currentTimeString = "00:00"
377390
@Published var durationString = "00:00"
391+
@Published var isSpeakerOn = true
392+
393+
private func configureAudioSession() {
394+
do {
395+
let audioSession = AVAudioSession.sharedInstance()
396+
try audioSession.setCategory(.playback, mode: .default)
397+
try audioSession.setActive(true)
398+
updateSpeakerState()
399+
} catch {
400+
print("Failed to configure audio session: \(error)")
401+
}
402+
}
403+
404+
private func updateSpeakerState() {
405+
do {
406+
let audioSession = AVAudioSession.sharedInstance()
407+
try audioSession.overrideOutputAudioPort(
408+
isSpeakerOn ? .speaker : .none
409+
)
410+
} catch {
411+
print("Failed to switch audio output: \(error)")
412+
}
413+
}
414+
415+
func toggleSpeaker() {
416+
isSpeakerOn.toggle()
417+
updateSpeakerState()
418+
}
378419

379420
func setupPlayer(with url: URL) {
421+
configureAudioSession()
380422
player = AVPlayer(url: url)
381423

382424
// Add periodic time observer
@@ -391,24 +433,44 @@ class AudioPlayerViewModel: ObservableObject {
391433
self.durationString = self.formatTime(duration)
392434
}
393435

436+
// Observe player item status for completion
437+
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
438+
object: player?.currentItem,
439+
queue: .main) { [weak self] _ in
440+
self?.handlePlaybackCompletion()
441+
}
442+
394443
// Update duration when item is ready
395-
player?.currentItem?.asset.loadValuesAsynchronously(forKeys: ["duration"]) {
396-
DispatchQueue.main.async {
397-
if let duration = self.player?.currentItem?.duration.seconds,
398-
!duration.isNaN {
399-
self.durationString = self.formatTime(duration)
444+
Task {
445+
if let duration = try? await player?.currentItem?.asset.load(.duration) as? CMTime,
446+
!duration.seconds.isNaN {
447+
await MainActor.run {
448+
self.durationString = self.formatTime(duration.seconds)
400449
}
401450
}
402451
}
403452
}
404453

454+
private func handlePlaybackCompletion() {
455+
isPlaying = false
456+
// Reset to beginning
457+
seek(to: 0)
458+
}
459+
405460
func togglePlayback() {
406461
if isPlaying {
407462
player?.pause()
463+
isPlaying = false
408464
} else {
465+
// If we're at the end, seek to beginning before playing
466+
if let currentTime = player?.currentTime().seconds,
467+
let duration = player?.currentItem?.duration.seconds,
468+
currentTime >= duration {
469+
seek(to: 0)
470+
}
409471
player?.play()
472+
isPlaying = true
410473
}
411-
isPlaying.toggle()
412474
}
413475

414476
func seek(to progress: Double) {
@@ -431,6 +493,7 @@ class AudioPlayerViewModel: ObservableObject {
431493
if let timeObserver = timeObserver {
432494
player?.removeTimeObserver(timeObserver)
433495
}
496+
NotificationCenter.default.removeObserver(self)
434497
player?.pause()
435498
player = nil
436499
}

0 commit comments

Comments
 (0)