mirror of
https://github.com/yattee/yattee.git
synced 2026-10-26 06:32:53 +00:00
Phase 5 of the player panels redesign: - Per-page element toggles now rendered and editable for every page: comments (author avatars), related (thumbnails), chapters (thumbnails), queue (previously played section), tracks (video/audio/subtitles/speed sections) - Page bar labels toggle (icons-only bar shows the selected page's name) - Layout mode schematic diagram in the details panel settings - NEW badge machinery for future page types (versionAdded on PanelPageType) - Typed per-page settings accessors on PanelPageConfiguration and VM update helpers for each page kind - Unit tests for per-page settings round-trip and accessor fallbacks The standalone quality selector sheet is unaffected: section gating defaults to everything visible and only the embedded tracks page passes preset settings through.
97 lines
4.1 KiB
Swift
97 lines
4.1 KiB
Swift
//
|
|
// TracksPanelPage.swift
|
|
// Yattee
|
|
//
|
|
// Details panel page embedding the quality/audio/subtitles/rate selector.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
#if os(iOS) || os(macOS)
|
|
|
|
struct TracksPanelPage: View {
|
|
let context: PanelPageContext
|
|
var settings: TracksPageSettings = TracksPageSettings()
|
|
var bottomInset: CGFloat = 0
|
|
|
|
private var appEnvironment: AppEnvironment? { context.appEnvironment }
|
|
private var playerService: PlayerService? { appEnvironment?.playerService }
|
|
private var playerState: PlayerState? { playerService?.state }
|
|
|
|
var body: some View {
|
|
if let playerService {
|
|
let supportedFormats = playerService.currentBackendType.supportedFormats
|
|
QualitySelectorView(
|
|
streams: playerService.availableStreams.filter { stream in
|
|
let format = StreamFormat.detect(from: stream)
|
|
// DASH is never offered for manual selection
|
|
if format == .dash {
|
|
return false
|
|
}
|
|
return supportedFormats.contains(format)
|
|
},
|
|
captions: playerService.availableCaptions,
|
|
currentStream: playerState?.currentStream,
|
|
currentAudioStream: playerState?.currentAudioStream,
|
|
currentCaption: playerService.currentCaption,
|
|
isLoading: playerService.availableStreams.isEmpty && playerState?.playbackState == .loading,
|
|
currentDownload: playerService.currentDownload,
|
|
isLoadingOnlineStreams: playerService.isLoadingOnlineStreams,
|
|
localCaptionURL: playerService.currentDownload.flatMap { download in
|
|
guard let path = download.localCaptionPath else { return nil }
|
|
return appEnvironment?.downloadManager.downloadsDirectory().appendingPathComponent(path)
|
|
},
|
|
currentRate: playerState?.rate ?? .x1,
|
|
isControlsLocked: playerState?.isControlsLocked ?? false,
|
|
isAudioMode: appEnvironment?.settingsManager.audioOnlyModeEnabled ?? false,
|
|
embeddedAudioTracks: playerService.embeddedAudioTracks,
|
|
embeddedSubtitleTracks: playerService.embeddedSubtitleTracks,
|
|
currentEmbeddedAudioTrackID: playerService.selectedEmbeddedAudioTrackID,
|
|
currentEmbeddedSubtitleTrackID: playerService.selectedEmbeddedSubtitleTrackID,
|
|
embeddedVideoTrack: playerService.primaryEmbeddedVideoTrack,
|
|
onStreamSelected: { stream, audioStream in
|
|
Task {
|
|
await playerService.selectStreamManually(stream, audioStream: audioStream)
|
|
}
|
|
},
|
|
onCaptionSelected: { caption in
|
|
playerService.loadCaption(caption)
|
|
},
|
|
onLoadOnlineStreams: {
|
|
Task {
|
|
await playerService.loadOnlineStreams()
|
|
}
|
|
},
|
|
onSwitchToOnlineStream: { stream, audioStream in
|
|
Task {
|
|
await playerService.switchToOnlineStream(stream, audioStream: audioStream)
|
|
}
|
|
},
|
|
onEmbeddedAudioTrackSelected: { trackID in
|
|
playerService.selectEmbeddedAudioTrack(trackID)
|
|
},
|
|
onEmbeddedSubtitleTrackSelected: { trackID in
|
|
playerService.selectEmbeddedSubtitleTrack(trackID)
|
|
},
|
|
onRateChanged: { rate in
|
|
playerState?.rate = rate
|
|
playerService.currentBackend?.rate = Float(rate.rawValue)
|
|
},
|
|
onLockToggled: { locked in
|
|
playerState?.isControlsLocked = locked
|
|
},
|
|
onAudioModeToggled: { enabled in
|
|
Task {
|
|
await playerService.setAudioMode(enabled)
|
|
}
|
|
},
|
|
isEmbedded: true,
|
|
visibleSections: settings
|
|
)
|
|
.safeAreaPadding(.bottom, bottomInset)
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|