Er hat weiterhin angehalten statt ein- und auszublenden, und der Grund steckte in der Rechnung: der schwarze Rand wurde aus der Fenstergrösse ausgerechnet, das Bild liegt aber in einer Fläche mit `ignoresSafeArea()`. Auf dem Mac ist der Einzug der Fensterleiste genau der Unterschied zwischen beiden — die Rechnung lag um diesen Betrag daneben. Jetzt wird die Bildfläche gemessen statt angenommen, und beide Zahlen stehen in einem gemeinsamen, benannten Koordinatenraum. Vor allem aber wird zuerst `AVPlayerLayer.videoRect` gefragt: der Player weiss selbst, wo Bild steht. Die eigene Rechnung bleibt für den Moment vor dem ersten Bild und für VLC, das keine solche Ebene hat. Dazu zwei Worte: „Nachschub" heisst jetzt „Nachladen", und „Blatt" heisst wieder „Sheet" — das ist ein Fachbegriff und bleibt englisch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
99 lines
3.2 KiB
Swift
99 lines
3.2 KiB
Swift
import SwiftUI
|
|
import FlixyDesign
|
|
import FlixyPlayback
|
|
|
|
/// Auswahl einer Spur — Ton **oder** Untertitel, nicht beides.
|
|
///
|
|
/// Getrennt, weil es zwei verschiedene Fragen sind: die Tonspur wechselt man
|
|
/// einmal am Anfang, die Untertitel mitten im Film. Beide in einem Sheet
|
|
/// bedeutete jedes Mal Scrollen an der anderen Liste vorbei.
|
|
struct TrackPickerSheet: View {
|
|
enum Kind: Identifiable {
|
|
case audio
|
|
case subtitles
|
|
|
|
var id: Self { self }
|
|
|
|
var title: LocalizedStringKey {
|
|
switch self {
|
|
case .audio: "player.audioTracks"
|
|
case .subtitles: "player.subtitleTracks"
|
|
}
|
|
}
|
|
}
|
|
|
|
let model: PlayerModel
|
|
let kind: Kind
|
|
|
|
@Environment(\.dismiss) private var dismiss
|
|
@Environment(\.flixyAccent) private var accent
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
List {
|
|
switch kind {
|
|
case .audio:
|
|
ForEach(model.audioTracks) { track in
|
|
row(
|
|
title: track.displayName,
|
|
isSelected: model.selectedAudioTrack == track
|
|
) {
|
|
model.selectAudioTrack(track)
|
|
dismiss()
|
|
}
|
|
}
|
|
|
|
case .subtitles:
|
|
// „Aus" gehört in dieselbe Liste wie die Spuren, nicht als
|
|
// eigener Schalter daneben: es ist eine Auswahl unter
|
|
// mehreren, keine getrennte Eigenschaft.
|
|
row(
|
|
title: String(localized: "player.subtitlesOff"),
|
|
isSelected: model.selectedSubtitleTrack == nil
|
|
) {
|
|
model.selectSubtitleTrack(nil)
|
|
dismiss()
|
|
}
|
|
|
|
ForEach(model.subtitleTracks) { track in
|
|
row(
|
|
title: track.displayName,
|
|
isSelected: model.selectedSubtitleTrack == track
|
|
) {
|
|
model.selectSubtitleTrack(track)
|
|
dismiss()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.scrollContentBackground(.hidden)
|
|
.background(Color.flixyCanvas)
|
|
.navigationTitle(Text(kind.title))
|
|
.flixyInlineTitle()
|
|
.toolbar {
|
|
ToolbarItem(placement: .confirmationAction) {
|
|
Button("action.close") { dismiss() }
|
|
}
|
|
}
|
|
}
|
|
.flixyMediumSheet()
|
|
}
|
|
|
|
private func row(title: String, isSelected: Bool, action: @escaping () -> Void) -> some View {
|
|
Button(action: action) {
|
|
HStack {
|
|
Text(title)
|
|
.foregroundStyle(Color.flixyTextPrimary)
|
|
Spacer()
|
|
if isSelected {
|
|
Image(systemName: "checkmark").foregroundStyle(accent)
|
|
}
|
|
}
|
|
.contentShape(.rect)
|
|
}
|
|
.buttonStyle(.plain)
|
|
.listRowBackground(Color.flixySurface)
|
|
.accessibilityAddTraits(isSelected ? [.isButton, .isSelected] : .isButton)
|
|
}
|
|
}
|