Add iOS/iPad target with platform-adaptive UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,7 @@ private func makeSingleStreamPlayerItem(from source: SingleStreamPlaybackSource)
|
||||
}
|
||||
|
||||
struct SingleStreamPlaybackScreen: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
let resolveSource: @Sendable () async -> SingleStreamPlaybackSource?
|
||||
var resolveNextSource: (@Sendable (URL?) async -> SingleStreamPlaybackSource?)? = nil
|
||||
let tickerGames: [Game]
|
||||
@@ -90,6 +91,18 @@ struct SingleStreamPlaybackScreen: View {
|
||||
.padding(.horizontal, 18)
|
||||
.padding(.bottom, 14)
|
||||
}
|
||||
.overlay(alignment: .topTrailing) {
|
||||
#if os(iOS)
|
||||
Button {
|
||||
dismiss()
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.font(.system(size: 28, weight: .bold))
|
||||
.foregroundStyle(.white.opacity(0.9))
|
||||
.padding(20)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
.onAppear {
|
||||
logSingleStream("SingleStreamPlaybackScreen appeared tickerGames=\(tickerGames.count) tickerMode=marqueeOverlay")
|
||||
@@ -103,10 +116,12 @@ struct SingleStreamPlaybackScreen: View {
|
||||
struct SingleStreamPlaybackSource: Sendable {
|
||||
let url: URL
|
||||
let httpHeaders: [String: String]
|
||||
let forceMuteAudio: Bool
|
||||
|
||||
init(url: URL, httpHeaders: [String: String] = [:]) {
|
||||
init(url: URL, httpHeaders: [String: String] = [:], forceMuteAudio: Bool = false) {
|
||||
self.url = url
|
||||
self.httpHeaders = httpHeaders
|
||||
self.forceMuteAudio = forceMuteAudio
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,6 +300,9 @@ struct SingleStreamPlayerView: UIViewControllerRepresentable {
|
||||
let controller = AVPlayerViewController()
|
||||
controller.allowsPictureInPicturePlayback = true
|
||||
controller.showsPlaybackControls = true
|
||||
#if os(iOS)
|
||||
controller.canStartPictureInPictureAutomaticallyFromInline = true
|
||||
#endif
|
||||
logSingleStream("AVPlayerViewController configured without contentOverlayView ticker")
|
||||
|
||||
Task { @MainActor in
|
||||
@@ -311,6 +329,7 @@ struct SingleStreamPlayerView: UIViewControllerRepresentable {
|
||||
let playerItem = makeSingleStreamPlayerItem(from: source)
|
||||
let player = AVPlayer(playerItem: playerItem)
|
||||
player.automaticallyWaitsToMinimizeStalling = false
|
||||
player.isMuted = source.forceMuteAudio
|
||||
logSingleStream("Configured player for fast start preferredForwardBufferDuration=2 automaticallyWaitsToMinimizeStalling=false")
|
||||
context.coordinator.attachDebugObservers(to: player, url: url, resolveNextSource: resolveNextSource)
|
||||
controller.player = player
|
||||
@@ -433,6 +452,7 @@ struct SingleStreamPlayerView: UIViewControllerRepresentable {
|
||||
let nextItem = makeSingleStreamPlayerItem(from: nextSource)
|
||||
player.replaceCurrentItem(with: nextItem)
|
||||
player.automaticallyWaitsToMinimizeStalling = false
|
||||
player.isMuted = nextSource.forceMuteAudio
|
||||
self.attachDebugObservers(to: player, url: nextSource.url, resolveNextSource: resolveNextSource)
|
||||
logSingleStream("Autoplay replacing item and replaying url=\(singleStreamDebugURLDescription(nextSource.url))")
|
||||
player.playImmediately(atRate: 1.0)
|
||||
|
||||
Reference in New Issue
Block a user