fix: preload first track to avoid ui freeze

Preload the first track to avoid ui stutter when the play button is
first pressed
This commit is contained in:
2024-07-28 17:31:05 +01:00
parent 390f9b2b09
commit 352f5f01cf
2 changed files with 29 additions and 10 deletions

View File

@@ -20,6 +20,7 @@ struct ContentView: View {
case .paused: "play" case .paused: "play"
case .playing: "pause" case .playing: "pause"
case .loading: "dot.square" case .loading: "dot.square"
default: ""
} }
VStack(alignment: .center) { VStack(alignment: .center) {
@@ -30,12 +31,14 @@ struct ContentView: View {
Spacer() Spacer()
NeuButton(action: { if playbackManager.playbackState != .initializing {
toggleAudioPlayback() NeuButton(action: {
}) { toggleAudioPlayback()
Image(systemName: buttonImageName) }) {
.font(.system(size: 24)) Image(systemName: buttonImageName)
.tint(.text) .font(.system(size: 24))
.tint(.text)
}
} }
Spacer() Spacer()

View File

@@ -5,10 +5,11 @@ enum PlaybackState {
case playing case playing
case paused case paused
case loading case loading
case initializing
} }
class PlaybackManager: ObservableObject { class PlaybackManager: ObservableObject {
@Published var playbackState: PlaybackState = .paused @Published var playbackState: PlaybackState = .initializing
@Published var hasError = false @Published var hasError = false
private var audioPlayer = AVPlayer() private var audioPlayer = AVPlayer()
@@ -16,10 +17,15 @@ class PlaybackManager: ObservableObject {
private var fadeOutTimer: Timer? private var fadeOutTimer: Timer?
private var scheduledFadeOutTimer: Timer? private var scheduledFadeOutTimer: Timer?
init() {
Task { try await initialize() }
}
func nextTrack() { func nextTrack() {
playbackState = .loading playbackState = .loading
Task { Task {
try await loadAndPlayNextTrack() try await loadNextTrack()
await playCurrentTrack()
await MainActor.run { await MainActor.run {
playbackState = .playing playbackState = .playing
} }
@@ -37,7 +43,15 @@ class PlaybackManager: ObservableObject {
audioPlayer.pause() audioPlayer.pause()
} }
private nonisolated func loadAndPlayNextTrack() async throws { private func initialize() async throws {
try await loadNextTrack()
await MainActor.run {
playbackState = .paused
}
}
private nonisolated func loadNextTrack() async throws {
let now = Date().timeIntervalSince1970 let now = Date().timeIntervalSince1970
guard let url = URL(string: "https://infinifi.cafe/current.mp3?t=\(now)") else { guard let url = URL(string: "https://infinifi.cafe/current.mp3?t=\(now)") else {
return return
@@ -56,8 +70,10 @@ class PlaybackManager: ObservableObject {
audioPlayer.volume = 0.0 audioPlayer.volume = 0.0
audioPlayer.replaceCurrentItem(with: playerItem) audioPlayer.replaceCurrentItem(with: playerItem)
await audioPlayer.play() }
private nonisolated func playCurrentTrack() async {
await audioPlayer.play()
DispatchQueue.main.async { DispatchQueue.main.async {
self.fadeInAudio() self.fadeInAudio()
self.scheduledFadeOutTimer = Timer.scheduledTimer(withTimeInterval: 55, repeats: false) { _ in self.scheduledFadeOutTimer = Timer.scheduledTimer(withTimeInterval: 55, repeats: false) { _ in