feat: add playback loading state

This commit is contained in:
2024-07-28 15:12:10 +01:00
parent dc80455f3e
commit 5f4a3c8a0a
4 changed files with 110 additions and 24 deletions

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F138396B2C51BABD00B4814F"
BuildableName = "InfinifiIOS.app"
BlueprintName = "InfinifiIOS"
ReferencedContainer = "container:InfinifiIOS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F138396B2C51BABD00B4814F"
BuildableName = "InfinifiIOS.app"
BlueprintName = "InfinifiIOS"
ReferencedContainer = "container:InfinifiIOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F138396B2C51BABD00B4814F"
BuildableName = "InfinifiIOS.app"
BlueprintName = "InfinifiIOS"
ReferencedContainer = "container:InfinifiIOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>InfinifiIOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
</dict>
</plist>

View File

@@ -10,6 +10,8 @@ struct ContentView: View {
playbackManager.stop() playbackManager.stop()
case .paused: case .paused:
playbackManager.nextTrack() playbackManager.nextTrack()
default:
break
} }
} }
@@ -17,6 +19,7 @@ struct ContentView: View {
let buttonImageName = switch playbackManager.playbackState { let buttonImageName = switch playbackManager.playbackState {
case .paused: "play" case .paused: "play"
case .playing: "pause" case .playing: "pause"
case .loading: "dot.square"
} }
VStack(alignment: .center) { VStack(alignment: .center) {

View File

@@ -4,8 +4,10 @@ import Foundation
enum PlaybackState { enum PlaybackState {
case playing case playing
case paused case paused
case loading
} }
@MainActor
class PlaybackManager: ObservableObject { class PlaybackManager: ObservableObject {
@Published var playbackState: PlaybackState = .paused @Published var playbackState: PlaybackState = .paused
@Published var hasError = false @Published var hasError = false
@@ -13,20 +15,37 @@ class PlaybackManager: ObservableObject {
private var audioPlayer = AVPlayer() private var audioPlayer = AVPlayer()
func nextTrack() { func nextTrack() {
let now = Date().timeIntervalSince1970 playbackState = .loading
// add timestamp to the url to prevent caching Task {
let playerItem = AVPlayerItem(url: URL(string: "https://infinifi.cafe/current.mp3?t=\(now)")!) try await loadCurrentTrack()
NotificationCenter.default.addObserver(self, selector: #selector(playbackFinished), name: AVPlayerItem.didPlayToEndTimeNotification, object: playerItem) playbackState = .playing
}
audioPlayer.replaceCurrentItem(with: playerItem)
audioPlayer.play()
playbackState = .playing
} }
func stop() { func stop() {
audioPlayer.pause()
playbackState = .paused 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 @objc