mirror of
https://github.com/yattee/yattee.git
synced 2026-10-26 14:42:53 +00:00
Phase 5 of the player panels redesign: - Per-page element toggles now rendered and editable for every page: comments (author avatars), related (thumbnails), chapters (thumbnails), queue (previously played section), tracks (video/audio/subtitles/speed sections) - Page bar labels toggle (icons-only bar shows the selected page's name) - Layout mode schematic diagram in the details panel settings - NEW badge machinery for future page types (versionAdded on PanelPageType) - Typed per-page settings accessors on PanelPageConfiguration and VM update helpers for each page kind - Unit tests for per-page settings round-trip and accessor fallbacks The standalone quality selector sheet is unaffected: section gating defaults to everything visible and only the embedded tracks page passes preset settings through.
68 lines
2.2 KiB
Swift
68 lines
2.2 KiB
Swift
//
|
|
// ChaptersPanelPage.swift
|
|
// Yattee
|
|
//
|
|
// Details panel page listing video chapters; tapping seeks.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
#if os(iOS) || os(macOS)
|
|
|
|
struct ChaptersPanelPage: View {
|
|
let context: PanelPageContext
|
|
var settings: ChaptersPageSettings = ChaptersPageSettings()
|
|
var scrollConfig: PanelScrollConfig = PanelScrollConfig()
|
|
|
|
private var appEnvironment: AppEnvironment? { context.appEnvironment }
|
|
private var playerService: PlayerService? { appEnvironment?.playerService }
|
|
private var playerState: PlayerState? { playerService?.state }
|
|
|
|
private var chapters: [VideoChapter] { playerState?.chapters ?? [] }
|
|
private var currentTime: TimeInterval { playerState?.currentTime ?? 0 }
|
|
private var storyboard: Storyboard? { playerState?.preferredStoryboard }
|
|
|
|
var body: some View {
|
|
PanelPageScrollView(config: scrollConfig) {
|
|
LazyVStack(spacing: 0) {
|
|
ForEach(chapters) { chapter in
|
|
ChapterRow(
|
|
chapter: chapter,
|
|
isActive: isChapterActive(chapter),
|
|
storyboard: storyboard,
|
|
showThumbnail: settings.effectiveShowThumbnails,
|
|
onTap: {
|
|
Task {
|
|
await playerService?.seek(to: chapter.startTime)
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
.padding(.horizontal)
|
|
.padding(.top, 8)
|
|
}
|
|
.task(id: context.video.id) {
|
|
if settings.effectiveShowThumbnails {
|
|
await preloadChapterSheets()
|
|
}
|
|
}
|
|
}
|
|
|
|
private func isChapterActive(_ chapter: VideoChapter) -> Bool {
|
|
let nextChapter = chapters.first { $0.startTime > chapter.startTime }
|
|
let endTime = nextChapter?.startTime ?? .infinity
|
|
return currentTime >= chapter.startTime && currentTime < endTime
|
|
}
|
|
|
|
private func preloadChapterSheets() async {
|
|
guard let storyboard else { return }
|
|
let service = StoryboardService.shared
|
|
for chapter in chapters {
|
|
await service.loadSheet(for: chapter.startTime, from: storyboard)
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|