ui: integrate captions and unify playback chrome backgrounds
This commit is contained in:
+63
-39
@@ -1455,11 +1455,7 @@ private struct PlayerContent: View {
|
||||
.padding(.vertical, 4)
|
||||
.background(PlayerGlass(cornerRadius: 8).clipShape(RoundedRectangle(cornerRadius: 8)).allowsHitTesting(false))
|
||||
Spacer(minLength: 12)
|
||||
iconButton(model.isOnTop ? "pin.fill" : "pin",
|
||||
model.isOnTop ? "Stop Keeping Window on Top" : "Keep Window on Top", action: model.toggleOnTop)
|
||||
.imageScale(.small)
|
||||
.foregroundStyle(Color(model.isOnTop ? SunsetPalette.accent : SunsetPalette.secondaryText))
|
||||
.disabled(model.isFullScreen || model.compactWindow.isTransitioning)
|
||||
titleControls
|
||||
}
|
||||
.padding(.leading, model.isFullScreen ? 16 : 86)
|
||||
.padding(.trailing, 12)
|
||||
@@ -1471,6 +1467,42 @@ private struct PlayerContent: View {
|
||||
.accessibilityHidden(!model.controlsVisible)
|
||||
}
|
||||
|
||||
private var titleControls: some View {
|
||||
HStack(spacing: 4) {
|
||||
iconButton(model.isOnTop ? "pin.fill" : "pin",
|
||||
model.isOnTop ? "Stop Keeping Window on Top" : "Keep Window on Top", action: model.toggleOnTop)
|
||||
.imageScale(.small)
|
||||
.foregroundStyle(Color(model.isOnTop ? SunsetPalette.accent : SunsetPalette.secondaryText))
|
||||
.disabled(model.isFullScreen || model.compactWindow.isTransitioning)
|
||||
actionsMenu
|
||||
}
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 4)
|
||||
.background(PlayerGlass(cornerRadius: 8).clipShape(RoundedRectangle(cornerRadius: 8)).allowsHitTesting(false))
|
||||
}
|
||||
|
||||
private var captionsMenu: some View {
|
||||
Menu {
|
||||
Button("Off") { model.selectSubtitle(nil) }
|
||||
ForEach(model.subtitleTracks.indices, id: \.self) { index in
|
||||
Button {
|
||||
model.selectSubtitle(index)
|
||||
} label: {
|
||||
Label(model.subtitleTracks[index].label + " (" + model.subtitleTracks[index].language + ")",
|
||||
systemImage: model.selectedSubtitle == index ? "checkmark" : "text.bubble")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "captions.bubble").font(.system(size: 17)).frame(width: 24, height: 24)
|
||||
}
|
||||
.menuStyle(.borderlessButton)
|
||||
.menuIndicator(.hidden)
|
||||
.fixedSize()
|
||||
.disabled(model.subtitleTracks.isEmpty)
|
||||
.accessibilityLabel("Subtitles")
|
||||
.help("Subtitles")
|
||||
}
|
||||
|
||||
private var actionsMenu: some View {
|
||||
Menu {
|
||||
PlayerActionButton(model: model, action: .openFile, title: "Open File…")
|
||||
@@ -1507,7 +1539,7 @@ private struct PlayerContent: View {
|
||||
.disabled(!model.canTogglePlayback)
|
||||
iconButton("pip.exit", "Exit Compact Mode", action: model.toggleCompact)
|
||||
.disabled(!model.canToggleCompact)
|
||||
actionsMenu
|
||||
captionsMenu
|
||||
}
|
||||
if showsBufferReadout { bufferReadout }
|
||||
}
|
||||
@@ -1557,7 +1589,7 @@ private struct PlayerContent: View {
|
||||
HStack(spacing: 12) {
|
||||
iconButton("pip.enter", "Enter Compact Mode", action: model.toggleCompact)
|
||||
.disabled(!model.canToggleCompact)
|
||||
actionsMenu
|
||||
captionsMenu
|
||||
}
|
||||
.frame(width: 106, alignment: .trailing)
|
||||
}
|
||||
@@ -1638,33 +1670,20 @@ private struct PlayerContent: View {
|
||||
.foregroundStyle(.white)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(8)
|
||||
.background(.black.opacity(0.75), in: RoundedRectangle(cornerRadius: 4))
|
||||
.background(PlayerGlass().clipShape(RoundedRectangle(cornerRadius: 12)).allowsHitTesting(false))
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.bottom, model.controlsVisible ? 110 : 24)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
if !model.subtitleTracks.isEmpty && (model.controlsVisible || model.subtitleError != nil) {
|
||||
VStack(alignment: .trailing) {
|
||||
Menu {
|
||||
Button("Off") { model.selectSubtitle(nil) }
|
||||
ForEach(model.subtitleTracks.indices, id: \.self) { index in
|
||||
Button {
|
||||
model.selectSubtitle(index)
|
||||
} label: {
|
||||
Label(model.subtitleTracks[index].label + " (" + model.subtitleTracks[index].language + ")",
|
||||
systemImage: model.selectedSubtitle == index ? "checkmark" : "text.bubble")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "captions.bubble").accessibilityLabel("Subtitles")
|
||||
}
|
||||
if let error = model.subtitleError {
|
||||
Text(error).font(.caption).foregroundStyle(.yellow)
|
||||
}
|
||||
}
|
||||
.padding(.top, 44).padding(.trailing, 16)
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
if let error = model.subtitleError {
|
||||
Text(error)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.yellow)
|
||||
.padding(8)
|
||||
.background(PlayerGlass().clipShape(RoundedRectangle(cornerRadius: 12)).allowsHitTesting(false))
|
||||
.padding(.top, 44).padding(.trailing, 16)
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
}
|
||||
if let error = model.errorText {
|
||||
VStack(spacing: 12) {
|
||||
@@ -1789,22 +1808,27 @@ private struct PlayerContent: View {
|
||||
|
||||
let progress = model.isCompact || model.compactWindow.isTransitioning ? model.compactProgress : nil
|
||||
ZStack(alignment: .top) {
|
||||
ViewThatFits(in: .horizontal) {
|
||||
compactTitleLabel(progress: progress, constrained: false)
|
||||
.fixedSize(horizontal: true, vertical: false)
|
||||
compactTitleLabel(progress: progress, constrained: true)
|
||||
}
|
||||
HStack(spacing: 8) {
|
||||
ViewThatFits(in: .horizontal) {
|
||||
compactTitleLabel(progress: progress, constrained: false)
|
||||
.fixedSize(horizontal: true, vertical: false)
|
||||
compactTitleLabel(progress: progress, constrained: true)
|
||||
}
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.accessibilityElement(children: .combine)
|
||||
.help((model.fileName ?? "terebi") + (progress.map { " · \($0)" } ?? ""))
|
||||
.padding(8)
|
||||
.background(PlayerGlass(cornerRadius: 10).clipShape(RoundedRectangle(cornerRadius: 10)).allowsHitTesting(false))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(8)
|
||||
.foregroundStyle(Color(SunsetPalette.text))
|
||||
.opacity(model.controlsVisible ? 1 : 0)
|
||||
.allowsHitTesting(false)
|
||||
.accessibilityHidden(!model.controlsVisible)
|
||||
Spacer(minLength: 0)
|
||||
titleControls
|
||||
}
|
||||
.padding(8)
|
||||
.foregroundStyle(Color(SunsetPalette.text))
|
||||
.onHover(perform: model.setTitleHovered)
|
||||
.opacity(model.controlsVisible ? 1 : 0)
|
||||
.allowsHitTesting(model.controlsVisible)
|
||||
.accessibilityHidden(!model.controlsVisible)
|
||||
compactControls
|
||||
.position(x: geometry.size.width / 2, y: geometry.size.height - compactControlHeight / 2 - 8)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user