mirror of
https://github.com/yattee/yattee.git
synced 2024-11-09 15:58:20 +00:00
Simplify video views
This commit is contained in:
parent
52ffe19324
commit
5b0a3458f3
@ -13,7 +13,7 @@ struct TVNavigationView: View {
|
||||
.tabItem { Text("Subscriptions") }
|
||||
.tag(TabSelection.subscriptions)
|
||||
|
||||
PopularVideosView()
|
||||
PopularView()
|
||||
.tabItem { Text("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) {
|
||||
LazyVGrid(columns: items, alignment: .center) {
|
||||
ForEach(videos) { video in
|
||||
VideoCellView(video: video)
|
||||
VideoView(video: video)
|
||||
.contextMenu { VideoContextMenuView(video: video) }
|
||||
}
|
||||
}
|
||||
|
@ -37,4 +37,8 @@ extension 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 */; };
|
||||
377FC7D5267A080300A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7D4267A080300A6BBAF /* SwiftyJSON */; };
|
||||
377FC7DB267A080300A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7DA267A080300A6BBAF /* Logging */; };
|
||||
377FC7DC267A081800A6BBAF /* PopularVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularVideosView.swift */; };
|
||||
377FC7DD267A081A00A6BBAF /* PopularVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularVideosView.swift */; };
|
||||
377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
|
||||
377FC7DD267A081A00A6BBAF /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
|
||||
377FC7DE267A082100A6BBAF /* 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 */; };
|
||||
377FC7E1267A082600A6BBAF /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.swift */; };
|
||||
377FC7E2267A084A00A6BBAF /* VideoListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoListRowView.swift */; };
|
||||
377FC7E3267A084A00A6BBAF /* VideoListRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoListRowView.swift */; };
|
||||
377FC7E2267A084A00A6BBAF /* VideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoView.swift */; };
|
||||
377FC7E3267A084A00A6BBAF /* VideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoView.swift */; };
|
||||
377FC7E4267A084E00A6BBAF /* 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 */; };
|
||||
@ -94,7 +94,7 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF2892673AB89007FC770 /* ChannelView.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 */; };
|
||||
37D4B1812671653A00C925CA /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
|
||||
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 */; };
|
||||
37D4B19826717E1500C925CA /* 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 */; };
|
||||
37F4AE7326828F0900BD60EA /* 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 */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -235,7 +232,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -272,13 +269,12 @@
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
37F4AE752682908700BD60EA /* VideoCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCellView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -407,8 +403,16 @@
|
||||
37D4B0C22671614700C925CA /* PearvidiousApp.swift */,
|
||||
37BE0BD226A1D4780092E2DB /* Player.swift */,
|
||||
37BE0BD526A1D4A90092E2DB /* PlayerViewController.swift */,
|
||||
376578902685490700D4EA09 /* PlaylistsView.swift */,
|
||||
37AAF27D26737323007FC770 /* PopularView.swift */,
|
||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
||||
37AAF2932674086B007FC770 /* TabSelection.swift */,
|
||||
3714166E267A8ACC006CA35D /* TrendingView.swift */,
|
||||
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
|
||||
37AAF29926740A01007FC770 /* VideosListView.swift */,
|
||||
371231832683E62F0000B307 /* VideosView.swift */,
|
||||
37D4B18B26717B3800C925CA /* VideoView.swift */,
|
||||
37D4B0C42671614800C925CA /* Assets.xcassets */,
|
||||
37BD07C42698ADEE003EBB87 /* Pearvidious.entitlements */,
|
||||
);
|
||||
@ -453,22 +457,13 @@
|
||||
373CFABD26966115003CB2C6 /* CoverSectionView.swift */,
|
||||
37B76E95268747C900CE5671 /* OptionsView.swift */,
|
||||
373CFAEA26975CBF003CB2C6 /* PlaylistFormView.swift */,
|
||||
376578902685490700D4EA09 /* PlaylistsView.swift */,
|
||||
37AAF27D26737323007FC770 /* PopularVideosView.swift */,
|
||||
373CFAC52696617C003CB2C6 /* SearchOptionsView.swift */,
|
||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
||||
3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */,
|
||||
3714166E267A8ACC006CA35D /* TrendingView.swift */,
|
||||
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */,
|
||||
37F4AE752682908700BD60EA /* VideoCellView.swift */,
|
||||
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
|
||||
37B17DA3268A285E006AEE9B /* VideoDetailsView.swift */,
|
||||
37D4B18B26717B3800C925CA /* VideoListRowView.swift */,
|
||||
372F954926A4D0C900502766 /* VideoLoading.swift */,
|
||||
37F4AE7126828F0900BD60EA /* VideosCellsView.swift */,
|
||||
37AAF29926740A01007FC770 /* VideosListView.swift */,
|
||||
371231832683E62F0000B307 /* VideosView.swift */,
|
||||
37D4B15E267164AF00C925CA /* Assets.xcassets */,
|
||||
37D4B1AE26729DEB00C925CA /* Info.plist */,
|
||||
);
|
||||
@ -758,7 +753,6 @@
|
||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
||||
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
||||
37F4AE762682908700BD60EA /* VideoCellView.swift in Sources */,
|
||||
37C7A1DA267CACF50010EAD6 /* TrendingCountrySelectionView.swift in Sources */,
|
||||
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
||||
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
||||
@ -767,7 +761,7 @@
|
||||
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
||||
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||
377FC7DC267A081800A6BBAF /* PopularVideosView.swift in Sources */,
|
||||
377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */,
|
||||
373CFAC62696617C003CB2C6 /* SearchOptionsView.swift in Sources */,
|
||||
371231842683E62F0000B307 /* VideosView.swift in Sources */,
|
||||
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||
@ -778,7 +772,7 @@
|
||||
373CFAC026966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
||||
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||
377FC7E3267A084A00A6BBAF /* VideoListRowView.swift in Sources */,
|
||||
377FC7E3267A084A00A6BBAF /* VideoView.swift in Sources */,
|
||||
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
||||
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
||||
37AAF2942674086B007FC770 /* TabSelection.swift in Sources */,
|
||||
@ -813,17 +807,16 @@
|
||||
files = (
|
||||
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
|
||||
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||
37F4AE772682908700BD60EA /* VideoCellView.swift in Sources */,
|
||||
373CFABF26966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
||||
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
|
||||
371F2F1B269B43D300E4A7AB /* NavigationState.swift in Sources */,
|
||||
377FC7DD267A081A00A6BBAF /* PopularVideosView.swift in Sources */,
|
||||
377FC7DD267A081A00A6BBAF /* PopularView.swift in Sources */,
|
||||
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
||||
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||
377FC7E2267A084A00A6BBAF /* VideoListRowView.swift in Sources */,
|
||||
377FC7E2267A084A00A6BBAF /* VideoView.swift in Sources */,
|
||||
3765788A2685471400D4EA09 /* Playlist.swift in Sources */,
|
||||
373CFACC26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
||||
373CFAC32696616C003CB2C6 /* CoverSectionRowView.swift in Sources */,
|
||||
@ -886,7 +879,6 @@
|
||||
37AAF28026737550007FC770 /* SearchView.swift in Sources */,
|
||||
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||
37CEE4BF2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||
37F4AE782682908700BD60EA /* VideoCellView.swift in Sources */,
|
||||
37BE0BD426A1D47D0092E2DB /* Player.swift in Sources */,
|
||||
37977585268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
||||
37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
||||
@ -907,9 +899,9 @@
|
||||
373CFABE26966148003CB2C6 /* CoverSectionView.swift in Sources */,
|
||||
37B767DD2677C3CA0098BAA8 /* PlayerState.swift in Sources */,
|
||||
373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||
37D4B18E26717B3800C925CA /* VideoListRowView.swift in Sources */,
|
||||
37D4B18E26717B3800C925CA /* VideoView.swift in Sources */,
|
||||
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
||||
37AAF27E26737323007FC770 /* PopularVideosView.swift in Sources */,
|
||||
37AAF27E26737323007FC770 /* PopularView.swift in Sources */,
|
||||
37AAF29A26740A01007FC770 /* VideosListView.swift in Sources */,
|
||||
37AAF2962674086B007FC770 /* TabSelection.swift in Sources */,
|
||||
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
||||
|
@ -3,38 +3,4 @@
|
||||
uuid = "E30DA302-B258-4C14-8808-5E4CE238A4FF"
|
||||
type = "1"
|
||||
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>
|
||||
|
@ -44,15 +44,54 @@ struct AppSidebarNavigation: View {
|
||||
SubscriptionsView()
|
||||
}
|
||||
label: {
|
||||
Label("Subscriptions", systemImage: "star")
|
||||
Label("Subscriptions", systemImage: "play.rectangle.fill")
|
||||
.accessibility(label: Text("Subscriptions"))
|
||||
}
|
||||
|
||||
NavigationLink(tag: TabSelection.popular, selection: navigationState.tabSelectionOptionalBinding) {
|
||||
PopularVideosView()
|
||||
PopularView()
|
||||
}
|
||||
label: {
|
||||
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)
|
||||
|
||||
NavigationView {
|
||||
PopularVideosView()
|
||||
PopularView()
|
||||
}
|
||||
.tabItem {
|
||||
Label("Popular", systemImage: "chart.bar")
|
||||
|
@ -6,5 +6,10 @@ struct PearvidiousApp: App {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.commands {
|
||||
SidebarCommands()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Siesta
|
||||
import SwiftUI
|
||||
|
||||
struct PopularVideosView: View {
|
||||
struct PopularView: View {
|
||||
@ObservedObject private var store = Store<[Video]>()
|
||||
|
||||
var resource = InvidiousAPI.shared.popular
|
@ -1,20 +1,301 @@
|
||||
//
|
||||
// VideoView.swift
|
||||
// VideoView
|
||||
//
|
||||
// Created by Arkadiusz Fal on 26/07/2021.
|
||||
//
|
||||
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
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 {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VideoView_Previews: PreviewProvider {
|
||||
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 VideoListRowPreview: PreviewProvider {
|
||||
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 {
|
||||
List {
|
||||
ForEach(videos) { video in
|
||||
VideoListRowView(video: video)
|
||||
VideoView(video: video, layout: .list)
|
||||
.contextMenu { VideoContextMenuView(video: video) }
|
||||
#if os(tvOS)
|
||||
.listRowInsets(listRowInsets)
|
||||
@ -29,3 +29,9 @@ struct VideosListView: View {
|
||||
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