mirror of
https://github.com/yattee/yattee.git
synced 2026-10-28 15:37:17 +00:00
Phase 1 of the player panels redesign: - New PanelSettings model (pages, regions, layout mode, default visibility) stored as an optional field on PlayerControlsLayout with an effectivePanelSettings accessor; lenient Codable so future page types and settings payloads never corrupt saved presets. - New Views/Player/Panels content engine: PlayerPanelContentView renders a page bar plus the selected page (info, comments, related, chapters, queue, tracks), with runtime hiding of empty pages. - PortraitDetailsPanel and FloatingDetailsPanel now host the shared content instead of their duplicated info bodies; drag machinery, pills, and fades are untouched. - Comments list extracted into CommentsListContent shared by the overlay and the comments page; comments pill routes to the comments page (expanding the portrait panel) when the page is enabled, and falls back to the overlay when it is not. - Tracks page embeds QualitySelectorView via a new isEmbedded mode. - Deleted the unused video info bodies in ExpandedPlayerSheet+VideoInfo and the dead PlayerInfoTab model.
62 lines
2.0 KiB
Swift
62 lines
2.0 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 scrollConfig: PanelScrollConfig = PanelScrollConfig()
|
|
|
|
private var relatedVideos: [Video] { context.video.relatedVideos ?? [] }
|
|
|
|
var body: some View {
|
|
PanelPageScrollView(config: scrollConfig) {
|
|
if relatedVideos.isEmpty {
|
|
emptyState
|
|
} else {
|
|
LazyVStack(spacing: 12) {
|
|
ForEach(Array(relatedVideos.enumerated()), id: \.element.id) { index, relatedVideo in
|
|
VideoRowView(video: relatedVideo, style: .regular)
|
|
.tappableVideo(
|
|
relatedVideo,
|
|
queueSource: .manual,
|
|
sourceLabel: String(localized: "videoInfo.section.relatedVideos"),
|
|
videoList: relatedVideos,
|
|
videoIndex: index,
|
|
loadMoreVideos: nil
|
|
)
|
|
|
|
if index < relatedVideos.count - 1 {
|
|
Divider()
|
|
.padding(.leading, VideoRowStyle.regular.thumbnailWidth + 12)
|
|
}
|
|
}
|
|
}
|
|
.padding(.horizontal)
|
|
.padding(.top, 8)
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|