Add corner player layout on iPad and macOS

Preset-selected two-region layout: video in the top-left, a resizable
side column, and an optional region below the video. Pages are assigned
to regions per preset (Location picker in the page editor); the layout
falls back to the stacked widescreen layout below 900pt width, so Split
View and narrow windows degrade automatically.

- CornerPlayerLayout hosts the shared playerAreaForWidescreen builder,
  so the MPV hosting path is identical to the stacked layout
- Layout resolver in ExpandedPlayerSheet picks corner per layout pass;
  NavigationCoordinator.isCornerLayoutActive feeds the macOS window
  manager, which drops the aspect-ratio lock and auto-fit while corner
  is active (and restores them on exit, incl. fullscreen replay and
  window re-mounts)
- Side column width persisted via new cornerPanelColumnWidth setting
  (280-560pt, video column kept >= 480pt)
- Settings: layout mode picker (iPad/macOS) with automatic-fallback
  footer, per-page region picker when corner is on, region shown in
  the pages list
This commit is contained in:
Arkadiusz Fal
2026-09-21 23:52:09 +02:00
parent c33d125553
commit a6d989c7af
14 changed files with 582 additions and 12 deletions

View File

@@ -61,18 +61,38 @@ enum PanelPageType: String, Codable, CaseIterable, Sendable {
/// Region a page is assigned to in the corner layout.
/// `primary` is the right column in corner mode and the only panel elsewhere;
/// the assignment is ignored outside corner mode.
enum PanelRegion: String, Codable, Sendable {
enum PanelRegion: String, Codable, CaseIterable, Sendable {
case primary
case belowVideo
/// Localized name for the settings picker.
var displayName: String {
switch self {
case .primary:
return String(localized: "panel.region.primary")
case .belowVideo:
return String(localized: "panel.region.belowVideo")
}
}
}
// MARK: - Layout Mode
/// How the details panel is laid out on iPad/macOS.
/// Corner mode automatically falls back to stacked when the window is narrow.
enum PanelLayoutMode: String, Codable, Sendable {
enum PanelLayoutMode: String, Codable, CaseIterable, Sendable {
case stacked
case corner
/// Localized name for the settings picker.
var displayName: String {
switch self {
case .stacked:
return String(localized: "panel.layoutMode.stacked")
case .corner:
return String(localized: "panel.layoutMode.corner")
}
}
}
// MARK: - Default Visibility
@@ -377,6 +397,12 @@ struct PanelSettings: Codable, Hashable, Sendable {
pages[index].settings = newSettings
}
mutating func setRegion(_ region: PanelRegion, for pageType: PanelPageType) {
normalize()
guard let index = pages.firstIndex(where: { $0.pageType == pageType }) else { return }
pages[index].region = region
}
private enum CodingKeys: String, CodingKey {
case pages
case layoutMode