mirror of
https://github.com/yattee/yattee.git
synced 2026-10-23 13:12:53 +00:00
Move comments pill mode into the comments page settings
The pill mode now lives on CommentsPageSettings and is edited in the comments page editor instead of a standalone settings section. The legacy value on PlayerPillSettings is kept for decoding old presets and migrated by effectivePanelSettings. Comments are loaded when either the comments page is enabled or the pill is not disabled.
This commit is contained in:
@@ -147,11 +147,42 @@ struct InfoPageSettings: Codable, Hashable, Sendable {
|
||||
var effectiveShowDescription: Bool { showDescription ?? true }
|
||||
}
|
||||
|
||||
// MARK: - Comments Pill Mode
|
||||
|
||||
/// Controls how the comments pill is displayed in the player.
|
||||
/// Stored on the comments page settings (moved from the player pill settings;
|
||||
/// `PlayerControlsLayout.effectivePanelSettings` migrates the legacy value).
|
||||
enum CommentsPillMode: String, Codable, Hashable, Sendable, CaseIterable {
|
||||
case pill // Default - shows expanded pill, collapses on scroll
|
||||
case button // Always show collapsed (button-only)
|
||||
case disabled // No button/pill visible
|
||||
|
||||
/// Localized display name for settings UI.
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .pill:
|
||||
return String(localized: "commentsPill.mode.pill")
|
||||
case .button:
|
||||
return String(localized: "commentsPill.mode.button")
|
||||
case .disabled:
|
||||
return String(localized: "commentsPill.mode.disabled")
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the comments pill should always be collapsed (button mode).
|
||||
var alwaysCollapsed: Bool {
|
||||
self == .button
|
||||
}
|
||||
}
|
||||
|
||||
/// Element toggles for the comments page.
|
||||
struct CommentsPageSettings: Codable, Hashable, Sendable {
|
||||
var showAvatars: Bool?
|
||||
/// How the comments pill (portrait/floating panel) is displayed.
|
||||
var pillMode: CommentsPillMode?
|
||||
|
||||
var effectiveShowAvatars: Bool { showAvatars ?? true }
|
||||
var effectivePillMode: CommentsPillMode { pillMode ?? .pill }
|
||||
}
|
||||
|
||||
/// Element toggles for the related videos page.
|
||||
@@ -418,6 +449,17 @@ struct PanelSettings: Codable, Hashable, Sendable {
|
||||
enabledPages().contains { $0.pageType == pageType }
|
||||
}
|
||||
|
||||
/// The comments pill mode from the comments page settings.
|
||||
var commentsPillMode: CommentsPillMode {
|
||||
configuration(for: .comments)?.commentsSettings.effectivePillMode ?? .pill
|
||||
}
|
||||
|
||||
/// Whether comments should be loaded from the API: needed by the comments
|
||||
/// page (when enabled) and by the pill (unless disabled).
|
||||
var shouldLoadComments: Bool {
|
||||
isPageEnabled(.comments) || commentsPillMode != .disabled
|
||||
}
|
||||
|
||||
/// The stored configuration for a page type, if present.
|
||||
func configuration(for pageType: PanelPageType) -> PanelPageConfiguration? {
|
||||
normalizedPages.first { $0.pageType == pageType }
|
||||
|
||||
@@ -100,8 +100,18 @@ struct PlayerControlsLayout: Codable, Hashable, Sendable {
|
||||
// MARK: - Panel Settings
|
||||
|
||||
/// Returns the effective details panel settings, using defaults if not set.
|
||||
/// Migrates the legacy comments pill mode (once stored on the player pill
|
||||
/// settings) into the comments page settings; the migrated value persists
|
||||
/// the first time the panel settings are edited and saved.
|
||||
var effectivePanelSettings: PanelSettings {
|
||||
panelSettings ?? .default
|
||||
var settings = panelSettings ?? .default
|
||||
if let legacyMode = playerPillSettings?.commentsPillMode,
|
||||
settings.configuration(for: .comments)?.commentsSettings.pillMode == nil {
|
||||
var comments = settings.configuration(for: .comments)?.commentsSettings ?? CommentsPageSettings()
|
||||
comments.pillMode = legacyMode
|
||||
settings.updateSettings(.comments(comments), for: .comments)
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
// MARK: - Defaults
|
||||
|
||||
@@ -8,37 +8,6 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - CommentsPillMode
|
||||
|
||||
/// Controls how the comments pill is displayed in the player.
|
||||
enum CommentsPillMode: String, Codable, Hashable, Sendable, CaseIterable {
|
||||
case pill // Default - shows expanded pill, collapses on scroll
|
||||
case button // Always show collapsed (button-only)
|
||||
case disabled // No button/pill visible, no API query
|
||||
|
||||
/// Localized display name for settings UI.
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .pill:
|
||||
return String(localized: "commentsPill.mode.pill")
|
||||
case .button:
|
||||
return String(localized: "commentsPill.mode.button")
|
||||
case .disabled:
|
||||
return String(localized: "commentsPill.mode.disabled")
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether comments should be loaded from the API.
|
||||
var shouldLoadComments: Bool {
|
||||
self != .disabled
|
||||
}
|
||||
|
||||
/// Whether the comments pill should always be collapsed (button mode).
|
||||
var alwaysCollapsed: Bool {
|
||||
self == .button
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - PillVisibility
|
||||
|
||||
/// Controls when the player pill is visible based on orientation.
|
||||
@@ -89,7 +58,9 @@ struct PlayerPillSettings: Codable, Hashable, Sendable {
|
||||
/// Ordered list of buttons to display in the pill.
|
||||
var buttons: [ControlButtonConfiguration]
|
||||
|
||||
/// How the comments pill should be displayed (optional for backward compatibility).
|
||||
/// Legacy: the comments pill mode now lives on the comments page settings
|
||||
/// (`CommentsPageSettings.pillMode`). Kept only so old presets decode;
|
||||
/// `PlayerControlsLayout.effectivePanelSettings` migrates it.
|
||||
var commentsPillMode: CommentsPillMode?
|
||||
|
||||
// MARK: - Initialization
|
||||
@@ -104,28 +75,6 @@ struct PlayerPillSettings: Codable, Hashable, Sendable {
|
||||
self.commentsPillMode = commentsPillMode
|
||||
}
|
||||
|
||||
// MARK: - Computed Properties
|
||||
|
||||
/// Returns the effective comments pill mode, defaulting to `.pill` when nil.
|
||||
var effectiveCommentsPillMode: CommentsPillMode {
|
||||
commentsPillMode ?? .pill
|
||||
}
|
||||
|
||||
/// Whether comments should be loaded from the API.
|
||||
var shouldLoadComments: Bool {
|
||||
effectiveCommentsPillMode.shouldLoadComments
|
||||
}
|
||||
|
||||
/// Whether the comments pill should always be shown collapsed.
|
||||
var isCommentsPillAlwaysCollapsed: Bool {
|
||||
effectiveCommentsPillMode.alwaysCollapsed
|
||||
}
|
||||
|
||||
/// Whether the comments pill should be visible at all.
|
||||
var shouldShowCommentsPill: Bool {
|
||||
effectiveCommentsPillMode != .disabled
|
||||
}
|
||||
|
||||
// MARK: - Mutation Helpers
|
||||
|
||||
/// Adds a button of the given type to the pill.
|
||||
|
||||
@@ -625,19 +625,6 @@ final class PlayerControlsSettingsViewModel {
|
||||
playerPillSettings.buttons
|
||||
}
|
||||
|
||||
/// Current comments pill mode.
|
||||
var commentsPillMode: CommentsPillMode {
|
||||
playerPillSettings.effectiveCommentsPillMode
|
||||
}
|
||||
|
||||
/// Synchronously updates the comments pill mode with immediate UI feedback.
|
||||
/// - Parameter mode: The new comments pill mode.
|
||||
func syncCommentsPillMode(_ mode: CommentsPillMode) {
|
||||
updatePlayerPillSettingsSync { settings in
|
||||
settings.commentsPillMode = mode
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronously updates the pill visibility with immediate UI feedback.
|
||||
/// - Parameter visibility: The new visibility mode.
|
||||
func syncPillVisibility(_ visibility: PillVisibility) {
|
||||
|
||||
@@ -165,13 +165,14 @@ extension ExpandedPlayerSheet {
|
||||
|
||||
// Check if expanded comments pill will be visible (needs extra panel height)
|
||||
let pillSettings = playerControlsLayout.effectivePlayerPillSettings
|
||||
let commentsPillMode = playerControlsLayout.effectivePanelSettings.commentsPillMode
|
||||
let hasCommentsPill = playerState?.commentsState == .loaded &&
|
||||
!(playerState?.comments.isEmpty ?? true) &&
|
||||
pillSettings.shouldShowCommentsPill
|
||||
commentsPillMode != .disabled
|
||||
let hasExpandedCommentsPill = hasCommentsPill &&
|
||||
pillSettings.visibility.isVisible(isWideLayout: false) &&
|
||||
!pillSettings.buttons.isEmpty &&
|
||||
!pillSettings.isCommentsPillAlwaysCollapsed
|
||||
!commentsPillMode.alwaysCollapsed
|
||||
|
||||
let minPanelHeight: CGFloat = useCompactPanel ? 150 : 200
|
||||
// When compact panel but expanded comments pill visible, need taller panel (~250pt)
|
||||
|
||||
@@ -70,9 +70,8 @@ extension ExpandedPlayerSheet {
|
||||
func preloadComments() async {
|
||||
guard let playerState, playerState.commentsState == .idle else { return }
|
||||
|
||||
// Check if comments pill is disabled in preset settings
|
||||
let pillSettings = playerControlsLayout.effectivePlayerPillSettings
|
||||
guard pillSettings.shouldLoadComments else {
|
||||
// Skip when nothing displays comments (page disabled and pill disabled)
|
||||
guard playerControlsLayout.effectivePanelSettings.shouldLoadComments else {
|
||||
playerState.commentsState = .disabled
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,15 +69,15 @@ struct FloatingDetailsPanel: View {
|
||||
!playerPillSettings.buttons.isEmpty
|
||||
}
|
||||
|
||||
// Comments pill helpers
|
||||
// Comments pill helpers (mode lives on the comments page settings)
|
||||
private var commentsPillMode: CommentsPillMode {
|
||||
playerPillSettings.effectiveCommentsPillMode
|
||||
panelSettings.commentsPillMode
|
||||
}
|
||||
private var shouldShowCommentsPill: Bool {
|
||||
playerPillSettings.shouldShowCommentsPill
|
||||
commentsPillMode != .disabled
|
||||
}
|
||||
private var isCommentsPillAlwaysCollapsed: Bool {
|
||||
playerPillSettings.isCommentsPillAlwaysCollapsed
|
||||
commentsPillMode.alwaysCollapsed
|
||||
}
|
||||
|
||||
private var hasVideoDescription: Bool {
|
||||
|
||||
@@ -72,15 +72,15 @@ struct PortraitDetailsPanel: View {
|
||||
!playerPillSettings.buttons.isEmpty
|
||||
}
|
||||
|
||||
// Comments pill helpers
|
||||
// Comments pill helpers (mode lives on the comments page settings)
|
||||
private var commentsPillMode: CommentsPillMode {
|
||||
playerPillSettings.effectiveCommentsPillMode
|
||||
panelSettings.commentsPillMode
|
||||
}
|
||||
private var shouldShowCommentsPill: Bool {
|
||||
!hidesCommentsPill && playerPillSettings.shouldShowCommentsPill
|
||||
!hidesCommentsPill && commentsPillMode != .disabled
|
||||
}
|
||||
private var isCommentsPillAlwaysCollapsed: Bool {
|
||||
playerPillSettings.isCommentsPillAlwaysCollapsed
|
||||
commentsPillMode.alwaysCollapsed
|
||||
}
|
||||
|
||||
private var hasVideoDescription: Bool {
|
||||
|
||||
@@ -20,6 +20,7 @@ struct PanelPageEditorView: View {
|
||||
@State private var showStatsRow: Bool = true
|
||||
@State private var showChannelRow: Bool = true
|
||||
@State private var showAvatars: Bool = true
|
||||
@State private var commentsPillMode: CommentsPillMode = .pill
|
||||
@State private var showRelatedThumbnails: Bool = true
|
||||
@State private var showChapterThumbnails: Bool = true
|
||||
@State private var showHistory: Bool = true
|
||||
@@ -167,6 +168,19 @@ struct PanelPageEditorView: View {
|
||||
guard newValue != commentsSettings.effectiveShowAvatars else { return }
|
||||
viewModel.updatePanelCommentsSettingsSync { $0.showAvatars = newValue }
|
||||
}
|
||||
|
||||
Picker(
|
||||
String(localized: "commentsPill.mode.title"),
|
||||
selection: $commentsPillMode
|
||||
) {
|
||||
ForEach(CommentsPillMode.allCases, id: \.self) { mode in
|
||||
Text(mode.displayName).tag(mode)
|
||||
}
|
||||
}
|
||||
.onChange(of: commentsPillMode) { _, newValue in
|
||||
guard newValue != commentsSettings.effectivePillMode else { return }
|
||||
viewModel.updatePanelCommentsSettingsSync { $0.pillMode = newValue }
|
||||
}
|
||||
} header: {
|
||||
Text(String(localized: "panel.settings.elements.header"))
|
||||
}
|
||||
@@ -308,6 +322,7 @@ struct PanelPageEditorView: View {
|
||||
showStatsRow = info.effectiveShowStatsRow
|
||||
showChannelRow = info.effectiveShowChannelRow
|
||||
showAvatars = commentsSettings.effectiveShowAvatars
|
||||
commentsPillMode = commentsSettings.effectivePillMode
|
||||
showRelatedThumbnails = relatedSettings.effectiveShowThumbnails
|
||||
showChapterThumbnails = chaptersSettings.effectiveShowThumbnails
|
||||
showHistory = queueSettings.effectiveShowHistory
|
||||
|
||||
@@ -91,7 +91,6 @@ private struct PlayerControlsSettingsContent: View {
|
||||
)
|
||||
LayoutSectionsSection(viewModel: viewModel)
|
||||
#if os(iOS)
|
||||
CommentsPillSection(viewModel: viewModel)
|
||||
GesturesSectionsSection(viewModel: viewModel)
|
||||
#endif
|
||||
SystemControlsSection(viewModel: viewModel)
|
||||
@@ -426,39 +425,6 @@ private struct LayoutSectionsSection: View {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Comments Pill Section
|
||||
|
||||
private struct CommentsPillSection: View {
|
||||
@Bindable var viewModel: PlayerControlsSettingsViewModel
|
||||
|
||||
// Local state for immediate UI updates
|
||||
@State private var commentsPillMode: CommentsPillMode = .pill
|
||||
|
||||
var body: some View {
|
||||
Section {
|
||||
Picker(
|
||||
String(localized: "commentsPill.mode.title"),
|
||||
selection: $commentsPillMode
|
||||
) {
|
||||
ForEach(CommentsPillMode.allCases, id: \.self) { mode in
|
||||
Text(mode.displayName).tag(mode)
|
||||
}
|
||||
}
|
||||
.disabled(!viewModel.canEditActivePreset)
|
||||
.onChange(of: commentsPillMode) { _, newValue in
|
||||
guard newValue != viewModel.commentsPillMode else { return }
|
||||
viewModel.syncCommentsPillMode(newValue)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
commentsPillMode = viewModel.commentsPillMode
|
||||
}
|
||||
.onChange(of: viewModel.activePreset?.id) { _, _ in
|
||||
commentsPillMode = viewModel.commentsPillMode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Gestures Sections Section (iOS only)
|
||||
|
||||
#if os(iOS)
|
||||
|
||||
Reference in New Issue
Block a user