feat: add playback loading state
This commit is contained in:
@@ -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>
|
@@ -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>
|
|
@@ -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) {
|
||||||
|
@@ -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)
|
|
||||||
|
|
||||||
audioPlayer.replaceCurrentItem(with: playerItem)
|
|
||||||
audioPlayer.play()
|
|
||||||
|
|
||||||
playbackState = .playing
|
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
|
||||||
|
Reference in New Issue
Block a user