From 7c50db426feb62831bdab6e84e0bc56d507462cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Sat, 11 May 2024 20:18:56 +0200 Subject: [PATCH] Chapters: allow user to disable thumbnails Chapters have their own section is the settings. The users can decide if chapter thumbnails should be shown or not. Also they can decide to only show thumbnails if they are not the same. The VideoDetailsView had to be modified, to avoid compiler type-checking errors. --- Shared/Defaults.swift | 2 + Shared/Player/Video Details/ChapterView.swift | 8 +- .../Player/Video Details/ChaptersView.swift | 12 +- .../Player/Video Details/VideoDetails.swift | 140 ++++++++++-------- Shared/Settings/PlayerSettings.swift | 25 +++- 5 files changed, 114 insertions(+), 73 deletions(-) diff --git a/Shared/Defaults.swift b/Shared/Defaults.swift index 7df4c47d..8ebdd9ad 100644 --- a/Shared/Defaults.swift +++ b/Shared/Defaults.swift @@ -77,6 +77,8 @@ extension Defaults.Keys { static let collapsedLinesDescription = Key("collapsedLinesDescription", default: 5) static let showChapters = Key("showChapters", default: true) + static let showChapterThumbnails = Key("showChapterThumbnails", default: true) + static let showChapterThumbnailsOnlyWhenDifferent = Key("showChapterThumbnailsOnlyWhenDifferent", default: true) static let expandChapters = Key("expandChapters", default: true) static let showRelated = Key("showRelated", default: true) static let showInspector = Key("showInspector", default: .onlyLocal) diff --git a/Shared/Player/Video Details/ChapterView.swift b/Shared/Player/Video Details/ChapterView.swift index 8a5fc0d2..34babd1b 100644 --- a/Shared/Player/Video Details/ChapterView.swift +++ b/Shared/Player/Video Details/ChapterView.swift @@ -9,6 +9,8 @@ import SwiftUI var chapterIndex: Int @ObservedObject private var player = PlayerModel.shared + var showThumbnail: Bool + var isCurrentChapter: Bool { player.currentChapterIndex == chapterIndex } @@ -27,7 +29,7 @@ import SwiftUI var verticalChapter: some View { VStack(spacing: 12) { - if !chapter.image.isNil { + if !chapter.image.isNil, showThumbnail { smallImage(chapter) } VStack(alignment: .leading, spacing: 4) { @@ -40,7 +42,7 @@ import SwiftUI .font(.system(.subheadline).monospacedDigit()) .foregroundColor(.secondary) } - .frame(maxWidth: !chapter.image.isNil ? Self.thumbnailWidth : nil, alignment: .leading) + .frame(maxWidth: !chapter.image.isNil && showThumbnail ? Self.thumbnailWidth : nil, alignment: .leading) } } @@ -126,7 +128,7 @@ struct ChapterView_Preview: PreviewProvider { ChapterViewTVOS(chapter: .init(title: "Chapter", start: 30)) .injectFixtureEnvironmentObjects() #else - ChapterView(chapter: .init(title: "Chapter", start: 30), chapterIndex: 0) + ChapterView(chapter: .init(title: "Chapter", start: 30), chapterIndex: 0, showThumbnail: true) .injectFixtureEnvironmentObjects() #endif } diff --git a/Shared/Player/Video Details/ChaptersView.swift b/Shared/Player/Video Details/ChaptersView.swift index 65baa874..aae1031b 100644 --- a/Shared/Player/Video Details/ChaptersView.swift +++ b/Shared/Player/Video Details/ChaptersView.swift @@ -5,18 +5,16 @@ import SwiftUI struct ChaptersView: View { @ObservedObject private var player = PlayerModel.shared @Binding var expand: Bool + let chaptersHaveImages: Bool + let showThumbnails: Bool var chapters: [Chapter] { player.videoForDisplay?.chapters ?? [] } - var chaptersHaveImages: Bool { - chapters.allSatisfy { $0.image != nil } - } - var body: some View { if !chapters.isEmpty { - if chaptersHaveImages { + if chaptersHaveImages, showThumbnails { #if os(tvOS) List { Section { @@ -70,7 +68,7 @@ struct ChaptersView: View { private func chapterViews(for chaptersToShow: ArraySlice, opacity: Double = 1.0, clickable: Bool = true) -> some View { ForEach(Array(chaptersToShow.indices), id: \.self) { index in let chapter = chaptersToShow[index] - ChapterView(chapter: chapter, chapterIndex: index) + ChapterView(chapter: chapter, chapterIndex: index, showThumbnail: showThumbnails) .opacity(index == 0 ? 1.0 : opacity) .allowsHitTesting(clickable) } @@ -80,7 +78,7 @@ struct ChaptersView: View { struct ChaptersView_Previews: PreviewProvider { static var previews: some View { - ChaptersView(expand: .constant(false)) + ChaptersView(expand: .constant(false), chaptersHaveImages: false, showThumbnails: true) .injectFixtureEnvironmentObjects() } } diff --git a/Shared/Player/Video Details/VideoDetails.swift b/Shared/Player/Video Details/VideoDetails.swift index 1da9b6d8..2656ee2d 100644 --- a/Shared/Player/Video Details/VideoDetails.swift +++ b/Shared/Player/Video Details/VideoDetails.swift @@ -186,6 +186,8 @@ struct VideoDetails: View { @Default(.playerSidebar) private var playerSidebar @Default(.showInspector) private var showInspector @Default(.showChapters) private var showChapters + @Default(.showChapterThumbnails) private var showChapterThumbnails + @Default(.showChapterThumbnailsOnlyWhenDifferent) private var showChapterThumbnailsOnlyWhenDifferent @Default(.showRelated) private var showRelated #if !os(tvOS) @Default(.showScrollToTopInComments) private var showScrollToTopInComments @@ -287,6 +289,63 @@ struct VideoDetails: View { } } + func infoView(video: Video) -> some View { + VStack(alignment: .leading, spacing: 10) { + if !player.videoBeingOpened.isNil && (video.description.isNil || video.description!.isEmpty) { + VStack { + ProgressView() + .progressViewStyle(.circular) + } + .frame(maxWidth: .infinity) + } else if let description = video.description, !description.isEmpty { + Section(header: descriptionHeader) { + VideoDescription(video: video, detailsSize: detailsSize, expand: $descriptionExpanded) + .padding(.horizontal) + } + } else if !video.isLocal { + Text("No description") + .font(.caption) + .foregroundColor(.secondary) + .padding(.horizontal) + } + + if player.videoBeingOpened.isNil { + if showChapters, + !video.isLocal, + !video.chapters.isEmpty + { + Section(header: chaptersHeader) { + ChaptersView(expand: $chaptersExpanded, chaptersHaveImages: chaptersHaveImages, showThumbnails: showThumbnails) + } + } + + if showInspector == .always || video.isLocal { + InspectorView(video: player.videoForDisplay) + .padding(.horizontal) + } + + if showRelated, + !sidebarQueue, + !(player.videoForDisplay?.related.isEmpty ?? true) + { + RelatedView() + .padding(.horizontal) + .padding(.top, 20) + } + } + } + .onAppear { + if !pageAvailable(page) { + page = .info + } + } + .transition(.opacity) + .animation(nil, value: player.currentItem) + #if os(iOS) + .frame(maxWidth: YatteeApp.isForPreviews ? .infinity : maxWidth) + #endif + } + var pageView: some View { ScrollView(.vertical) { LazyVStack { @@ -296,69 +355,12 @@ struct VideoDetails: View { switch page { case .info: - Group { - if let video { - VStack(alignment: .leading, spacing: 10) { - if !player.videoBeingOpened.isNil && (video.description.isNil || video.description!.isEmpty) { - VStack { - ProgressView() - .progressViewStyle(.circular) - } - .frame(maxWidth: .infinity) - } else if let description = video.description, !description.isEmpty { - Section(header: descriptionHeader) { - VideoDescription(video: video, detailsSize: detailsSize, expand: $descriptionExpanded) - .padding(.horizontal) - } - } else if !video.isLocal { - Text("No description") - .font(.caption) - .foregroundColor(.secondary) - .padding(.horizontal) - } - - if player.videoBeingOpened.isNil { - if showChapters, - !video.isLocal, - !video.chapters.isEmpty - { - Section(header: chaptersHeader) { - ChaptersView(expand: $chaptersExpanded) - } - } - - if showInspector == .always || video.isLocal { - InspectorView(video: player.videoForDisplay) - .padding(.horizontal) - } - - if showRelated, - !sidebarQueue, - !(player.videoForDisplay?.related.isEmpty ?? true) - { - RelatedView() - .padding(.horizontal) - .padding(.top, 20) - } - } - } - } + if let video = self.video { + infoView(video: video) } - .onAppear { - if video != nil, !pageAvailable(page) { - page = .info - } - } - .transition(.opacity) - .animation(nil, value: player.currentItem) - #if os(iOS) - .frame(maxWidth: YatteeApp.isForPreviews ? .infinity : maxWidth) - #endif - case .queue: PlayerQueueView(sidebarQueue: false) .padding(.horizontal) - case .comments: CommentsView() .onAppear { @@ -447,9 +449,27 @@ struct VideoDetails: View { player.videoForDisplay?.chapters.allSatisfy { $0.image != nil } ?? false } + var chapterImagesTheSame: Bool { + guard let firstChapterURL = player.videoForDisplay?.chapters.first?.image else { + return false + } + + return player.videoForDisplay?.chapters.allSatisfy { $0.image == firstChapterURL } ?? false + } + + var showThumbnails: Bool { + if !chaptersHaveImages || !showChapterThumbnails { + return false + } + if showChapterThumbnailsOnlyWhenDifferent { + return !chapterImagesTheSame + } + return true + } + var chaptersHeader: some View { Group { - if !chaptersHaveImages { + if !chaptersHaveImages || !showThumbnails { #if canImport(UIKit) Button(action: { chaptersExpanded.toggle() diff --git a/Shared/Settings/PlayerSettings.swift b/Shared/Settings/PlayerSettings.swift index 0ae8defd..eaa890f9 100644 --- a/Shared/Settings/PlayerSettings.swift +++ b/Shared/Settings/PlayerSettings.swift @@ -32,6 +32,8 @@ struct PlayerSettings: View { @Default(.showInspector) private var showInspector @Default(.showChapters) private var showChapters + @Default(.showChapterThumbnails) private var showThumbnails + @Default(.showChapterThumbnailsOnlyWhenDifferent) private var showThumbnailsOnlyWhenDifferent @Default(.expandChapters) private var expandChapters @Default(.showRelated) private var showRelated @@ -80,8 +82,6 @@ struct PlayerSettings: View { Section(header: SettingsHeader(text: "Info".localized())) { expandVideoDescriptionToggle collapsedLineDescriptionStepper - showChaptersToggle - expandChaptersToggle showRelatedToggle #if os(macOS) HStack { @@ -93,6 +93,13 @@ struct PlayerSettings: View { inspectorVisibilityPicker #endif } + + Section(header: SettingsHeader(text: "Chapters".localized())) { + showChaptersToggle + showThumbnailsToggle + showThumbnailsWhenDifferentToggle + expandChaptersToggle + } #endif let interface = Section(header: SettingsHeader(text: "Interface".localized())) { @@ -284,7 +291,19 @@ struct PlayerSettings: View { } private var showChaptersToggle: some View { - Toggle("Chapters (if available)", isOn: $showChapters) + Toggle("Show chapters", isOn: $showChapters) + } + + private var showThumbnailsToggle: some View { + Toggle("Show thumbnails", isOn: $showThumbnails) + .disabled(!showChapters) + .foregroundColor(showChapters ? .primary : .secondary) + } + + private var showThumbnailsWhenDifferentToggle: some View { + Toggle("Show thumbnails only when unique", isOn: $showThumbnailsOnlyWhenDifferent) + .disabled(!showChapters || !showThumbnails) + .foregroundColor(showChapters && showThumbnails ? .primary : .secondary) } private var expandChaptersToggle: some View {