diff --git a/InfinifiIOS.xcodeproj/xcshareddata/xcschemes/InfinifiIOS.xcscheme b/InfinifiIOS.xcodeproj/xcshareddata/xcschemes/InfinifiIOS.xcscheme
new file mode 100644
index 0000000..098968e
--- /dev/null
+++ b/InfinifiIOS.xcodeproj/xcshareddata/xcschemes/InfinifiIOS.xcscheme
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/InfinifiIOS.xcodeproj/xcuserdata/kennethng.xcuserdatad/xcschemes/xcschememanagement.plist b/InfinifiIOS.xcodeproj/xcuserdata/kennethng.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index 4b77bca..0000000
--- a/InfinifiIOS.xcodeproj/xcuserdata/kennethng.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- SchemeUserState
-
- InfinifiIOS.xcscheme_^#shared#^_
-
- orderHint
- 0
-
-
-
-
diff --git a/InfinifiIOS/ContentView.swift b/InfinifiIOS/ContentView.swift
index df85abd..d887f64 100644
--- a/InfinifiIOS/ContentView.swift
+++ b/InfinifiIOS/ContentView.swift
@@ -10,6 +10,8 @@ struct ContentView: View {
playbackManager.stop()
case .paused:
playbackManager.nextTrack()
+ default:
+ break
}
}
@@ -17,6 +19,7 @@ struct ContentView: View {
let buttonImageName = switch playbackManager.playbackState {
case .paused: "play"
case .playing: "pause"
+ case .loading: "dot.square"
}
VStack(alignment: .center) {
diff --git a/InfinifiIOS/PlaybackManager.swift b/InfinifiIOS/PlaybackManager.swift
index aa7a7d8..4b56ef4 100644
--- a/InfinifiIOS/PlaybackManager.swift
+++ b/InfinifiIOS/PlaybackManager.swift
@@ -4,8 +4,10 @@ import Foundation
enum PlaybackState {
case playing
case paused
+ case loading
}
+@MainActor
class PlaybackManager: ObservableObject {
@Published var playbackState: PlaybackState = .paused
@Published var hasError = false
@@ -13,20 +15,37 @@ class PlaybackManager: ObservableObject {
private var audioPlayer = AVPlayer()
func nextTrack() {
- let now = Date().timeIntervalSince1970
- // add timestamp to the url to prevent caching
- let playerItem = AVPlayerItem(url: URL(string: "https://infinifi.cafe/current.mp3?t=\(now)")!)
- NotificationCenter.default.addObserver(self, selector: #selector(playbackFinished), name: AVPlayerItem.didPlayToEndTimeNotification, object: playerItem)
-
- audioPlayer.replaceCurrentItem(with: playerItem)
- audioPlayer.play()
-
- playbackState = .playing
+ playbackState = .loading
+ Task {
+ try await loadCurrentTrack()
+ playbackState = .playing
+ }
}
func stop() {
- audioPlayer.pause()
playbackState = .paused
+ audioPlayer.pause()
+ }
+
+ private nonisolated func loadCurrentTrack() async throws {
+ let now = Date().timeIntervalSince1970
+ guard let url = URL(string: "https://infinifi.cafe/current.mp3?t=\(now)") else {
+ return
+ }
+
+ // add timestamp to the url to prevent caching
+ let asset = AVAsset(url: url)
+ let isPlayable = try await asset.load(.isPlayable)
+ guard isPlayable else {
+ return
+ }
+
+ let playerItem = AVPlayerItem(asset: asset)
+
+ NotificationCenter.default.addObserver(self, selector: #selector(playbackFinished), name: AVPlayerItem.didPlayToEndTimeNotification, object: playerItem)
+
+ await audioPlayer.replaceCurrentItem(with: playerItem)
+ await audioPlayer.play()
}
@objc