Files
yattee/Yattee/Views/Player/Panels/RelatedPanelPage.swift
Arkadiusz Fal 22451804db Route corner layout pages by region and harden page selection
The below-video panel now renders only when the info page is assigned
to that region; comments assigned below become the portrait panel's
pill (iOS), and every other below-video page falls back to the side
column instead of disappearing. Page selection snaps to the first
configured page when the current one is disabled or reordered away,
and the page bar highlight follows the actually rendered page. The
related tab stays visible with a spinner while video details load
instead of vanishing until they arrive.
2026-09-23 23:52:08 +02:00

84 lines
2.7 KiB
Swift

//
// RelatedPanelPage.swift
// Yattee
//
// Details panel page listing videos related to the current one.
//
import SwiftUI
#if os(iOS) || os(macOS)
struct RelatedPanelPage: View {
let context: PanelPageContext
var settings: RelatedPageSettings = RelatedPageSettings()
var scrollConfig: PanelScrollConfig = PanelScrollConfig()
private var relatedVideos: [Video] { context.video.relatedVideos ?? [] }
private var isLoadingDetails: Bool {
let state = context.appEnvironment?.playerService.state.videoDetailsState ?? .idle
return state == .idle || state == .loading
}
var body: some View {
PanelPageScrollView(config: scrollConfig) {
if relatedVideos.isEmpty {
if isLoadingDetails {
loadingState
} else {
emptyState
}
} else {
LazyVStack(spacing: 12) {
ForEach(Array(relatedVideos.enumerated()), id: \.element.id) { index, relatedVideo in
VideoRowView(
video: relatedVideo,
style: .regular,
showThumbnail: settings.effectiveShowThumbnails
)
.tappableVideo(
relatedVideo,
queueSource: .manual,
sourceLabel: String(localized: "videoInfo.section.relatedVideos"),
videoList: relatedVideos,
videoIndex: index,
loadMoreVideos: nil
)
if index < relatedVideos.count - 1 {
Divider()
.padding(.leading, settings.effectiveShowThumbnails
? VideoRowStyle.regular.thumbnailWidth + 12
: 0)
}
}
}
.padding(.horizontal)
.padding(.top, 8)
}
}
}
private var loadingState: some View {
ProgressView()
.frame(maxWidth: .infinity)
.padding(.vertical, 32)
}
private var emptyState: some View {
VStack(spacing: 8) {
Image(systemName: "rectangle.stack.badge.play")
.font(.title2)
.foregroundStyle(.secondary)
Text(String(localized: "videoInfo.section.relatedVideos"))
.font(.subheadline)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 32)
}
}
#endif