mirror of
https://github.com/yattee/yattee.git
synced 2026-02-19 17:29:45 +00:00
230 lines
8.7 KiB
Swift
230 lines
8.7 KiB
Swift
//
|
|
// BuiltInPresets.swift
|
|
// Yattee
|
|
//
|
|
// Factory methods for built-in layout presets.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
extension LayoutPreset {
|
|
/// Bump this version whenever any built-in preset definition changes.
|
|
/// On launch, the app compares this against the last-applied version
|
|
/// and replaces stale built-in presets with fresh copies from code.
|
|
static let builtInPresetsVersion = 5
|
|
|
|
// MARK: - Built-in Preset IDs
|
|
|
|
/// Stable UUIDs for built-in presets to ensure consistency across devices.
|
|
private enum BuiltInID {
|
|
static let defaultPreset = UUID(uuidString: "00000000-0000-0000-0000-000000000001")!
|
|
static let minimalPreset = UUID(uuidString: "00000000-0000-0000-0000-000000000002")!
|
|
}
|
|
|
|
// MARK: - Built-in Presets
|
|
|
|
/// Default preset with balanced controls for general use.
|
|
static func defaultPreset(for deviceClass: DeviceClass = .current) -> LayoutPreset {
|
|
// Top buttons: titleAuthor (wideOnly), spacer, orientationLock, close
|
|
let topButtons: [ControlButtonConfiguration] = [
|
|
ControlButtonConfiguration(
|
|
buttonType: .titleAuthor,
|
|
visibilityMode: .wideOnly
|
|
),
|
|
.flexibleSpacer(),
|
|
ControlButtonConfiguration(
|
|
buttonType: .contextMenu,
|
|
visibilityMode: .wideOnly
|
|
),
|
|
.defaultConfiguration(for: .orientationLock),
|
|
.defaultConfiguration(for: .close)
|
|
]
|
|
|
|
// Bottom buttons: time, queue (wideOnly), playNext (wideOnly), spacer, contextMenu (wideOnly), settings, PiP, fullscreen
|
|
let bottomButtons: [ControlButtonConfiguration] = [
|
|
ControlButtonConfiguration(
|
|
buttonType: .timeDisplay,
|
|
settings: .timeDisplay(TimeDisplaySettings(format: .currentAndTotal))
|
|
),
|
|
ControlButtonConfiguration(
|
|
buttonType: .queue,
|
|
visibilityMode: .wideOnly
|
|
),
|
|
ControlButtonConfiguration(
|
|
buttonType: .playNext,
|
|
visibilityMode: .wideOnly
|
|
),
|
|
.flexibleSpacer(),
|
|
.defaultConfiguration(for: .settings),
|
|
.defaultConfiguration(for: .pictureInPicture),
|
|
.defaultConfiguration(for: .fullscreen)
|
|
]
|
|
|
|
// Center: all enabled, 10s seek, left=volume, right=brightness
|
|
let centerSettings = CenterSectionSettings(
|
|
showPlayPause: true,
|
|
showSeekBackward: true,
|
|
showSeekForward: true,
|
|
seekBackwardSeconds: 10,
|
|
seekForwardSeconds: 10,
|
|
leftSlider: .volume,
|
|
rightSlider: .brightness
|
|
)
|
|
|
|
// Global: plain style, medium buttons, system font
|
|
let globalSettings = GlobalLayoutSettings(
|
|
style: .plain,
|
|
buttonSize: .medium,
|
|
fontStyle: .system,
|
|
systemControlsMode: .seek,
|
|
systemControlsSeekDuration: .tenSeconds,
|
|
volumeMode: .mpv
|
|
)
|
|
|
|
// Gestures: tap 2x1 with seek, seek enabled, panscan with snap
|
|
let gesturesSettings = GesturesSettings(
|
|
tapGestures: TapGesturesSettings(
|
|
isEnabled: true,
|
|
layout: .horizontalSplit,
|
|
zoneConfigurations: [
|
|
TapZoneConfiguration(position: .left, action: .seekBackward(seconds: 10)),
|
|
TapZoneConfiguration(position: .right, action: .seekForward(seconds: 10))
|
|
]
|
|
),
|
|
seekGesture: SeekGestureSettings(isEnabled: false),
|
|
panscanGesture: PanscanGestureSettings(isEnabled: true, snapToEnds: true)
|
|
)
|
|
|
|
// Player pill: queue, previous, play/pause, next, close
|
|
let playerPillSettings = PlayerPillSettings(
|
|
visibility: .portraitOnly,
|
|
buttons: [
|
|
ControlButtonConfiguration(buttonType: .queue),
|
|
ControlButtonConfiguration(buttonType: .playPrevious),
|
|
ControlButtonConfiguration(buttonType: .playPause),
|
|
ControlButtonConfiguration(buttonType: .playNext),
|
|
ControlButtonConfiguration(buttonType: .close)
|
|
]
|
|
)
|
|
|
|
// Mini player: show video, tap for PiP
|
|
let miniPlayerSettings = MiniPlayerSettings()
|
|
|
|
let layout = PlayerControlsLayout(
|
|
topSection: LayoutSection(buttons: topButtons),
|
|
centerSettings: centerSettings,
|
|
bottomSection: LayoutSection(buttons: bottomButtons),
|
|
globalSettings: globalSettings,
|
|
progressBarSettings: ProgressBarSettings(),
|
|
gesturesSettings: gesturesSettings,
|
|
playerPillSettings: playerPillSettings,
|
|
miniPlayerSettings: miniPlayerSettings
|
|
)
|
|
|
|
return LayoutPreset(
|
|
id: BuiltInID.defaultPreset,
|
|
name: String(localized: "controls.preset.default"),
|
|
createdAt: Date(timeIntervalSince1970: 0),
|
|
updatedAt: Date(timeIntervalSince1970: 0),
|
|
isBuiltIn: true,
|
|
deviceClass: deviceClass,
|
|
layout: layout
|
|
)
|
|
}
|
|
|
|
/// Minimal preset with stripped-down controls for distraction-free playback.
|
|
static func minimalPreset(for deviceClass: DeviceClass = .current) -> LayoutPreset {
|
|
let topButtons: [ControlButtonConfiguration] = [
|
|
.flexibleSpacer(),
|
|
.defaultConfiguration(for: .close)
|
|
]
|
|
|
|
let bottomButtons: [ControlButtonConfiguration] = [
|
|
ControlButtonConfiguration(
|
|
buttonType: .timeDisplay,
|
|
settings: .timeDisplay(TimeDisplaySettings(format: .currentAndTotal))
|
|
),
|
|
.flexibleSpacer(),
|
|
.defaultConfiguration(for: .settings),
|
|
.defaultConfiguration(for: .pictureInPicture),
|
|
.defaultConfiguration(for: .fullscreen)
|
|
]
|
|
|
|
let centerSettings = CenterSectionSettings(
|
|
showPlayPause: true,
|
|
showSeekBackward: true,
|
|
showSeekForward: true,
|
|
seekBackwardSeconds: 10,
|
|
seekForwardSeconds: 10,
|
|
leftSlider: .disabled,
|
|
rightSlider: .disabled
|
|
)
|
|
|
|
let globalSettings = GlobalLayoutSettings(
|
|
style: .plain,
|
|
buttonSize: .medium,
|
|
fontStyle: .system,
|
|
systemControlsMode: .seek,
|
|
systemControlsSeekDuration: .tenSeconds,
|
|
volumeMode: .mpv
|
|
)
|
|
|
|
let gesturesSettings = GesturesSettings(
|
|
tapGestures: TapGesturesSettings(
|
|
isEnabled: true,
|
|
layout: .horizontalSplit,
|
|
zoneConfigurations: [
|
|
TapZoneConfiguration(position: .left, action: .seekBackward(seconds: 10)),
|
|
TapZoneConfiguration(position: .right, action: .seekForward(seconds: 10))
|
|
]
|
|
),
|
|
seekGesture: SeekGestureSettings(isEnabled: false),
|
|
panscanGesture: PanscanGestureSettings(isEnabled: true, snapToEnds: true)
|
|
)
|
|
|
|
let playerPillSettings = PlayerPillSettings(
|
|
visibility: .never,
|
|
buttons: [
|
|
ControlButtonConfiguration(buttonType: .queue),
|
|
ControlButtonConfiguration(buttonType: .playPrevious),
|
|
ControlButtonConfiguration(buttonType: .playPause),
|
|
ControlButtonConfiguration(buttonType: .playNext),
|
|
ControlButtonConfiguration(buttonType: .close)
|
|
]
|
|
)
|
|
|
|
let miniPlayerSettings = MiniPlayerSettings()
|
|
|
|
let progressBarSettings = ProgressBarSettings(
|
|
showChapters: false,
|
|
sponsorBlockSettings: SponsorBlockSegmentSettings(showSegments: false)
|
|
)
|
|
|
|
let layout = PlayerControlsLayout(
|
|
topSection: LayoutSection(buttons: topButtons),
|
|
centerSettings: centerSettings,
|
|
bottomSection: LayoutSection(buttons: bottomButtons),
|
|
globalSettings: globalSettings,
|
|
progressBarSettings: progressBarSettings,
|
|
gesturesSettings: gesturesSettings,
|
|
playerPillSettings: playerPillSettings,
|
|
miniPlayerSettings: miniPlayerSettings
|
|
)
|
|
|
|
return LayoutPreset(
|
|
id: BuiltInID.minimalPreset,
|
|
name: String(localized: "controls.preset.minimal"),
|
|
createdAt: Date(timeIntervalSince1970: 0),
|
|
updatedAt: Date(timeIntervalSince1970: 0),
|
|
isBuiltIn: true,
|
|
deviceClass: deviceClass,
|
|
layout: layout
|
|
)
|
|
}
|
|
|
|
/// All built-in presets for the given device class.
|
|
static func allBuiltIn(for deviceClass: DeviceClass = .current) -> [LayoutPreset] {
|
|
[defaultPreset(for: deviceClass), minimalPreset(for: deviceClass)]
|
|
}
|
|
}
|