121 lines
4.2 KiB
Swift
121 lines
4.2 KiB
Swift
//
|
|
// PlayerViewModel.swift
|
|
// SwiftAudio
|
|
//
|
|
// Created by David Chavez on 4/12/24.
|
|
//
|
|
|
|
import SwiftAudioEx
|
|
|
|
#if os(macOS)
|
|
import AppKit
|
|
public typealias NativeImage = NSImage
|
|
#elseif os(iOS)
|
|
import UIKit
|
|
public typealias NativeImage = UIImage
|
|
#endif
|
|
|
|
extension PlayerView {
|
|
final class ViewModel: ObservableObject {
|
|
// MARK: - Observables
|
|
|
|
@Published var playing: Bool = false
|
|
@Published var position: Double = 0
|
|
@Published var artwork: NativeImage? = nil
|
|
@Published var title: String = ""
|
|
@Published var artist: String = ""
|
|
@Published var maxTime: TimeInterval = 100
|
|
@Published var isScrubbing: Bool = false
|
|
@Published var elapsedTime: String = "00:00"
|
|
@Published var remainingTime: String = "00:00"
|
|
|
|
@Published var playWhenReady: Bool = false
|
|
@Published var playbackState: AudioPlayerState = .idle
|
|
|
|
// MARK: - Properties
|
|
|
|
let controller = AudioController.shared
|
|
|
|
// MARK: - Initializer
|
|
|
|
init() {
|
|
controller.player.event.playWhenReadyChange.addListener(self, handlePlayWhenReadyChange)
|
|
controller.player.event.stateChange.addListener(self, handleAudioPlayerStateChange)
|
|
controller.player.event.playbackEnd.addListener(self, handleAudioPlayerPlaybackEnd(data:))
|
|
controller.player.event.secondElapse.addListener(self, handleAudioPlayerSecondElapsed)
|
|
controller.player.event.seek.addListener(self, handleAudioPlayerDidSeek)
|
|
controller.player.event.updateDuration.addListener(self, handleAudioPlayerUpdateDuration)
|
|
controller.player.event.didRecreateAVPlayer.addListener(self, handleAVPlayerRecreated)
|
|
}
|
|
|
|
// MARK: - Updates
|
|
|
|
private func render() {
|
|
DispatchQueue.main.async { [weak self] in
|
|
guard let self else { return }
|
|
playing = (controller.player.playerState == .playing)
|
|
playbackState = controller.player.playerState
|
|
playWhenReady = controller.player.playWhenReady
|
|
position = controller.player.currentTime
|
|
maxTime = controller.player.duration
|
|
artist = controller.player.currentItem?.getArtist() ?? ""
|
|
title = controller.player.currentItem?.getTitle() ?? ""
|
|
elapsedTime = controller.player.currentTime.secondsToString()
|
|
remainingTime = (controller.player.duration - controller.player.currentTime).secondsToString()
|
|
if let item = controller.player.currentItem as? DefaultAudioItem {
|
|
artwork = item.artwork
|
|
} else {
|
|
artwork = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
private func renderTimes() {
|
|
DispatchQueue.main.async { [weak self] in
|
|
guard let self else { return }
|
|
position = controller.player.currentTime
|
|
maxTime = controller.player.duration
|
|
elapsedTime = controller.player.currentTime.secondsToString()
|
|
remainingTime = (controller.player.duration - controller.player.currentTime).secondsToString()
|
|
print(elapsedTime)
|
|
}
|
|
}
|
|
|
|
// MARK: - AudioPlayer Event Handlers
|
|
|
|
func handleAudioPlayerStateChange(data: AudioPlayer.StateChangeEventData) {
|
|
print("state=\(data)")
|
|
render()
|
|
}
|
|
|
|
func handlePlayWhenReadyChange(data: AudioPlayer.PlayWhenReadyChangeData) {
|
|
print("playWhenReady=\(data)")
|
|
render()
|
|
}
|
|
|
|
func handleAudioPlayerPlaybackEnd(data: AudioPlayer.PlaybackEndEventData) {
|
|
print("playEndReason=\(data)")
|
|
}
|
|
|
|
func handleAudioPlayerSecondElapsed(data: AudioPlayer.SecondElapseEventData) {
|
|
if !isScrubbing {
|
|
renderTimes()
|
|
}
|
|
}
|
|
|
|
func handleAudioPlayerDidSeek(data: AudioPlayer.SeekEventData) {
|
|
// .. don't need this
|
|
}
|
|
|
|
func handleAudioPlayerUpdateDuration(data: AudioPlayer.UpdateDurationEventData) {
|
|
if !isScrubbing {
|
|
renderTimes()
|
|
}
|
|
}
|
|
|
|
func handleAVPlayerRecreated() {
|
|
// .. don't need this
|
|
}
|
|
}
|
|
}
|