Add per-page element customization and panel settings polish

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.
This commit is contained in:
Arkadiusz Fal
2026-09-22 09:37:10 +02:00
parent 052cb76702
commit c289e7576e
19 changed files with 618 additions and 68 deletions

View File

@@ -37,6 +37,22 @@ enum PanelPageType: String, Codable, CaseIterable, Sendable {
}
}
/// The panel settings version when this page type was added.
/// Used for showing "NEW" badges on recently added pages.
var versionAdded: Int {
// All initial pages shipped together; bump for future page types.
return 1
}
/// Pages added after this version show a "NEW" badge in settings.
/// Raise it together with the release that introduces a new page type.
static let newBadgeThresholdVersion = 1
/// Whether this page should carry a "NEW" badge in settings.
var isRecentlyAdded: Bool {
versionAdded > Self.newBadgeThresholdVersion
}
/// SF Symbol used in the page bar and settings.
var systemImage: String {
switch self {
@@ -165,6 +181,11 @@ struct TracksPageSettings: Codable, Hashable, Sendable {
var showAudio: Bool?
var showSubtitles: Bool?
var showRate: Bool?
var effectiveShowQuality: Bool { showQuality ?? true }
var effectiveShowAudio: Bool { showAudio ?? true }
var effectiveShowSubtitles: Bool { showSubtitles ?? true }
var effectiveShowRate: Bool { showRate ?? true }
}
/// Typed per-page settings payload. Uses the same discriminator pattern as
@@ -273,6 +294,36 @@ struct PanelPageConfiguration: Codable, Hashable, Sendable, Identifiable {
return InfoPageSettings()
}
/// Comments page settings when set, defaults otherwise.
var commentsSettings: CommentsPageSettings {
if case .comments(let settings) = settings { return settings }
return CommentsPageSettings()
}
/// Related page settings when set, defaults otherwise.
var relatedSettings: RelatedPageSettings {
if case .related(let settings) = settings { return settings }
return RelatedPageSettings()
}
/// Chapters page settings when set, defaults otherwise.
var chaptersSettings: ChaptersPageSettings {
if case .chapters(let settings) = settings { return settings }
return ChaptersPageSettings()
}
/// Queue page settings when set, defaults otherwise.
var queueSettings: QueuePageSettings {
if case .queue(let settings) = settings { return settings }
return QueuePageSettings()
}
/// Tracks page settings when set, defaults otherwise.
var tracksSettings: TracksPageSettings {
if case .tracks(let settings) = settings { return settings }
return TracksPageSettings()
}
private enum CodingKeys: String, CodingKey {
case pageType
case isEnabled