From 9c5e427c7b798d74d722c1adbcb48f415605e6b4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Mon, 2 Aug 2021 01:01:24 +0200 Subject: [PATCH] Layout improvements --- Apple TV/VideosCellsView.swift | 33 ---- Pearvidious.xcodeproj/project.pbxproj | 28 ++-- Shared/AppSidebarNavigation.swift | 2 - Shared/ContentView.swift | 15 +- Shared/VideoView.swift | 185 ++++++---------------- Shared/VideosCellsView.swift | 65 ++++++++ Shared/VideosListView.swift | 16 +- Shared/VideosView.swift | 27 +--- {Mac => macOS}/Player.swift | 0 {Mac => macOS}/PlayerViewController.swift | 0 10 files changed, 148 insertions(+), 223 deletions(-) delete mode 100644 Apple TV/VideosCellsView.swift create mode 100644 Shared/VideosCellsView.swift rename {Mac => macOS}/Player.swift (100%) rename {Mac => macOS}/PlayerViewController.swift (100%) diff --git a/Apple TV/VideosCellsView.swift b/Apple TV/VideosCellsView.swift deleted file mode 100644 index e4a6ed3b..00000000 --- a/Apple TV/VideosCellsView.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Defaults -import SwiftUI - -struct VideosCellsView: View { - @State private var columns: Int - - init(videos: [Video], columns: Int = 3) { - self.videos = videos - self.columns = columns - } - - var videos = [Video]() - - var body: some View { - ScrollView(.vertical, showsIndicators: false) { - LazyVGrid(columns: items, alignment: .center) { - ForEach(videos) { video in - VideoView(video: video) - .contextMenu { VideoContextMenuView(video: video) } - } - } - .padding() - } - } - - var items: [GridItem] { - Array(repeating: .init(.fixed(600)), count: gridColumns) - } - - var gridColumns: Int { - videos.count < columns ? videos.count : columns - } -} diff --git a/Pearvidious.xcodeproj/project.pbxproj b/Pearvidious.xcodeproj/project.pbxproj index ca9e3364..06980a39 100644 --- a/Pearvidious.xcodeproj/project.pbxproj +++ b/Pearvidious.xcodeproj/project.pbxproj @@ -14,9 +14,6 @@ 3711403F26B206A6005B3555 /* SearchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3711403E26B206A6005B3555 /* SearchState.swift */; }; 3711404026B206A6005B3555 /* SearchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3711403E26B206A6005B3555 /* SearchState.swift */; }; 3711404126B206A6005B3555 /* SearchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3711403E26B206A6005B3555 /* SearchState.swift */; }; - 371231842683E62F0000B307 /* VideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371231832683E62F0000B307 /* VideosView.swift */; }; - 371231852683E7820000B307 /* VideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371231832683E62F0000B307 /* VideosView.swift */; }; - 371231862683E7820000B307 /* VideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371231832683E62F0000B307 /* VideosView.swift */; }; 3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3714166E267A8ACC006CA35D /* TrendingView.swift */; }; 37141670267A8ACC006CA35D /* TrendingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3714166E267A8ACC006CA35D /* TrendingView.swift */; }; 37141671267A8ACC006CA35D /* TrendingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3714166E267A8ACC006CA35D /* TrendingView.swift */; }; @@ -69,6 +66,9 @@ 376578912685490700D4EA09 /* PlaylistsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578902685490700D4EA09 /* PlaylistsView.swift */; }; 376578922685490700D4EA09 /* PlaylistsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578902685490700D4EA09 /* PlaylistsView.swift */; }; 376578932685490700D4EA09 /* PlaylistsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578902685490700D4EA09 /* PlaylistsView.swift */; }; + 37754C9D26B7500000DBD602 /* VideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37754C9C26B7500000DBD602 /* VideosView.swift */; }; + 37754C9E26B7500000DBD602 /* VideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37754C9C26B7500000DBD602 /* VideosView.swift */; }; + 37754C9F26B7500000DBD602 /* VideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37754C9C26B7500000DBD602 /* VideosView.swift */; }; 377A20A92693C9A2002842B8 /* TypedContentAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */; }; 377A20AA2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */; }; 377A20AB2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */; }; @@ -76,8 +76,6 @@ 377FC7DB267A080300A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7DA267A080300A6BBAF /* Logging */; }; 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 /* VideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoView.swift */; }; @@ -209,7 +207,6 @@ 3705B17F267B4DFB00704544 /* TrendingCountrySelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCountrySelection.swift; sourceTree = ""; }; 3705B181267B4E4900704544 /* TrendingCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCategory.swift; sourceTree = ""; }; 3711403E26B206A6005B3555 /* SearchState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchState.swift; sourceTree = ""; }; - 371231832683E62F0000B307 /* VideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosView.swift; sourceTree = ""; }; 3714166E267A8ACC006CA35D /* TrendingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingView.swift; sourceTree = ""; }; 37141672267A8E10006CA35D /* Country.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Country.swift; sourceTree = ""; }; 371F2F19269B43D300E4A7AB /* NavigationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationState.swift; sourceTree = ""; }; @@ -227,6 +224,7 @@ 376578842685429C00D4EA09 /* CaseIterable+Next.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CaseIterable+Next.swift"; sourceTree = ""; }; 376578882685471400D4EA09 /* Playlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Playlist.swift; sourceTree = ""; }; 376578902685490700D4EA09 /* PlaylistsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistsView.swift; sourceTree = ""; }; + 37754C9C26B7500000DBD602 /* VideosView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideosView.swift; sourceTree = ""; }; 377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = ""; }; 37977582268922F600DD52A8 /* InvidiousAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvidiousAPI.swift; sourceTree = ""; }; 3797758A2689345500DD52A8 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; @@ -353,13 +351,13 @@ name = Frameworks; sourceTree = ""; }; - 37BE0BD826A214500092E2DB /* Mac */ = { + 37BE0BD826A214500092E2DB /* macOS */ = { isa = PBXGroup; children = ( 37BE0BDB26A2367F0092E2DB /* Player.swift */, 37BE0BD926A214630092E2DB /* PlayerViewController.swift */, ); - path = Mac; + path = macOS; sourceTree = ""; }; 37C7A9022679058300E721B4 /* Extensions */ = { @@ -376,7 +374,7 @@ isa = PBXGroup; children = ( 37D4B0C12671614700C925CA /* Shared */, - 37BE0BD826A214500092E2DB /* Mac */, + 37BE0BD826A214500092E2DB /* macOS */, 37D4B1B72672CFE300C925CA /* Model */, 37D4B159267164AE00C925CA /* Apple TV */, 37C7A9022679058300E721B4 /* Extensions */, @@ -407,10 +405,11 @@ 37AAF29F26741C97007FC770 /* SubscriptionsView.swift */, 3705B17F267B4DFB00704544 /* TrendingCountrySelection.swift */, 3714166E267A8ACC006CA35D /* TrendingView.swift */, + 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */, 37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */, 37AAF29926740A01007FC770 /* VideosListView.swift */, - 371231832683E62F0000B307 /* VideosView.swift */, 37D4B18B26717B3800C925CA /* VideoView.swift */, + 37754C9C26B7500000DBD602 /* VideosView.swift */, 37D4B0C42671614800C925CA /* Assets.xcassets */, 37BD07C42698ADEE003EBB87 /* Pearvidious.entitlements */, ); @@ -459,7 +458,6 @@ 37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */, 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */, 37B17DA3268A285E006AEE9B /* VideoDetailsView.swift */, - 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */, 37D4B15E267164AF00C925CA /* Assets.xcassets */, 37D4B1AE26729DEB00C925CA /* Info.plist */, ); @@ -753,6 +751,7 @@ 37C7A1DA267CACF50010EAD6 /* TrendingCountrySelection.swift in Sources */, 37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */, 37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */, + 37754C9D26B7500000DBD602 /* VideosView.swift in Sources */, 3711403F26B206A6005B3555 /* SearchState.swift in Sources */, 37BE0BD326A1D4780092E2DB /* Player.swift in Sources */, 37CEE4C12677B697005A1EFE /* Stream.swift in Sources */, @@ -761,7 +760,6 @@ 3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */, 377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */, 373CFAC62696617C003CB2C6 /* SearchOptionsView.swift in Sources */, - 371231842683E62F0000B307 /* VideosView.swift in Sources */, 3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */, 37EAD86F267B9ED100D9E01B /* Segment.swift in Sources */, 376578892685471400D4EA09 /* Playlist.swift in Sources */, @@ -787,7 +785,6 @@ 3748186E26A769D60084E870 /* DetailBadge.swift in Sources */, 37AAF2A026741C97007FC770 /* SubscriptionsView.swift in Sources */, 373CFAEB26975CBF003CB2C6 /* PlaylistFormView.swift in Sources */, - 377FC7DF267A082200A6BBAF /* VideosListView.swift in Sources */, 372915E62687E3B900F5A35B /* Defaults.swift in Sources */, 37D4B19726717E1500C925CA /* Video.swift in Sources */, 371F2F1A269B43D300E4A7AB /* NavigationState.swift in Sources */, @@ -831,14 +828,13 @@ 379775942689365600DD52A8 /* Array+Next.swift in Sources */, 3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */, 37BE0BDA26A214630092E2DB /* PlayerViewController.swift in Sources */, - 371231862683E7820000B307 /* VideosView.swift in Sources */, 37C7A1D6267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */, 37C7A1DD267CE9D90010EAD6 /* Profile.swift in Sources */, 37B767DC2677C3CA0098BAA8 /* PlayerState.swift in Sources */, + 37754C9E26B7500000DBD602 /* VideosView.swift in Sources */, 3797758C2689345500DD52A8 /* Store.swift in Sources */, 37141674267A8E10006CA35D /* Country.swift in Sources */, 37AAF2A126741C97007FC770 /* SubscriptionsView.swift in Sources */, - 377FC7DE267A082100A6BBAF /* VideosListView.swift in Sources */, 37D4B19826717E1500C925CA /* Video.swift in Sources */, 37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */, 37BD07C12698AD3B003EBB87 /* TrendingCountrySelection.swift in Sources */, @@ -873,6 +869,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 37754C9F26B7500000DBD602 /* VideosView.swift in Sources */, 37AAF28026737550007FC770 /* SearchView.swift in Sources */, 37EAD871267B9ED100D9E01B /* Segment.swift in Sources */, 37CEE4BF2677B670005A1EFE /* SingleAssetStream.swift in Sources */, @@ -881,7 +878,6 @@ 37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */, 376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */, 37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */, - 371231852683E7820000B307 /* VideosView.swift in Sources */, 3748187026A769D60084E870 /* DetailBadge.swift in Sources */, 37BD07CA2698FBE5003EBB87 /* AppSidebarNavigation.swift in Sources */, 373CFAC926966188003CB2C6 /* SearchOptionsView.swift in Sources */, diff --git a/Shared/AppSidebarNavigation.swift b/Shared/AppSidebarNavigation.swift index 6330ec1c..4ffca915 100644 --- a/Shared/AppSidebarNavigation.swift +++ b/Shared/AppSidebarNavigation.swift @@ -40,8 +40,6 @@ struct AppSidebarNavigation: View { .frame(minWidth: 180) Text("Select section") - - Text("Select video") } } diff --git a/Shared/ContentView.swift b/Shared/ContentView.swift index 978a0485..bf32c52c 100644 --- a/Shared/ContentView.swift +++ b/Shared/ContentView.swift @@ -22,8 +22,21 @@ struct ContentView: View { TVNavigationView() #endif } + #if !os(tvOS) + .sheet(isPresented: $navigationState.showingVideo) { + if let video = navigationState.video { + VideoPlayerView(video) + #if !os(iOS) + .frame(minWidth: 500, minHeight: 300) + .onExitCommand { + navigationState.showingVideo = false + } + #endif + } + } + #endif .environmentObject(navigationState) - .environmentObject(searchState) + .environmentObject(searchState) } } diff --git a/Shared/VideoView.swift b/Shared/VideoView.swift index c3235959..b45c7c52 100644 --- a/Shared/VideoView.swift +++ b/Shared/VideoView.swift @@ -4,90 +4,43 @@ import SwiftUI struct VideoView: View { @EnvironmentObject 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 layout: ListingLayout var body: some View { - #if os(tvOS) + Button(action: { navigationState.playVideo(video) }) { 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 os(iOS) if verticalSizeClass == .compact { - horizontalRow(padding: 4) + horizontalRow + .padding(.vertical, 4) } else { verticalRow } + #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) - } + } else { + horizontalRow } } - #endif + .buttonStyle(.plain) + } - func horizontalRow(detailsOnThumbnail: Bool = true, padding: Double = 0) -> some View { + var horizontalRow: some View { HStack(alignment: .top, spacing: 2) { - if detailsOnThumbnail { - thumbnailWithDetails() - .padding(padding) - } else { - thumbnail(.medium, maxWidth: 320, maxHeight: 180) - } + thumbnailImage(quality: .medium) + .frame(maxWidth: 320) VStack(alignment: .leading, spacing: 0) { - videoDetail(video.title, bold: true) + videoDetail(video.title) .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) - if !detailsOnThumbnail { - videoDetail(video.author, color: .secondary, bold: true) - } + videoDetail(video.author) Spacer() @@ -96,60 +49,42 @@ struct VideoView: View { .padding() .frame(minHeight: 180) - if !detailsOnThumbnail { - if video.playTime != nil || video.live || video.upcoming { + if video.playTime != nil || video.live || video.upcoming { + Spacer() + + VStack(alignment: .center) { 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) + if let time = video.playTime { + HStack(spacing: 4) { + Image(systemName: "clock") + Text(time) + .fontWeight(.bold) } - - Spacer() + .foregroundColor(.secondary) + } else if video.live { + DetailBadge(text: "Live", style: .outstanding) + } else if video.upcoming { + DetailBadge(text: "Upcoming", style: .informational) } + + Spacer() } } } + .padding(.trailing) } var verticalRow: some View { VStack(alignment: .leading) { - thumbnailWithDetails(minWidth: 250, maxWidth: 600, minHeight: 180) - .frame(idealWidth: 320) - .padding([.leading, .top, .trailing], 4) + thumbnail 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) + videoDetail(video.title, lineLimit: additionalDetailsAvailable ? 2 : 3) .frame(minHeight: 80, alignment: .top) + #if os(tvOS) .padding(.bottom) + #endif if additionalDetailsAvailable { additionalDetails @@ -158,10 +93,11 @@ struct VideoView: View { Spacer() } } - .frame(minWidth: 0, maxWidth: .infinity, minHeight: 150, alignment: .leading) - .padding(10) + #if os(tvOS) + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 150, alignment: .leading) + .padding(10) + #endif } - .frame(width: 558) } var additionalDetailsAvailable: Bool { @@ -180,21 +116,12 @@ struct VideoView: View { Text(video.viewsCount) } } - #if os(tvOS) - .foregroundColor(.secondary) - #else - .foregroundColor(focused ? .white : .secondary) - #endif + .foregroundColor(.secondary) } - func thumbnailWithDetails( - minWidth: Double = 250, - maxWidth: Double = .infinity, - minHeight: Double = 140, - maxHeight: Double = .infinity - ) -> some View { + var thumbnail: some View { ZStack(alignment: .leading) { - thumbnail(.maxres, minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight) + thumbnailImage(quality: .maxres) VStack { HStack(alignment: .top) { @@ -222,44 +149,34 @@ struct VideoView: View { .padding(10) } } + .padding([.leading, .top, .trailing], 4) .frame(maxWidth: 600) } - func thumbnail( - _ quality: Thumbnail.Quality, - minWidth: Double = 320, - maxWidth: Double = .infinity, - minHeight: Double = 180, - maxHeight: Double = .infinity - ) -> some View { + func thumbnailImage(quality: Thumbnail.Quality) -> 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() + .aspectRatio(contentMode: .fill) } .mask(RoundedRectangle(cornerRadius: 12)) } else { Image(systemName: "exclamationmark.square") } } - .frame(minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight) + .frame(minWidth: 320, maxWidth: .infinity, minHeight: 180, maxHeight: .infinity) + .aspectRatio(1.777, contentMode: .fit) } - func videoDetail(_ text: String, color: Color? = .primary, bold: Bool = false, lineLimit: Int = 1) -> some View { + func videoDetail(_ text: String, lineLimit: Int = 1) -> some View { Text(text) - .fontWeight(bold ? .bold : .regular) - #if os(tvOS) - .foregroundColor(color) + .fontWeight(.bold) .lineLimit(lineLimit) .truncationMode(.middle) - #elseif os(iOS) || os(macOS) - .foregroundColor(focused ? .white : color) - #endif } } diff --git a/Shared/VideosCellsView.swift b/Shared/VideosCellsView.swift new file mode 100644 index 00000000..c5abb8f5 --- /dev/null +++ b/Shared/VideosCellsView.swift @@ -0,0 +1,65 @@ +import Defaults +import SwiftUI + +struct VideosCellsView: View { + #if os(iOS) + @Environment(\.verticalSizeClass) private var verticalSizeClass + #endif + + var videos = [Video]() + + var body: some View { + ScrollViewReader { scrollView in + ScrollView(.vertical, showsIndicators: scrollViewShowsIndicators) { + LazyVGrid(columns: items, alignment: .center) { + ForEach(videos) { video in + VideoView(video: video, layout: .cells) + .contextMenu { VideoContextMenuView(video: video) } + } + } + .padding() + } + .onChange(of: videos) { [videos] newVideos in + guard !videos.isEmpty, let video = newVideos.first else { + return + } + + scrollView.scrollTo(video.id, anchor: .top) + } + } + } + + var items: [GridItem] { + [GridItem(.adaptive(minimum: adaptiveGridItemMinimumSize))] + } + + var gridColumns: Int { + videos.count < 3 ? videos.count : 3 + } + + var adaptiveGridItemMinimumSize: CGFloat { + #if os(iOS) + return verticalSizeClass == .regular ? 340 : 800 + #elseif os(tvOS) + return 560 + #else + return 340 + #endif + } + + var scrollViewShowsIndicators: Bool { + #if !os(tvOS) + true + #else + false + #endif + } +} + +struct VideoCellsView_Previews: PreviewProvider { + static var previews: some View { + VideosView(videos: Video.allFixtures) + .frame(minWidth: 1000) + .environmentObject(NavigationState()) + } +} diff --git a/Shared/VideosListView.swift b/Shared/VideosListView.swift index 9e46dd80..56736a4c 100644 --- a/Shared/VideosListView.swift +++ b/Shared/VideosListView.swift @@ -10,13 +10,9 @@ struct VideosListView: View { List { ForEach(videos) { video in VideoView(video: video, layout: .list) + .frame(maxHeight: 200) .contextMenu { VideoContextMenuView(video: video) } - #if os(tvOS) - .listRowInsets(listRowInsets) - #elseif os(iOS) - .listRowInsets(EdgeInsets(.zero)) - .listRowSeparator(.hidden) - #endif + .listRowInsets(EdgeInsets()) } .onChange(of: videos) { videos in guard let video = videos.first else { @@ -27,15 +23,9 @@ struct VideosListView: View { } } } - #if os(tvOS) - .listStyle(GroupedListStyle()) - #endif + .listStyle(GroupedListStyle()) } } - - var listRowInsets: EdgeInsets { - EdgeInsets(top: .zero, leading: .zero, bottom: .zero, trailing: 30) - } } struct VideosListView_Previews: PreviewProvider { diff --git a/Shared/VideosView.swift b/Shared/VideosView.swift index f5ad5052..7d5df0c0 100644 --- a/Shared/VideosView.swift +++ b/Shared/VideosView.swift @@ -7,13 +7,7 @@ struct VideosView: View { @State private var profile = Profile() #if os(tvOS) - @Default(.layout) var layout - #endif - - @Default(.showingAddToPlaylist) var showingAddToPlaylist - - #if os(iOS) - @Environment(\.verticalSizeClass) private var horizontalSizeClass + @Default(.layout) private var layout #endif var videos: [Video] @@ -22,28 +16,13 @@ struct VideosView: View { VStack { #if os(tvOS) if layout == .cells { - VideosCellsView(videos: videos, columns: self.profile.cellsColumns) + VideosCellsView(videos: videos) } else { VideosListView(videos: videos) } #else - VideosListView(videos: videos) - #if os(macOS) - .frame(minWidth: 400) - #endif + VideosCellsView(videos: videos) #endif } - - #if os(tvOS) - .fullScreenCover(isPresented: $navigationState.showingVideo) { - if let video = navigationState.video { - VideoPlayerView(video) - } - } - .fullScreenCover(isPresented: $showingAddToPlaylist) { - AddToPlaylistView() - } - - #endif } } diff --git a/Mac/Player.swift b/macOS/Player.swift similarity index 100% rename from Mac/Player.swift rename to macOS/Player.swift diff --git a/Mac/PlayerViewController.swift b/macOS/PlayerViewController.swift similarity index 100% rename from Mac/PlayerViewController.swift rename to macOS/PlayerViewController.swift