mirror of
https://github.com/yattee/yattee.git
synced 2026-10-26 14:42:53 +00:00
Replace per-page corner regions with one "Below Video" picker
The corner layout's below-video host is the portrait info panel, not a page host: it can render only Info, plus Comments as the panel's pill on iOS. The page editor still offered "Below Video" for every page, so assigning Related there was accepted, stored, listed as such, and then silently rendered in the side column. - The Layout section gains a "Below Video" picker in corner mode: Nothing / Info / Info and Comments (macOS offers the first two). It writes the info/comments regions; the per-page Location section and its strings are gone. - PanelSettings.normalizedPages clamps regions to what the host can render (only info/comments below, comments only together with info), so older presets self-correct. effectiveRegion(for:) resolves the platform-specific placement and is used by both the pages list labels and CornerPlayerLayout, replacing its own region checks. - The layout schematic drops the below-video block for "Nothing"; the corner-mode footer explains the constraint. - Tests cover the picker round-trip and the clamping.
This commit is contained in:
@@ -134,30 +134,23 @@ struct CornerPlayerLayout<PlayerContent: View>: View {
|
||||
playerControlsLayout.effectivePanelSettings
|
||||
}
|
||||
|
||||
/// Whether the info page is assigned to (and enabled in) the below-video
|
||||
/// region — the below panel only exists to host it.
|
||||
/// Whether the info page is assigned below the video — the below panel
|
||||
/// only exists to host it. (`effectiveRegion` already clamps to what
|
||||
/// this platform can render; info is always enabled.)
|
||||
private var hasBelowVideoInfo: Bool {
|
||||
guard let info = panelSettings.configuration(for: .info) else { return false }
|
||||
return info.isEnabled && info.region == .belowVideo
|
||||
panelSettings.effectiveRegion(for: .info) == .belowVideo
|
||||
}
|
||||
|
||||
/// Comments assigned below the video render as the portrait panel's
|
||||
/// comments pill (iOS only, and only while the info panel is below —
|
||||
/// the pill lives inside it). Everything else falls back to the column.
|
||||
/// comments pill (iOS only, and only together with the info panel — the
|
||||
/// pill lives inside it; `effectiveRegion` enforces both).
|
||||
private var hasBelowVideoComments: Bool {
|
||||
#if os(iOS)
|
||||
guard hasBelowVideoInfo,
|
||||
let comments = panelSettings.configuration(for: .comments) else { return false }
|
||||
return comments.isEnabled && comments.region == .belowVideo
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
panelSettings.isPageEnabled(.comments)
|
||||
&& panelSettings.effectiveRegion(for: .comments) == .belowVideo
|
||||
}
|
||||
|
||||
/// Pages the below-video host actually renders. Enabled pages assigned
|
||||
/// `.belowVideo` that it can't host (chapters/related/queue/tracks, or
|
||||
/// comments without the info panel) fall back to the side column instead
|
||||
/// of disappearing.
|
||||
/// Pages the below-video host renders; everything else goes to the side
|
||||
/// column.
|
||||
private var belowVideoPageTypes: Set<PanelPageType> {
|
||||
var types: Set<PanelPageType> = []
|
||||
if hasBelowVideoInfo { types.insert(.info) }
|
||||
|
||||
@@ -15,7 +15,6 @@ struct PanelPageEditorView: View {
|
||||
|
||||
// Local state for immediate UI updates
|
||||
@State private var isEnabled: Bool = true
|
||||
@State private var region: PanelRegion = .primary
|
||||
@State private var showDescription: Bool = true
|
||||
@State private var descriptionExpandedByDefault: Bool = false
|
||||
@State private var descriptionCollapsedLines: Int = InfoPageSettings.defaultDescriptionCollapsedLines
|
||||
@@ -47,10 +46,6 @@ struct PanelPageEditorView: View {
|
||||
enabledSection
|
||||
}
|
||||
|
||||
if PanelSettingsView.supportsCornerLayout, viewModel.panelLayoutMode == .corner {
|
||||
regionSection
|
||||
}
|
||||
|
||||
switch pageType {
|
||||
case .info:
|
||||
infoElementsSection
|
||||
@@ -101,28 +96,6 @@ struct PanelPageEditorView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Region Section (corner layout)
|
||||
|
||||
private var regionSection: some View {
|
||||
Section {
|
||||
Picker(
|
||||
String(localized: "panel.settings.page.region"),
|
||||
selection: $region
|
||||
) {
|
||||
ForEach(PanelRegion.allCases, id: \.self) { region in
|
||||
Text(region.displayName).tag(region)
|
||||
}
|
||||
}
|
||||
.disabled(!viewModel.canEditActivePreset)
|
||||
.onChange(of: region) { _, newValue in
|
||||
guard newValue != configuration?.region else { return }
|
||||
viewModel.setPanelPageRegion(newValue, for: pageType)
|
||||
}
|
||||
} footer: {
|
||||
Text(String(localized: "panel.settings.page.region.footer"))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Info Elements Section
|
||||
|
||||
@ViewBuilder
|
||||
@@ -351,7 +324,6 @@ struct PanelPageEditorView: View {
|
||||
|
||||
private func syncLocalState() {
|
||||
isEnabled = configuration?.isEnabled ?? true
|
||||
region = configuration?.region ?? .primary
|
||||
let info = infoSettings
|
||||
showDescription = info.effectiveShowDescription
|
||||
descriptionExpandedByDefault = info.effectiveDescriptionExpandedByDefault
|
||||
|
||||
@@ -17,6 +17,7 @@ struct PanelSettingsView: View {
|
||||
@State private var landscapeDefaultVisibility: PanelDefaultVisibility = .hidden
|
||||
@State private var layoutMode: PanelLayoutMode = .stacked
|
||||
@State private var wideLayoutSide: FloatingPanelSide = .right
|
||||
@State private var belowVideoContent: PanelBelowVideoContent = .info
|
||||
@State private var showPageBarLabels: Bool = true
|
||||
@State private var commentsShowAvatars: Bool = true
|
||||
@State private var commentsPillMode: CommentsPillMode = .pill
|
||||
@@ -71,7 +72,11 @@ struct PanelSettingsView: View {
|
||||
|
||||
private var layoutSection: some View {
|
||||
Section {
|
||||
PanelLayoutSchematic(mode: layoutMode, side: wideLayoutSide)
|
||||
PanelLayoutSchematic(
|
||||
mode: layoutMode,
|
||||
side: wideLayoutSide,
|
||||
showsBelowVideo: belowVideoContent != .nothing
|
||||
)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 4)
|
||||
.listRowBackground(Color.clear)
|
||||
@@ -104,9 +109,25 @@ struct PanelSettingsView: View {
|
||||
guard newValue != viewModel.panelWideLayoutSide else { return }
|
||||
viewModel.syncPanelWideLayoutSide(newValue)
|
||||
}
|
||||
} else {
|
||||
Picker(
|
||||
String(localized: "panel.settings.belowVideo"),
|
||||
selection: $belowVideoContent
|
||||
) {
|
||||
ForEach(PanelBelowVideoContent.availableCases, id: \.self) { content in
|
||||
Text(content.displayName).tag(content)
|
||||
}
|
||||
}
|
||||
.disabled(!viewModel.canEditActivePreset)
|
||||
.onChange(of: belowVideoContent) { _, newValue in
|
||||
guard newValue != viewModel.panelBelowVideoContent else { return }
|
||||
viewModel.syncPanelBelowVideoContent(newValue)
|
||||
}
|
||||
}
|
||||
} footer: {
|
||||
Text(String(localized: "panel.settings.layoutMode.footer"))
|
||||
Text(layoutMode == .corner
|
||||
? String(localized: "panel.settings.belowVideo.footer")
|
||||
: String(localized: "panel.settings.layoutMode.footer"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +316,7 @@ struct PanelSettingsView: View {
|
||||
}
|
||||
Spacer()
|
||||
if page.isEnabled, layoutMode == .corner, Self.supportsCornerLayout {
|
||||
Text(page.region.displayName)
|
||||
Text(viewModel.panelSettings.effectiveRegion(for: page.pageType).displayName)
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
Text(page.isEnabled
|
||||
@@ -314,6 +335,8 @@ struct PanelSettingsView: View {
|
||||
landscapeDefaultVisibility = viewModel.panelDefaultVisibility(for: .landscape)
|
||||
layoutMode = viewModel.panelLayoutMode
|
||||
wideLayoutSide = viewModel.panelWideLayoutSide
|
||||
// Clamp to what this platform offers so the picker never shows blank.
|
||||
belowVideoContent = viewModel.panelSettings.effectiveBelowVideoContent
|
||||
showPageBarLabels = viewModel.panelShowPageBarLabels
|
||||
commentsShowAvatars = commentsSettings.effectiveShowAvatars
|
||||
commentsPillMode = commentsSettings.effectivePillMode
|
||||
@@ -328,6 +351,8 @@ private struct PanelLayoutSchematic: View {
|
||||
let mode: PanelLayoutMode
|
||||
/// Panel side in the standard layout; the corner column is always right.
|
||||
let side: FloatingPanelSide
|
||||
/// Whether the corner layout has an info panel below the video.
|
||||
let showsBelowVideo: Bool
|
||||
|
||||
private let cornerRadius: CGFloat = 4
|
||||
|
||||
@@ -341,8 +366,10 @@ private struct PanelLayoutSchematic: View {
|
||||
if mode == .corner {
|
||||
VStack(spacing: 3) {
|
||||
videoBlock
|
||||
panelBlock
|
||||
.frame(height: 26)
|
||||
if showsBelowVideo {
|
||||
panelBlock
|
||||
.frame(height: 26)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
videoBlock
|
||||
@@ -361,6 +388,7 @@ private struct PanelLayoutSchematic: View {
|
||||
}
|
||||
.animation(.easeInOut(duration: 0.25), value: mode)
|
||||
.animation(.easeInOut(duration: 0.25), value: side)
|
||||
.animation(.easeInOut(duration: 0.25), value: showsBelowVideo)
|
||||
}
|
||||
|
||||
private var videoBlock: some View {
|
||||
|
||||
Reference in New Issue
Block a user