mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
Simplify video views
This commit is contained in:
parent
52ffe19324
commit
5b0a3458f3
@ -13,7 +13,7 @@ struct TVNavigationView: View {
|
|||||||
.tabItem { Text("Subscriptions") }
|
.tabItem { Text("Subscriptions") }
|
||||||
.tag(TabSelection.subscriptions)
|
.tag(TabSelection.subscriptions)
|
||||||
|
|
||||||
PopularVideosView()
|
PopularView()
|
||||||
.tabItem { Text("Popular") }
|
.tabItem { Text("Popular") }
|
||||||
.tag(TabSelection.popular)
|
.tag(TabSelection.popular)
|
||||||
|
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct VideoCellView: View {
|
|
||||||
@EnvironmentObject<NavigationState> private var navigationState
|
|
||||||
|
|
||||||
var video: Video
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Button(action: { navigationState.playVideo(video) }) {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
ZStack {
|
|
||||||
if let url = video.thumbnailURL(quality: .high) {
|
|
||||||
AsyncImage(url: url) { image in
|
|
||||||
image
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: 550, height: 310)
|
|
||||||
} placeholder: {
|
|
||||||
ProgressView()
|
|
||||||
}
|
|
||||||
.mask(RoundedRectangle(cornerRadius: 12))
|
|
||||||
} else {
|
|
||||||
Image(systemName: "exclamationmark.square")
|
|
||||||
.frame(width: 550, height: 310)
|
|
||||||
}
|
|
||||||
|
|
||||||
VStack {
|
|
||||||
HStack(alignment: .top) {
|
|
||||||
if video.live {
|
|
||||||
DetailBadge(text: "Live", style: .outstanding)
|
|
||||||
} else if video.upcoming {
|
|
||||||
DetailBadge(text: "Upcoming", style: .informational)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
DetailBadge(text: video.author, style: .prominent)
|
|
||||||
}
|
|
||||||
.padding(10)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
HStack(alignment: .top) {
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
if let time = video.playTime {
|
|
||||||
DetailBadge(text: time, style: .prominent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(width: 550, height: 310)
|
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text(video.title)
|
|
||||||
.bold()
|
|
||||||
.lineLimit(2)
|
|
||||||
.multilineTextAlignment(.leading)
|
|
||||||
.padding(.horizontal)
|
|
||||||
.padding(.bottom, 2)
|
|
||||||
.frame(minHeight: 80, alignment: .top)
|
|
||||||
.truncationMode(.middle)
|
|
||||||
|
|
||||||
HStack(spacing: 8) {
|
|
||||||
if video.publishedDate != nil || video.views != 0 {
|
|
||||||
if let date = video.publishedDate {
|
|
||||||
Image(systemName: "calendar")
|
|
||||||
Text(date)
|
|
||||||
}
|
|
||||||
|
|
||||||
if video.views != 0 {
|
|
||||||
Image(systemName: "eye")
|
|
||||||
Text(video.viewsCount)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Section {
|
|
||||||
if video.live {
|
|
||||||
Image(systemName: "camera.fill")
|
|
||||||
Text("Premiering now")
|
|
||||||
} else {
|
|
||||||
Image(systemName: "questionmark.app.fill")
|
|
||||||
Text("date and views unavailable")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.opacity(0.6)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding([.horizontal, .bottom])
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(width: 550, alignment: .leading)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.padding(.vertical)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VideoCellView_Preview: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
HStack {
|
|
||||||
VideoCellView(video: Video.fixture)
|
|
||||||
VideoCellView(video: Video.fixtureUpcomingWithoutPublishedOrViews)
|
|
||||||
VideoCellView(video: Video.fixtureLiveWithoutPublishedOrViews)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,215 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct VideoListRowView: View {
|
|
||||||
@EnvironmentObject<NavigationState> private var navigationState
|
|
||||||
|
|
||||||
@Environment(\.isFocused) private var focused: Bool
|
|
||||||
|
|
||||||
#if os(iOS)
|
|
||||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var video: Video
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
#if os(tvOS)
|
|
||||||
Button(action: { navigationState.playVideo(video) }) {
|
|
||||||
horizontalRow(detailsOnThumbnail: false)
|
|
||||||
}
|
|
||||||
#elseif os(macOS)
|
|
||||||
NavigationLink(destination: VideoPlayerView(video)) {
|
|
||||||
verticalRow
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
ZStack {
|
|
||||||
#if os(macOS)
|
|
||||||
verticalRow
|
|
||||||
#else
|
|
||||||
if verticalSizeClass == .compact {
|
|
||||||
horizontalRow(padding: 4)
|
|
||||||
} else {
|
|
||||||
verticalRow
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NavigationLink(destination: VideoPlayerView(video)) {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
.buttonStyle(PlainButtonStyle())
|
|
||||||
.opacity(0)
|
|
||||||
.frame(height: 0)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
func horizontalRow(detailsOnThumbnail: Bool = true, padding: Double = 0) -> some View {
|
|
||||||
HStack(alignment: .top, spacing: 2) {
|
|
||||||
if detailsOnThumbnail {
|
|
||||||
thumbnailWithDetails()
|
|
||||||
.padding(padding)
|
|
||||||
} else {
|
|
||||||
thumbnail(.medium, maxWidth: 320, maxHeight: 180)
|
|
||||||
}
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
|
||||||
videoDetail(video.title, bold: true)
|
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
|
||||||
|
|
||||||
if !detailsOnThumbnail {
|
|
||||||
videoDetail(video.author, color: .secondary, bold: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
additionalDetails
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.frame(minHeight: 180)
|
|
||||||
|
|
||||||
if !detailsOnThumbnail, let time = video.playTime {
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
VStack(alignment: .center) {
|
|
||||||
Spacer()
|
|
||||||
HStack(spacing: 8) {
|
|
||||||
Image(systemName: "clock")
|
|
||||||
Text(time)
|
|
||||||
.fontWeight(.bold)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var verticalRow: some View {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
thumbnailWithDetails(minWidth: 250, maxWidth: 600, minHeight: 180)
|
|
||||||
.frame(idealWidth: 320)
|
|
||||||
.padding([.leading, .top, .trailing], 4)
|
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
videoDetail(video.title, bold: true)
|
|
||||||
.padding(.bottom)
|
|
||||||
|
|
||||||
additionalDetails
|
|
||||||
.padding(.bottom, 10)
|
|
||||||
}
|
|
||||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
|
||||||
.padding(.horizontal, 8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var additionalDetails: some View {
|
|
||||||
VStack {
|
|
||||||
if !video.published.isEmpty || video.views != 0 {
|
|
||||||
HStack(spacing: 8) {
|
|
||||||
if !video.published.isEmpty {
|
|
||||||
Image(systemName: "calendar")
|
|
||||||
Text(video.published)
|
|
||||||
}
|
|
||||||
|
|
||||||
if video.views != 0 {
|
|
||||||
Image(systemName: "eye")
|
|
||||||
Text(video.viewsCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if os(tvOS)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
#else
|
|
||||||
.foregroundColor(focused ? .white : .secondary)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func thumbnailWithDetails(
|
|
||||||
minWidth: Double = 250,
|
|
||||||
maxWidth: Double = .infinity,
|
|
||||||
minHeight: Double = 140,
|
|
||||||
maxHeight: Double = .infinity
|
|
||||||
) -> some View {
|
|
||||||
ZStack(alignment: .trailing) {
|
|
||||||
thumbnail(.maxres, minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
|
||||||
|
|
||||||
VStack(alignment: .trailing) {
|
|
||||||
detailOnThinMaterial(video.author)
|
|
||||||
.offset(x: -5, y: 5)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
if let time = video.playTime {
|
|
||||||
detailOnThinMaterial(time, bold: true)
|
|
||||||
.offset(x: -5, y: -5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func detailOnThinMaterial(_ text: String, bold: Bool = false) -> some View {
|
|
||||||
Text(text)
|
|
||||||
.fontWeight(bold ? .semibold : .regular)
|
|
||||||
.padding(8)
|
|
||||||
.background(.thinMaterial)
|
|
||||||
.mask(RoundedRectangle(cornerRadius: 12))
|
|
||||||
}
|
|
||||||
|
|
||||||
func thumbnail(
|
|
||||||
_ quality: Thumbnail.Quality,
|
|
||||||
minWidth: Double = 320,
|
|
||||||
maxWidth: Double = .infinity,
|
|
||||||
minHeight: Double = 180,
|
|
||||||
maxHeight: Double = .infinity
|
|
||||||
) -> some View {
|
|
||||||
Group {
|
|
||||||
if let url = video.thumbnailURL(quality: quality) {
|
|
||||||
AsyncImage(url: url) { image in
|
|
||||||
image
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
|
||||||
} placeholder: {
|
|
||||||
ProgressView()
|
|
||||||
}
|
|
||||||
.mask(RoundedRectangle(cornerRadius: 12))
|
|
||||||
} else {
|
|
||||||
Image(systemName: "exclamationmark.square")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
func videoDetail(_ text: String, color: Color? = .primary, bold: Bool = false) -> some View {
|
|
||||||
Text(text)
|
|
||||||
.fontWeight(bold ? .bold : .regular)
|
|
||||||
#if os(tvOS)
|
|
||||||
.foregroundColor(color)
|
|
||||||
.lineLimit(1)
|
|
||||||
.truncationMode(.middle)
|
|
||||||
#elseif os(iOS) || os(macOS)
|
|
||||||
.foregroundColor(focused ? .white : color)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VideoListRowPreview: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
List {
|
|
||||||
VideoListRowView(video: Video.fixture)
|
|
||||||
VideoListRowView(video: Video.fixtureUpcomingWithoutPublishedOrViews)
|
|
||||||
VideoListRowView(video: Video.fixtureLiveWithoutPublishedOrViews)
|
|
||||||
}
|
|
||||||
.frame(maxWidth: 400)
|
|
||||||
|
|
||||||
#if os(iOS)
|
|
||||||
List {
|
|
||||||
VideoListRowView(video: Video.fixture)
|
|
||||||
VideoListRowView(video: Video.fixtureUpcomingWithoutPublishedOrViews)
|
|
||||||
VideoListRowView(video: Video.fixtureLiveWithoutPublishedOrViews)
|
|
||||||
}
|
|
||||||
.environment(\.verticalSizeClass, .compact)
|
|
||||||
.frame(maxWidth: 800)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,7 +15,7 @@ struct VideosCellsView: View {
|
|||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
LazyVGrid(columns: items, alignment: .center) {
|
LazyVGrid(columns: items, alignment: .center) {
|
||||||
ForEach(videos) { video in
|
ForEach(videos) { video in
|
||||||
VideoCellView(video: video)
|
VideoView(video: video)
|
||||||
.contextMenu { VideoContextMenuView(video: video) }
|
.contextMenu { VideoContextMenuView(video: video) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,4 +37,8 @@ extension Video {
|
|||||||
|
|
||||||
return video
|
return video
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var allFixtures: [Video] {
|
||||||
|
[fixture, fixtureLiveWithoutPublishedOrViews, fixtureUpcomingWithoutPublishedOrViews]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,14 +72,14 @@
|
|||||||
377A20AB2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */; };
|
377A20AB2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */; };
|
||||||
377FC7D5267A080300A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7D4267A080300A6BBAF /* SwiftyJSON */; };
|
377FC7D5267A080300A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7D4267A080300A6BBAF /* SwiftyJSON */; };
|
||||||
377FC7DB267A080300A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7DA267A080300A6BBAF /* Logging */; };
|
377FC7DB267A080300A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7DA267A080300A6BBAF /* Logging */; };
|
||||||
377FC7DC267A081800A6BBAF /* PopularVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularVideosView.swift */; };
|
377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
|
||||||
377FC7DD267A081A00A6BBAF /* PopularVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularVideosView.swift */; };
|
377FC7DD267A081A00A6BBAF /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
|
||||||
377FC7DE267A082100A6BBAF /* VideosListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF29926740A01007FC770 /* VideosListView.swift */; };
|
377FC7DE267A082100A6BBAF /* VideosListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF29926740A01007FC770 /* VideosListView.swift */; };
|
||||||
377FC7DF267A082200A6BBAF /* VideosListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF29926740A01007FC770 /* VideosListView.swift */; };
|
377FC7DF267A082200A6BBAF /* VideosListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF29926740A01007FC770 /* VideosListView.swift */; };
|
||||||
377FC7E0267A082600A6BBAF /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.swift */; };
|
377FC7E0267A082600A6BBAF /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.swift */; };
|
||||||
377FC7E1267A082600A6BBAF /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.swift */; };
|
377FC7E1267A082600A6BBAF /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.swift */; };
|
||||||
377FC7E2267A084A00A6BBAF /* VideoListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoListRowView.swift */; };
|
377FC7E2267A084A00A6BBAF /* VideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoView.swift */; };
|
||||||
377FC7E3267A084A00A6BBAF /* VideoListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoListRowView.swift */; };
|
377FC7E3267A084A00A6BBAF /* VideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoView.swift */; };
|
||||||
377FC7E4267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
377FC7E4267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
||||||
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
||||||
377FC7ED267A0A0800A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7EC267A0A0800A6BBAF /* SwiftyJSON */; };
|
377FC7ED267A0A0800A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7EC267A0A0800A6BBAF /* SwiftyJSON */; };
|
||||||
@ -94,7 +94,7 @@
|
|||||||
379775932689365600DD52A8 /* Array+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379775922689365600DD52A8 /* Array+Next.swift */; };
|
379775932689365600DD52A8 /* Array+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379775922689365600DD52A8 /* Array+Next.swift */; };
|
||||||
379775942689365600DD52A8 /* Array+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379775922689365600DD52A8 /* Array+Next.swift */; };
|
379775942689365600DD52A8 /* Array+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379775922689365600DD52A8 /* Array+Next.swift */; };
|
||||||
379775952689365600DD52A8 /* Array+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379775922689365600DD52A8 /* Array+Next.swift */; };
|
379775952689365600DD52A8 /* Array+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379775922689365600DD52A8 /* Array+Next.swift */; };
|
||||||
37AAF27E26737323007FC770 /* PopularVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularVideosView.swift */; };
|
37AAF27E26737323007FC770 /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
|
||||||
37AAF28026737550007FC770 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
37AAF28026737550007FC770 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
||||||
37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.swift */; };
|
37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.swift */; };
|
||||||
37AAF29026740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
37AAF29026740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
|
||||||
@ -166,7 +166,7 @@
|
|||||||
37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C22671614700C925CA /* PearvidiousApp.swift */; };
|
37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C22671614700C925CA /* PearvidiousApp.swift */; };
|
||||||
37D4B1812671653A00C925CA /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
|
37D4B1812671653A00C925CA /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
|
||||||
37D4B1862671691600C925CA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37D4B0C42671614800C925CA /* Assets.xcassets */; };
|
37D4B1862671691600C925CA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37D4B0C42671614800C925CA /* Assets.xcassets */; };
|
||||||
37D4B18E26717B3800C925CA /* VideoListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoListRowView.swift */; };
|
37D4B18E26717B3800C925CA /* VideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoView.swift */; };
|
||||||
37D4B19726717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
37D4B19726717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
||||||
37D4B19826717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
37D4B19826717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
||||||
37D4B19926717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
37D4B19926717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
||||||
@ -180,9 +180,6 @@
|
|||||||
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */; };
|
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */; };
|
||||||
37F4AE7326828F0900BD60EA /* VideosCellsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */; };
|
37F4AE7326828F0900BD60EA /* VideosCellsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */; };
|
||||||
37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */; };
|
37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */; };
|
||||||
37F4AE762682908700BD60EA /* VideoCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE752682908700BD60EA /* VideoCellView.swift */; };
|
|
||||||
37F4AE772682908700BD60EA /* VideoCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE752682908700BD60EA /* VideoCellView.swift */; };
|
|
||||||
37F4AE782682908700BD60EA /* VideoCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE752682908700BD60EA /* VideoCellView.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -235,7 +232,7 @@
|
|||||||
37977582268922F600DD52A8 /* InvidiousAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvidiousAPI.swift; sourceTree = "<group>"; };
|
37977582268922F600DD52A8 /* InvidiousAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvidiousAPI.swift; sourceTree = "<group>"; };
|
||||||
3797758A2689345500DD52A8 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = "<group>"; };
|
3797758A2689345500DD52A8 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = "<group>"; };
|
||||||
379775922689365600DD52A8 /* Array+Next.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Next.swift"; sourceTree = "<group>"; };
|
379775922689365600DD52A8 /* Array+Next.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Next.swift"; sourceTree = "<group>"; };
|
||||||
37AAF27D26737323007FC770 /* PopularVideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopularVideosView.swift; sourceTree = "<group>"; };
|
37AAF27D26737323007FC770 /* PopularView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopularView.swift; sourceTree = "<group>"; };
|
||||||
37AAF27F26737550007FC770 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = "<group>"; };
|
37AAF27F26737550007FC770 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = "<group>"; };
|
||||||
37AAF2892673AB89007FC770 /* ChannelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelView.swift; sourceTree = "<group>"; };
|
37AAF2892673AB89007FC770 /* ChannelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelView.swift; sourceTree = "<group>"; };
|
||||||
37AAF28F26740715007FC770 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
|
37AAF28F26740715007FC770 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
|
||||||
@ -272,13 +269,12 @@
|
|||||||
37D4B15E267164AF00C925CA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
37D4B15E267164AF00C925CA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
37D4B171267164B000C925CA /* Tests Apple TV.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Apple TV.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
37D4B171267164B000C925CA /* Tests Apple TV.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Apple TV.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
37D4B175267164B000C925CA /* PearvidiousUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PearvidiousUITests.swift; sourceTree = "<group>"; };
|
37D4B175267164B000C925CA /* PearvidiousUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PearvidiousUITests.swift; sourceTree = "<group>"; };
|
||||||
37D4B18B26717B3800C925CA /* VideoListRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoListRowView.swift; sourceTree = "<group>"; };
|
37D4B18B26717B3800C925CA /* VideoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoView.swift; sourceTree = "<group>"; };
|
||||||
37D4B19626717E1500C925CA /* Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Video.swift; sourceTree = "<group>"; };
|
37D4B19626717E1500C925CA /* Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Video.swift; sourceTree = "<group>"; };
|
||||||
37D4B1AE26729DEB00C925CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
37D4B1AE26729DEB00C925CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
37EAD86A267B9C5600D9E01B /* SponsorBlockAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SponsorBlockAPI.swift; sourceTree = "<group>"; };
|
37EAD86A267B9C5600D9E01B /* SponsorBlockAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SponsorBlockAPI.swift; sourceTree = "<group>"; };
|
||||||
37EAD86E267B9ED100D9E01B /* Segment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Segment.swift; sourceTree = "<group>"; };
|
37EAD86E267B9ED100D9E01B /* Segment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Segment.swift; sourceTree = "<group>"; };
|
||||||
37F4AE7126828F0900BD60EA /* VideosCellsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosCellsView.swift; sourceTree = "<group>"; };
|
37F4AE7126828F0900BD60EA /* VideosCellsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosCellsView.swift; sourceTree = "<group>"; };
|
||||||
37F4AE752682908700BD60EA /* VideoCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCellView.swift; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -407,8 +403,16 @@
|
|||||||
37D4B0C22671614700C925CA /* PearvidiousApp.swift */,
|
37D4B0C22671614700C925CA /* PearvidiousApp.swift */,
|
||||||
37BE0BD226A1D4780092E2DB /* Player.swift */,
|
37BE0BD226A1D4780092E2DB /* Player.swift */,
|
||||||
37BE0BD526A1D4A90092E2DB /* PlayerViewController.swift */,
|
37BE0BD526A1D4A90092E2DB /* PlayerViewController.swift */,
|
||||||
|
376578902685490700D4EA09 /* PlaylistsView.swift */,
|
||||||
|
37AAF27D26737323007FC770 /* PopularView.swift */,
|
||||||
|
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||||
|
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
||||||
37AAF2932674086B007FC770 /* TabSelection.swift */,
|
37AAF2932674086B007FC770 /* TabSelection.swift */,
|
||||||
|
3714166E267A8ACC006CA35D /* TrendingView.swift */,
|
||||||
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
|
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
|
||||||
|
37AAF29926740A01007FC770 /* VideosListView.swift */,
|
||||||
|
371231832683E62F0000B307 /* VideosView.swift */,
|
||||||
|
37D4B18B26717B3800C925CA /* VideoView.swift */,
|
||||||
37D4B0C42671614800C925CA /* Assets.xcassets */,
|
37D4B0C42671614800C925CA /* Assets.xcassets */,
|
||||||
37BD07C42698ADEE003EBB87 /* Pearvidious.entitlements */,
|
37BD07C42698ADEE003EBB87 /* Pearvidious.entitlements */,
|
||||||
);
|
);
|
||||||
@ -453,22 +457,13 @@
|
|||||||
373CFABD26966115003CB2C6 /* CoverSectionView.swift */,
|
373CFABD26966115003CB2C6 /* CoverSectionView.swift */,
|
||||||
37B76E95268747C900CE5671 /* OptionsView.swift */,
|
37B76E95268747C900CE5671 /* OptionsView.swift */,
|
||||||
373CFAEA26975CBF003CB2C6 /* PlaylistFormView.swift */,
|
373CFAEA26975CBF003CB2C6 /* PlaylistFormView.swift */,
|
||||||
376578902685490700D4EA09 /* PlaylistsView.swift */,
|
|
||||||
37AAF27D26737323007FC770 /* PopularVideosView.swift */,
|
|
||||||
373CFAC52696617C003CB2C6 /* SearchOptionsView.swift */,
|
373CFAC52696617C003CB2C6 /* SearchOptionsView.swift */,
|
||||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
|
||||||
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
|
||||||
3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */,
|
3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */,
|
||||||
3714166E267A8ACC006CA35D /* TrendingView.swift */,
|
|
||||||
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */,
|
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */,
|
||||||
37F4AE752682908700BD60EA /* VideoCellView.swift */,
|
|
||||||
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
|
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
|
||||||
37B17DA3268A285E006AEE9B /* VideoDetailsView.swift */,
|
37B17DA3268A285E006AEE9B /* VideoDetailsView.swift */,
|
||||||
37D4B18B26717B3800C925CA /* VideoListRowView.swift */,
|
|
||||||
372F954926A4D0C900502766 /* VideoLoading.swift */,
|
372F954926A4D0C900502766 /* VideoLoading.swift */,
|
||||||
37F4AE7126828F0900BD60EA /* VideosCellsView.swift */,
|
37F4AE7126828F0900BD60EA /* VideosCellsView.swift */,
|
||||||
37AAF29926740A01007FC770 /* VideosListView.swift */,
|
|
||||||
371231832683E62F0000B307 /* VideosView.swift */,
|
|
||||||
37D4B15E267164AF00C925CA /* Assets.xcassets */,
|
37D4B15E267164AF00C925CA /* Assets.xcassets */,
|
||||||
37D4B1AE26729DEB00C925CA /* Info.plist */,
|
37D4B1AE26729DEB00C925CA /* Info.plist */,
|
||||||
);
|
);
|
||||||
@ -758,7 +753,6 @@
|
|||||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
||||||
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
||||||
37F4AE762682908700BD60EA /* VideoCellView.swift in Sources */,
|
|
||||||
37C7A1DA267CACF50010EAD6 /* TrendingCountrySelectionView.swift in Sources */,
|
37C7A1DA267CACF50010EAD6 /* TrendingCountrySelectionView.swift in Sources */,
|
||||||
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
||||||
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
||||||
@ -767,7 +761,7 @@
|
|||||||
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
||||||
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||||
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
377FC7DC267A081800A6BBAF /* PopularVideosView.swift in Sources */,
|
377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */,
|
||||||
373CFAC62696617C003CB2C6 /* SearchOptionsView.swift in Sources */,
|
373CFAC62696617C003CB2C6 /* SearchOptionsView.swift in Sources */,
|
||||||
371231842683E62F0000B307 /* VideosView.swift in Sources */,
|
371231842683E62F0000B307 /* VideosView.swift in Sources */,
|
||||||
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||||
@ -778,7 +772,7 @@
|
|||||||
373CFAC026966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
373CFAC026966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
||||||
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||||
377FC7E3267A084A00A6BBAF /* VideoListRowView.swift in Sources */,
|
377FC7E3267A084A00A6BBAF /* VideoView.swift in Sources */,
|
||||||
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
||||||
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
||||||
37AAF2942674086B007FC770 /* TabSelection.swift in Sources */,
|
37AAF2942674086B007FC770 /* TabSelection.swift in Sources */,
|
||||||
@ -813,17 +807,16 @@
|
|||||||
files = (
|
files = (
|
||||||
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
|
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
|
||||||
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||||
37F4AE772682908700BD60EA /* VideoCellView.swift in Sources */,
|
|
||||||
373CFABF26966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
373CFABF26966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
||||||
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
|
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
|
||||||
371F2F1B269B43D300E4A7AB /* NavigationState.swift in Sources */,
|
371F2F1B269B43D300E4A7AB /* NavigationState.swift in Sources */,
|
||||||
377FC7DD267A081A00A6BBAF /* PopularVideosView.swift in Sources */,
|
377FC7DD267A081A00A6BBAF /* PopularView.swift in Sources */,
|
||||||
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||||
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
||||||
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
377FC7E2267A084A00A6BBAF /* VideoListRowView.swift in Sources */,
|
377FC7E2267A084A00A6BBAF /* VideoView.swift in Sources */,
|
||||||
3765788A2685471400D4EA09 /* Playlist.swift in Sources */,
|
3765788A2685471400D4EA09 /* Playlist.swift in Sources */,
|
||||||
373CFACC26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
373CFACC26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
||||||
373CFAC32696616C003CB2C6 /* CoverSectionRowView.swift in Sources */,
|
373CFAC32696616C003CB2C6 /* CoverSectionRowView.swift in Sources */,
|
||||||
@ -886,7 +879,6 @@
|
|||||||
37AAF28026737550007FC770 /* SearchView.swift in Sources */,
|
37AAF28026737550007FC770 /* SearchView.swift in Sources */,
|
||||||
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
37CEE4BF2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
37CEE4BF2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||||
37F4AE782682908700BD60EA /* VideoCellView.swift in Sources */,
|
|
||||||
37BE0BD426A1D47D0092E2DB /* Player.swift in Sources */,
|
37BE0BD426A1D47D0092E2DB /* Player.swift in Sources */,
|
||||||
37977585268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
37977585268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
||||||
37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
||||||
@ -907,9 +899,9 @@
|
|||||||
373CFABE26966148003CB2C6 /* CoverSectionView.swift in Sources */,
|
373CFABE26966148003CB2C6 /* CoverSectionView.swift in Sources */,
|
||||||
37B767DD2677C3CA0098BAA8 /* PlayerState.swift in Sources */,
|
37B767DD2677C3CA0098BAA8 /* PlayerState.swift in Sources */,
|
||||||
373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||||
37D4B18E26717B3800C925CA /* VideoListRowView.swift in Sources */,
|
37D4B18E26717B3800C925CA /* VideoView.swift in Sources */,
|
||||||
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
||||||
37AAF27E26737323007FC770 /* PopularVideosView.swift in Sources */,
|
37AAF27E26737323007FC770 /* PopularView.swift in Sources */,
|
||||||
37AAF29A26740A01007FC770 /* VideosListView.swift in Sources */,
|
37AAF29A26740A01007FC770 /* VideosListView.swift in Sources */,
|
||||||
37AAF2962674086B007FC770 /* TabSelection.swift in Sources */,
|
37AAF2962674086B007FC770 /* TabSelection.swift in Sources */,
|
||||||
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
||||||
|
@ -3,38 +3,4 @@
|
|||||||
uuid = "E30DA302-B258-4C14-8808-5E4CE238A4FF"
|
uuid = "E30DA302-B258-4C14-8808-5E4CE238A4FF"
|
||||||
type = "1"
|
type = "1"
|
||||||
version = "2.0">
|
version = "2.0">
|
||||||
<Breakpoints>
|
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "FD786D10-33CD-43A8-8D52-4F647010EC88"
|
|
||||||
shouldBeEnabled = "No"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Shared/DetailBadge.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "75"
|
|
||||||
endingLineNumber = "75"
|
|
||||||
landmarkName = "body"
|
|
||||||
landmarkType = "24">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "15B71F2E-CE6A-4ECA-9390-ED336CB3691D"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "Model/PlayerState.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "105"
|
|
||||||
endingLineNumber = "105"
|
|
||||||
landmarkName = "playNewStream(_:)"
|
|
||||||
landmarkType = "7">
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
</Breakpoints>
|
|
||||||
</Bucket>
|
</Bucket>
|
||||||
|
@ -44,15 +44,54 @@ struct AppSidebarNavigation: View {
|
|||||||
SubscriptionsView()
|
SubscriptionsView()
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
Label("Subscriptions", systemImage: "star")
|
Label("Subscriptions", systemImage: "play.rectangle.fill")
|
||||||
|
.accessibility(label: Text("Subscriptions"))
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(tag: TabSelection.popular, selection: navigationState.tabSelectionOptionalBinding) {
|
NavigationLink(tag: TabSelection.popular, selection: navigationState.tabSelectionOptionalBinding) {
|
||||||
PopularVideosView()
|
PopularView()
|
||||||
}
|
}
|
||||||
label: {
|
label: {
|
||||||
Label("Popular", systemImage: "chart.bar")
|
Label("Popular", systemImage: "chart.bar")
|
||||||
|
.accessibility(label: Text("Popular"))
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(tag: TabSelection.trending, selection: navigationState.tabSelectionOptionalBinding) {
|
||||||
|
TrendingView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Trending", systemImage: "chart.line.uptrend.xyaxis")
|
||||||
|
.accessibility(label: Text("Trending"))
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(tag: TabSelection.playlists, selection: navigationState.tabSelectionOptionalBinding) {
|
||||||
|
PlaylistsView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Playlists", systemImage: "list.and.film")
|
||||||
|
.accessibility(label: Text("Playlists"))
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(tag: TabSelection.search, selection: navigationState.tabSelectionOptionalBinding) {
|
||||||
|
SearchView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Search", systemImage: "magnifyingglass")
|
||||||
|
.accessibility(label: Text("Search"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if os(macOS)
|
||||||
|
.toolbar {
|
||||||
|
Button(action: toggleSidebar) {
|
||||||
|
Image(systemName: "sidebar.left").help("Toggle Sidebar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
private func toggleSidebar() {
|
||||||
|
NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ struct AppTabNavigation: View {
|
|||||||
.tag(TabSelection.subscriptions)
|
.tag(TabSelection.subscriptions)
|
||||||
|
|
||||||
NavigationView {
|
NavigationView {
|
||||||
PopularVideosView()
|
PopularView()
|
||||||
}
|
}
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Popular", systemImage: "chart.bar")
|
Label("Popular", systemImage: "chart.bar")
|
||||||
|
@ -6,5 +6,10 @@ struct PearvidiousApp: App {
|
|||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
ContentView()
|
||||||
}
|
}
|
||||||
|
#if !os(tvOS)
|
||||||
|
.commands {
|
||||||
|
SidebarCommands()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Siesta
|
import Siesta
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct PopularVideosView: View {
|
struct PopularView: View {
|
||||||
@ObservedObject private var store = Store<[Video]>()
|
@ObservedObject private var store = Store<[Video]>()
|
||||||
|
|
||||||
var resource = InvidiousAPI.shared.popular
|
var resource = InvidiousAPI.shared.popular
|
@ -1,20 +1,301 @@
|
|||||||
//
|
import Defaults
|
||||||
// VideoView.swift
|
|
||||||
// VideoView
|
|
||||||
//
|
|
||||||
// Created by Arkadiusz Fal on 26/07/2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct VideoView: View {
|
struct VideoView: View {
|
||||||
|
@EnvironmentObject<NavigationState> private var navigationState
|
||||||
|
|
||||||
|
@Environment(\.isFocused) private var focused: Bool
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var layout: ListingLayout?
|
||||||
|
|
||||||
|
var video: Video
|
||||||
|
|
||||||
|
init(video: Video, layout: ListingLayout? = nil) {
|
||||||
|
self.video = video
|
||||||
|
self.layout = layout
|
||||||
|
|
||||||
|
#if os(tvOS)
|
||||||
|
if self.layout == nil {
|
||||||
|
self.layout = Defaults[.layout]
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
#if os(tvOS)
|
||||||
|
if layout == .cells {
|
||||||
|
tvOSButton
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.padding(.vertical)
|
||||||
|
} else {
|
||||||
|
tvOSButton
|
||||||
|
}
|
||||||
|
#elseif os(macOS)
|
||||||
|
NavigationLink(destination: VideoPlayerView(video)) {
|
||||||
|
verticalRow
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ZStack {
|
||||||
|
#if os(macOS)
|
||||||
|
verticalRow
|
||||||
|
#else
|
||||||
|
if verticalSizeClass == .compact {
|
||||||
|
horizontalRow(padding: 4)
|
||||||
|
} else {
|
||||||
|
verticalRow
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NavigationLink(destination: VideoPlayerView(video)) {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
.opacity(0)
|
||||||
|
.frame(height: 0)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(tvOS)
|
||||||
|
var tvOSButton: some View {
|
||||||
|
Button(action: { navigationState.playVideo(video) }) {
|
||||||
|
if layout == .cells {
|
||||||
|
cellRow
|
||||||
|
} else {
|
||||||
|
horizontalRow(detailsOnThumbnail: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
func horizontalRow(detailsOnThumbnail: Bool = true, padding: Double = 0) -> some View {
|
||||||
|
HStack(alignment: .top, spacing: 2) {
|
||||||
|
if detailsOnThumbnail {
|
||||||
|
thumbnailWithDetails()
|
||||||
|
.padding(padding)
|
||||||
|
} else {
|
||||||
|
thumbnail(.medium, maxWidth: 320, maxHeight: 180)
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
videoDetail(video.title, bold: true)
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
|
if !detailsOnThumbnail {
|
||||||
|
videoDetail(video.author, color: .secondary, bold: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
additionalDetails
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.frame(minHeight: 180)
|
||||||
|
|
||||||
|
if !detailsOnThumbnail {
|
||||||
|
if video.playTime != nil || video.live || video.upcoming {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if let time = video.playTime {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: "clock")
|
||||||
|
Text(time)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
}
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
} else if video.live {
|
||||||
|
DetailBadge(text: "Live", style: .outstanding)
|
||||||
|
} else if video.upcoming {
|
||||||
|
DetailBadge(text: "Upcoming", style: .informational)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var verticalRow: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
thumbnailWithDetails(minWidth: 250, maxWidth: 600, minHeight: 180)
|
||||||
|
.frame(idealWidth: 320)
|
||||||
|
.padding([.leading, .top, .trailing], 4)
|
||||||
|
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
videoDetail(video.title, bold: true)
|
||||||
|
.padding(.bottom)
|
||||||
|
|
||||||
|
additionalDetails
|
||||||
|
.padding(.bottom, 10)
|
||||||
|
}
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding(.horizontal, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var cellRow: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
thumbnailWithDetails(minWidth: 550, maxWidth: 550, minHeight: 310, maxHeight: 310)
|
||||||
|
.padding([.leading, .top, .trailing], 4)
|
||||||
|
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
videoDetail(video.title, bold: true, lineLimit: additionalDetailsAvailable ? 2 : 3)
|
||||||
|
.frame(minHeight: 80, alignment: .top)
|
||||||
|
.padding(.bottom)
|
||||||
|
|
||||||
|
if additionalDetailsAvailable {
|
||||||
|
additionalDetails
|
||||||
|
.padding(.bottom, 10)
|
||||||
|
} else {
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 150, alignment: .leading)
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
.frame(width: 558)
|
||||||
|
}
|
||||||
|
|
||||||
|
var additionalDetailsAvailable: Bool {
|
||||||
|
video.publishedDate != nil || video.views != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var additionalDetails: some View {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
if let date = video.publishedDate {
|
||||||
|
Image(systemName: "calendar")
|
||||||
|
Text(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
if video.views != 0 {
|
||||||
|
Image(systemName: "eye")
|
||||||
|
Text(video.viewsCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(tvOS)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
#else
|
||||||
|
.foregroundColor(focused ? .white : .secondary)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
func thumbnailWithDetails(
|
||||||
|
minWidth: Double = 250,
|
||||||
|
maxWidth: Double = .infinity,
|
||||||
|
minHeight: Double = 140,
|
||||||
|
maxHeight: Double = .infinity
|
||||||
|
) -> some View {
|
||||||
|
ZStack(alignment: .trailing) {
|
||||||
|
thumbnail(.maxres, minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
||||||
|
|
||||||
|
VStack {
|
||||||
|
HStack(alignment: .top) {
|
||||||
|
if video.live {
|
||||||
|
DetailBadge(text: "Live", style: .outstanding)
|
||||||
|
} else if video.upcoming {
|
||||||
|
DetailBadge(text: "Upcoming", style: .informational)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
DetailBadge(text: video.author, style: .prominent)
|
||||||
|
}
|
||||||
|
.padding(10)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
HStack(alignment: .top) {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if let time = video.playTime {
|
||||||
|
DetailBadge(text: time, style: .prominent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func thumbnail(
|
||||||
|
_ quality: Thumbnail.Quality,
|
||||||
|
minWidth: Double = 320,
|
||||||
|
maxWidth: Double = .infinity,
|
||||||
|
minHeight: Double = 180,
|
||||||
|
maxHeight: Double = .infinity
|
||||||
|
) -> some View {
|
||||||
|
Group {
|
||||||
|
if let url = video.thumbnailURL(quality: quality) {
|
||||||
|
AsyncImage(url: url) { image in
|
||||||
|
image
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
||||||
|
} placeholder: {
|
||||||
|
ProgressView()
|
||||||
|
}
|
||||||
|
.mask(RoundedRectangle(cornerRadius: 12))
|
||||||
|
} else {
|
||||||
|
Image(systemName: "exclamationmark.square")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func videoDetail(_ text: String, color: Color? = .primary, bold: Bool = false, lineLimit: Int = 1) -> some View {
|
||||||
|
Text(text)
|
||||||
|
.fontWeight(bold ? .bold : .regular)
|
||||||
|
#if os(tvOS)
|
||||||
|
.foregroundColor(color)
|
||||||
|
.lineLimit(lineLimit)
|
||||||
|
.truncationMode(.middle)
|
||||||
|
#elseif os(iOS) || os(macOS)
|
||||||
|
.foregroundColor(focused ? .white : color)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VideoView_Previews: PreviewProvider {
|
struct VideoListRowPreview: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
VideoView()
|
#if os(tvOS)
|
||||||
|
List {
|
||||||
|
ForEach(Video.allFixtures) { video in
|
||||||
|
VideoView(video: video, layout: .list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listStyle(GroupedListStyle())
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
ForEach(Video.allFixtures) { video in
|
||||||
|
VideoView(video: video, layout: .cells)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxHeight: 600)
|
||||||
|
#else
|
||||||
|
List {
|
||||||
|
ForEach(Video.allFixtures) { video in
|
||||||
|
VideoView(video: video, layout: .list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(macOS)
|
||||||
|
.frame(minHeight: 800)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
List {
|
||||||
|
ForEach(Video.allFixtures) { video in
|
||||||
|
VideoView(video: video, layout: .list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.previewInterfaceOrientation(.landscapeRight)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ struct VideosListView: View {
|
|||||||
Section {
|
Section {
|
||||||
List {
|
List {
|
||||||
ForEach(videos) { video in
|
ForEach(videos) { video in
|
||||||
VideoListRowView(video: video)
|
VideoView(video: video, layout: .list)
|
||||||
.contextMenu { VideoContextMenuView(video: video) }
|
.contextMenu { VideoContextMenuView(video: video) }
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.listRowInsets(listRowInsets)
|
.listRowInsets(listRowInsets)
|
||||||
@ -29,3 +29,9 @@ struct VideosListView: View {
|
|||||||
EdgeInsets(top: .zero, leading: .zero, bottom: .zero, trailing: 30)
|
EdgeInsets(top: .zero, leading: .zero, bottom: .zero, trailing: 30)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VideosListView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
VideosListView(videos: Video.allFixtures)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user