From 13ef96cd02d6d8528750dd3e4f8f2579a0be3278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Tue, 28 Nov 2023 20:05:04 +0100 Subject: [PATCH] separate tvOS View --- Shared/Player/Video Details/ChapterView.swift | 177 +++++++++++------- .../Player/Video Details/ChaptersView.swift | 56 +++--- tvOS/NowPlayingView.swift | 2 +- 3 files changed, 136 insertions(+), 99 deletions(-) diff --git a/Shared/Player/Video Details/ChapterView.swift b/Shared/Player/Video Details/ChapterView.swift index ca10ace8..1e808338 100644 --- a/Shared/Player/Video Details/ChapterView.swift +++ b/Shared/Player/Video Details/ChapterView.swift @@ -3,65 +3,44 @@ import Foundation import SDWebImageSwiftUI import SwiftUI -struct ChapterView: View { - var chapter: Chapter - var nextChapterStart: Double? +#if !os(tvOS) + struct ChapterView: View { + var chapter: Chapter + var nextChapterStart: Double? - var chapterIndex: Int - @ObservedObject private var player = PlayerModel.shared + var chapterIndex: Int + @ObservedObject private var player = PlayerModel.shared - var isCurrentChapter: Bool { - player.currentChapterIndex == chapterIndex - } + var isCurrentChapter: Bool { + player.currentChapterIndex == chapterIndex + } - var hasBeenPlayed: Bool { - player.playedChapters.contains(chapterIndex) - } + var hasBeenPlayed: Bool { + player.playedChapters.contains(chapterIndex) + } - var body: some View { - Button(action: { - player.backend.seek(to: chapter.start, seekType: .userInteracted) - }) { - Group { - #if os(tvOS) - horizontalChapter - #else + var body: some View { + Button(action: { + player.backend.seek(to: chapter.start, seekType: .userInteracted) + }) { + Group { verticalChapter - #endif + } + .contentShape(Rectangle()) } - .contentShape(Rectangle()) - } - .buttonStyle(.plain) - .onReceive(PlayerTimeModel.shared.$currentTime) { cmTime in - let time = CMTimeGetSeconds(cmTime) - if time >= self.chapter.start, self.nextChapterStart == nil || time < self.nextChapterStart! { - player.currentChapterIndex = self.chapterIndex - if !player.playedChapters.contains(self.chapterIndex) { - player.playedChapters.append(self.chapterIndex) + .buttonStyle(.plain) + + .onReceive(PlayerTimeModel.shared.$currentTime) { cmTime in + let time = CMTimeGetSeconds(cmTime) + if time >= self.chapter.start, self.nextChapterStart == nil || time < self.nextChapterStart! { + player.currentChapterIndex = self.chapterIndex + if !player.playedChapters.contains(self.chapterIndex) { + player.playedChapters.append(self.chapterIndex) + } } } } - } - #if os(tvOS) - - var horizontalChapter: some View { - HStack(spacing: 12) { - if !chapter.image.isNil { - smallImage(chapter) - } - - VStack(alignment: .leading, spacing: 4) { - Text(chapter.title) - .font(.headline) - Text(chapter.start.formattedAsPlaybackTime(allowZero: true) ?? "") - .font(.system(.subheadline).monospacedDigit()) - .foregroundColor(.secondary) - } - } - .frame(maxWidth: .infinity, alignment: .leading) - } - #else var verticalChapter: some View { VStack(spacing: 12) { if !chapter.image.isNil { @@ -80,35 +59,91 @@ struct ChapterView: View { .frame(maxWidth: !chapter.image.isNil ? Self.thumbnailWidth : nil, alignment: .leading) } } - #endif - @ViewBuilder func smallImage(_ chapter: Chapter) -> some View { - WebImage(url: chapter.image, options: [.lowPriority]) - .resizable() - .placeholder { - ProgressView() + @ViewBuilder func smallImage(_ chapter: Chapter) -> some View { + WebImage(url: chapter.image, options: [.lowPriority]) + .resizable() + .placeholder { + ProgressView() + } + .indicator(.activity) + .frame(width: Self.thumbnailWidth, height: Self.thumbnailHeight) + + .mask(RoundedRectangle(cornerRadius: 6)) + } + + static var thumbnailWidth: Double { + 250 + } + + static var thumbnailHeight: Double { + thumbnailWidth / 1.7777 + } + } + +#else + struct ChapterViewTVOS: View { + var chapter: Chapter + var player = PlayerModel.shared + + var body: some View { + Button { + player.backend.seek(to: chapter.start, seekType: .userInteracted) + } label: { + Group { + horizontalChapter + } + .contentShape(Rectangle()) } - .indicator(.activity) - .frame(width: Self.thumbnailWidth, height: Self.thumbnailHeight) - #if os(tvOS) - .mask(RoundedRectangle(cornerRadius: 12)) - #else - .mask(RoundedRectangle(cornerRadius: 6)) - #endif - } + .buttonStyle(.plain) + } - static var thumbnailWidth: Double { - 250 - } + var horizontalChapter: some View { + HStack(spacing: 12) { + if !chapter.image.isNil { + smallImage(chapter) + } - static var thumbnailHeight: Double { - thumbnailWidth / 1.7777 + VStack(alignment: .leading, spacing: 4) { + Text(chapter.title) + .font(.headline) + Text(chapter.start.formattedAsPlaybackTime(allowZero: true) ?? "") + .font(.system(.subheadline).monospacedDigit()) + .foregroundColor(.secondary) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } + + @ViewBuilder func smallImage(_ chapter: Chapter) -> some View { + WebImage(url: chapter.image, options: [.lowPriority]) + .resizable() + .placeholder { + ProgressView() + } + .indicator(.activity) + .frame(width: Self.thumbnailWidth, height: Self.thumbnailHeight) + .mask(RoundedRectangle(cornerRadius: 12)) + } + + static var thumbnailWidth: Double { + 250 + } + + static var thumbnailHeight: Double { + thumbnailWidth / 1.7777 + } } -} +#endif struct ChapterView_Preview: PreviewProvider { static var previews: some View { - ChapterView(chapter: .init(title: "Chapter", start: 30), chapterIndex: 0) - .injectFixtureEnvironmentObjects() + #if os(tvOS) + ChapterViewTVOS(chapter: .init(title: "Chapter", start: 30)) + .injectFixtureEnvironmentObjects() + #else + ChapterView(chapter: .init(title: "Chapter", start: 30), nextChapterStart: nil, chapterIndex: 0) + .injectFixtureEnvironmentObjects() + #endif } } diff --git a/Shared/Player/Video Details/ChaptersView.swift b/Shared/Player/Video Details/ChaptersView.swift index 55547886..5b02d5db 100644 --- a/Shared/Player/Video Details/ChaptersView.swift +++ b/Shared/Player/Video Details/ChaptersView.swift @@ -21,7 +21,7 @@ struct ChaptersView: View { List { Section { ForEach(chapters) { chapter in - ChapterView(chapter: chapter) + ChapterViewTVOS(chapter: chapter) } } .listRowBackground(Color.clear) @@ -29,51 +29,53 @@ struct ChaptersView: View { .listStyle(.plain) #else ScrollView(.horizontal) { - LazyHStack(spacing: 20) { - ForEach(Array(chapters.indices), id: \.self) { index in - let chapter = chapters[index] - let nextChapterStart: Double? = index < chapters.count - 1 ? chapters[index + 1].start : nil - ChapterView(chapter: chapter, nextChapterStart: nextChapterStart, chapterIndex: index) - } - } - .padding(.horizontal, 15) + LazyHStack(spacing: 20) { chapterViews(for: chapters.prefix(3), opacity: 1.0) }.padding(.horizontal, 15) } #endif } else if expand { - Section { - ForEach(Array(chapters.indices), id: \.self) { index in - let chapter = chapters[index] - let nextChapterStart: Double? = index < chapters.count - 1 ? chapters[index + 1].start : nil - ChapterView(chapter: chapter, nextChapterStart: nextChapterStart, chapterIndex: index) + #if os(tvOS) + Section { + ForEach(chapters) { chapter in + ChapterViewTVOS(chapter: chapter) + } } - } - .padding(.horizontal) + #else + Section { chapterViews(for: chapters[...], opacity: 1.0) }.padding(.horizontal) + #endif } else { #if os(iOS) Button(action: { self.expand.toggle() }) { - contents + Section { + chapterViews(for: chapters.prefix(3), opacity: 0.3) + }.padding(.horizontal) } + #elseif os(macOS) + Section { + chapterViews(for: chapters.prefix(3), opacity: 0.3) + }.padding(.horizontal) #else - contents + Section { + ForEach(chapters) { chapter in + ChapterViewTVOS(chapter: chapter) + } + } #endif } } } - var contents: some View { - Section { - ForEach(Array(chapters.prefix(3).indices), id: \.self) { index in - let chapter = chapters[index] - let nextChapterStart: Double? = index < chapters.count - 1 ? chapters[index + 1].start : nil + #if !os(tvOS) + private func chapterViews(for chaptersToShow: ArraySlice, opacity: Double = 1.0) -> some View { + ForEach(Array(chaptersToShow.indices), id: \.self) { index in + let chapter = chaptersToShow[index] + let nextChapterStart: Double? = index < chaptersToShow.count - 1 ? chaptersToShow[index + 1].start : nil ChapterView(chapter: chapter, nextChapterStart: nextChapterStart, chapterIndex: index) - .allowsHitTesting(expand) - .opacity(index == 0 ? 1.0 : 0.3) + .opacity(index == 0 ? 1.0 : opacity) } } - .padding(.horizontal) - } + #endif } struct ChaptersView_Previews: PreviewProvider { diff --git a/tvOS/NowPlayingView.swift b/tvOS/NowPlayingView.swift index 1502790f..14f3976a 100644 --- a/tvOS/NowPlayingView.swift +++ b/tvOS/NowPlayingView.swift @@ -130,7 +130,7 @@ struct NowPlayingView: View { } else { Section(header: Text("Chapters")) { ForEach(video.chapters) { chapter in - ChapterView(chapter: chapter) + ChapterViewTVOS(chapter: chapter) .padding(.horizontal, 40) } }