Surface the existing pin (keep-from-cull) and per-file delete actions as visible inline buttons on each offline cache row instead of context-menu-only: a star toggles protection from auto-cull (and restore-if-missing), a trash culls that file early. Aligns wording/icons to the star metaphor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
67 lines
3.2 KiB
Swift
67 lines
3.2 KiB
Swift
import SwiftUI
|
||
import TVAnarchyCore
|
||
|
||
/// Compact transport for a view's header toolbar: previous · −10s · play/pause ·
|
||
/// +10s · next, driving the active host. Lets you control playback without
|
||
/// leaving the current tab for the Player tab. The play button (when idle) will
|
||
/// resume the last played item from its saved position. Other controls are
|
||
/// enabled if the host is reachable.
|
||
struct MiniTransport: View {
|
||
@Bindable var controller: PlayerController
|
||
@Environment(\.appTheme) private var appTheme
|
||
|
||
private var snap: PlayerController.Snapshot { controller.activeSnapshot }
|
||
private var status: PlaybackStatus { snap.status }
|
||
/// Same "nothing playing" signal the Player tab uses for its title line.
|
||
private var idle: Bool { status.title == nil }
|
||
|
||
var body: some View {
|
||
Group {
|
||
if appTheme.usesWinampChrome {
|
||
HStack(spacing: 4) {
|
||
winamp("backward.end.fill", help: "Previous episode or track") { await $0.previous() }
|
||
winamp("gobackward.10", help: "Seek back 10 seconds") { await $0.seek(relative: -10) }
|
||
let showPlay = idle || status.paused == true
|
||
winamp(showPlay ? "play.fill" : "pause.fill", wide: true, help: showPlay ? "Play" : "Pause") { (_: any PlayerTarget) async in
|
||
controller.togglePlayPause()
|
||
}
|
||
winamp("goforward.10", help: "Seek forward 10 seconds") { await $0.seek(relative: 10) }
|
||
winamp("forward.end.fill", help: "Next episode or track") { await $0.next(); await $0.resume() }
|
||
}
|
||
} else {
|
||
HStack(spacing: 10) {
|
||
button("backward.end.fill", help: "Previous episode or track") { await $0.previous() }
|
||
button("gobackward.10", help: "Seek back 10 seconds") { await $0.seek(relative: -10) }
|
||
let showPlay = idle || status.paused == true
|
||
button(showPlay ? "play.fill" : "pause.fill", big: true, help: showPlay ? "Play" : "Pause") { (_: any PlayerTarget) async in
|
||
controller.togglePlayPause()
|
||
}
|
||
button("goforward.10", help: "Seek forward 10 seconds") { await $0.seek(relative: 10) }
|
||
button("forward.end.fill", help: "Next episode or track") { await $0.next(); await $0.resume() }
|
||
}
|
||
}
|
||
}
|
||
.disabled(snap.state == .unreachable)
|
||
}
|
||
|
||
private func winamp(_ system: String, wide: Bool = false,
|
||
help: String,
|
||
_ op: @escaping (any PlayerTarget) async -> Void) -> some View {
|
||
WinampTransportButton(
|
||
symbol: system,
|
||
width: wide ? 34 : 26,
|
||
height: 20,
|
||
help: help
|
||
) { controller.command(op) }
|
||
}
|
||
|
||
private func button(_ system: String, big: Bool = false,
|
||
help: String,
|
||
_ op: @escaping (any PlayerTarget) async -> Void) -> some View {
|
||
Button { controller.command(op) } label: {
|
||
Image(systemName: system).font(big ? .title3 : .body)
|
||
}
|
||
.buttonStyle(.borderless)
|
||
.help(help)
|
||
}
|
||
}
|