mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
Merge pull request #665 from stonerl/chapter-pictures
allow user to disable thumbnails and jump to current chapter in horizontal view
This commit is contained in:
commit
ae12eefafc
@ -77,6 +77,8 @@ extension Defaults.Keys {
|
||||
static let collapsedLinesDescription = Key<Int>("collapsedLinesDescription", default: 5)
|
||||
|
||||
static let showChapters = Key<Bool>("showChapters", default: true)
|
||||
static let showChapterThumbnails = Key<Bool>("showChapterThumbnails", default: true)
|
||||
static let showChapterThumbnailsOnlyWhenDifferent = Key<Bool>("showChapterThumbnailsOnlyWhenDifferent", default: true)
|
||||
static let expandChapters = Key<Bool>("expandChapters", default: true)
|
||||
static let showRelated = Key<Bool>("showRelated", default: true)
|
||||
static let showInspector = Key<ShowInspectorSetting>("showInspector", default: .onlyLocal)
|
||||
|
@ -9,8 +9,13 @@ import SwiftUI
|
||||
var chapterIndex: Int
|
||||
@ObservedObject private var player = PlayerModel.shared
|
||||
|
||||
var showThumbnail: Bool
|
||||
|
||||
var isCurrentChapter: Bool {
|
||||
player.currentChapterIndex == chapterIndex
|
||||
if let currentChapterIndex = player.currentChapterIndex {
|
||||
return currentChapterIndex == chapterIndex
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
@ -27,7 +32,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 +45,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 +131,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
|
||||
}
|
||||
|
@ -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 {
|
||||
@ -29,7 +27,22 @@ struct ChaptersView: View {
|
||||
.listStyle(.plain)
|
||||
#else
|
||||
ScrollView(.horizontal) {
|
||||
LazyHStack(spacing: 20) { chapterViews(for: chapters[...]) }.padding(.horizontal, 15)
|
||||
ScrollViewReader { scrollViewProxy in
|
||||
LazyHStack(spacing: 20) {
|
||||
chapterViews(for: chapters[...], scrollViewProxy: scrollViewProxy)
|
||||
}
|
||||
.padding(.horizontal, 15)
|
||||
.onAppear {
|
||||
if let currentChapterIndex = player.currentChapterIndex {
|
||||
scrollViewProxy.scrollTo(currentChapterIndex, anchor: .center)
|
||||
}
|
||||
}
|
||||
.onChange(of: player.currentChapterIndex) { currentChapterIndex in
|
||||
if let index = currentChapterIndex {
|
||||
scrollViewProxy.scrollTo(index, anchor: .center)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if expand {
|
||||
@ -67,10 +80,11 @@ struct ChaptersView: View {
|
||||
}
|
||||
|
||||
#if !os(tvOS)
|
||||
private func chapterViews(for chaptersToShow: ArraySlice<Chapter>, opacity: Double = 1.0, clickable: Bool = true) -> some View {
|
||||
private func chapterViews(for chaptersToShow: ArraySlice<Chapter>, opacity: Double = 1.0, clickable: Bool = true, scrollViewProxy: ScrollViewProxy? = nil) -> 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)
|
||||
.id(index)
|
||||
.opacity(index == 0 ? 1.0 : opacity)
|
||||
.allowsHitTesting(clickable)
|
||||
}
|
||||
@ -80,7 +94,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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user