Watch Now section, horizontal cells

This commit is contained in:
Arkadiusz Fal 2021-09-18 22:36:42 +02:00
parent 5e403c7f15
commit 8571822f23
21 changed files with 377 additions and 133 deletions

View File

@ -87,6 +87,10 @@ final class InvidiousAPI: Service {
Channel(json: content.json)
}
configureTransformer("/channels/*/latest", requestMethods: [.get]) { (content: Entity<JSON>) -> [Video] in
content.json.arrayValue.map(Video.init)
}
configureTransformer("/videos/*", requestMethods: [.get]) { (content: Entity<JSON>) -> Video in
Video(content.json)
}
@ -120,6 +124,10 @@ final class InvidiousAPI: Service {
resource("/channels/\(id)")
}
func channelVideos(_ id: String) -> Resource {
resource("/channels/\(id)/latest")
}
func video(_ id: String) -> Resource {
resource("/videos/\(id)")
}

View File

@ -3,10 +3,10 @@ import SwiftUI
final class NavigationState: ObservableObject {
enum TabSelection: Hashable {
case subscriptions, popular, trending, playlists, channel(String), playlist(String), search
case watchNow, subscriptions, popular, trending, playlists, channel(String), playlist(String), search
}
@Published var tabSelection: TabSelection = .subscriptions
@Published var tabSelection: TabSelection = .watchNow
@Published var showingVideoDetails = false
@Published var showingVideo = false

View File

@ -6,7 +6,7 @@ final class PlaybackState: ObservableObject {
@Published var stream: Stream?
@Published var time: CMTime?
var aspectRatio: CGFloat? {
var aspectRatio: Double? {
let tracks = stream?.videoAsset.tracks(withMediaType: .video)
guard tracks != nil else {

View File

@ -57,6 +57,12 @@
3748186E26A769D60084E870 /* DetailBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186D26A769D60084E870 /* DetailBadge.swift */; };
3748186F26A769D60084E870 /* DetailBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186D26A769D60084E870 /* DetailBadge.swift */; };
3748187026A769D60084E870 /* DetailBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748186D26A769D60084E870 /* DetailBadge.swift */; };
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
3761ABFE26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
3761AC0F26F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */; };
3761AC1026F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */; };
3761AC1126F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */; };
3763495126DFF59D00B9A393 /* AppSidebarRecentlyOpened.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecentlyOpened.swift */; };
3763495226DFF59D00B9A393 /* AppSidebarRecentlyOpened.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecentlyOpened.swift */; };
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578842685429C00D4EA09 /* CaseIterable+Next.swift */; };
@ -84,6 +90,15 @@
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
377FC7ED267A0A0800A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7EC267A0A0800A6BBAF /* SwiftyJSON */; };
377FC7F3267A0A0800A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7F2267A0A0800A6BBAF /* Logging */; };
3788AC2326F683DE00F6BAA9 /* WatchNowPlaylistSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2226F683DE00F6BAA9 /* WatchNowPlaylistSection.swift */; };
3788AC2426F683DE00F6BAA9 /* WatchNowPlaylistSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2226F683DE00F6BAA9 /* WatchNowPlaylistSection.swift */; };
3788AC2526F683DE00F6BAA9 /* WatchNowPlaylistSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2226F683DE00F6BAA9 /* WatchNowPlaylistSection.swift */; };
3788AC2726F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
3788AC2826F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
3788AC2926F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
3788AC2B26F6842D00F6BAA9 /* WatchNowSectionBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2A26F6842D00F6BAA9 /* WatchNowSectionBody.swift */; };
3788AC2C26F6842D00F6BAA9 /* WatchNowSectionBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2A26F6842D00F6BAA9 /* WatchNowSectionBody.swift */; };
3788AC2D26F6842D00F6BAA9 /* WatchNowSectionBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2A26F6842D00F6BAA9 /* WatchNowSectionBody.swift */; };
3797757D268922D100DD52A8 /* Siesta in Frameworks */ = {isa = PBXBuildFile; productRef = 3797757C268922D100DD52A8 /* Siesta */; };
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37977582268922F600DD52A8 /* InvidiousAPI.swift */; };
37977584268922F600DD52A8 /* InvidiousAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37977582268922F600DD52A8 /* InvidiousAPI.swift */; };
@ -94,12 +109,12 @@
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 */; };
379DDFEE26DEDB0E00EA08E7 /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DDFED26DEDB0E00EA08E7 /* EnvironmentValues.swift */; };
379DDFEF26DEDB0E00EA08E7 /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DDFED26DEDB0E00EA08E7 /* EnvironmentValues.swift */; };
379DDFF026DEDB0E00EA08E7 /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DDFED26DEDB0E00EA08E7 /* EnvironmentValues.swift */; };
379DDFF326DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DDFF226DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift */; };
379DDFF426DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DDFF226DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift */; };
379DDFF526DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DDFF226DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift */; };
37A9965A26D6F8CA006E3224 /* VideosCellsHorizontal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965926D6F8CA006E3224 /* VideosCellsHorizontal.swift */; };
37A9965B26D6F8CA006E3224 /* VideosCellsHorizontal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965926D6F8CA006E3224 /* VideosCellsHorizontal.swift */; };
37A9965C26D6F8CA006E3224 /* VideosCellsHorizontal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965926D6F8CA006E3224 /* VideosCellsHorizontal.swift */; };
37A9965E26D6F9B9006E3224 /* WatchNowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965D26D6F9B9006E3224 /* WatchNowView.swift */; };
37A9965F26D6F9B9006E3224 /* WatchNowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965D26D6F9B9006E3224 /* WatchNowView.swift */; };
37A9966026D6F9B9006E3224 /* WatchNowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A9965D26D6F9B9006E3224 /* WatchNowView.swift */; };
37AAF27E26737323007FC770 /* PopularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27D26737323007FC770 /* PopularView.swift */; };
37AAF28026737550007FC770 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
37AAF29026740715007FC770 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF28F26740715007FC770 /* Channel.swift */; };
@ -139,7 +154,6 @@
37BA794526DBA973002A0235 /* Playlists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794226DBA973002A0235 /* Playlists.swift */; };
37BA794726DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794626DC2E56002A0235 /* AppSidebarSubscriptions.swift */; };
37BA794826DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794626DC2E56002A0235 /* AppSidebarSubscriptions.swift */; };
37BA794B26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794A26DC30EC002A0235 /* AppSidebarPlaylists.swift */; };
37BA794C26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794A26DC30EC002A0235 /* AppSidebarPlaylists.swift */; };
37BA794F26DC3E0E002A0235 /* Int+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794E26DC3E0E002A0235 /* Int+Format.swift */; };
37BA795026DC3E0E002A0235 /* Int+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794E26DC3E0E002A0235 /* Int+Format.swift */; };
@ -162,6 +176,7 @@
37BD07C72698B27B003EBB87 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07C62698B27B003EBB87 /* Introspect */; };
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07B42698AA4D003EBB87 /* ContentView.swift */; };
37BD672426F13D65004BE0C1 /* AppSidebarPlaylists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794A26DC30EC002A0235 /* AppSidebarPlaylists.swift */; };
37BE0BCF26A0E2D50092E2DB /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */; };
37BE0BD026A0E2D50092E2DB /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */; };
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */; };
@ -213,9 +228,9 @@
37F49BA426CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F49BA226CAA59B00304AC0 /* Playlist+Fixtures.swift */; };
37F49BA526CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F49BA226CAA59B00304AC0 /* Playlist+Fixtures.swift */; };
37F49BA826CB0FCE00304AC0 /* PlaylistFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373CFAEA26975CBF003CB2C6 /* PlaylistFormView.swift */; };
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 */; };
37F4AE7226828F0900BD60EA /* VideosCellsVertical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsVertical.swift */; };
37F4AE7326828F0900BD60EA /* VideosCellsVertical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsVertical.swift */; };
37F4AE7426828F0900BD60EA /* VideosCellsVertical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F4AE7126828F0900BD60EA /* VideosCellsVertical.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -268,18 +283,23 @@
3748186526A7627F0084E870 /* Video+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Video+Fixtures.swift"; sourceTree = "<group>"; };
3748186926A764FB0084E870 /* Thumbnail+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thumbnail+Fixtures.swift"; sourceTree = "<group>"; };
3748186D26A769D60084E870 /* DetailBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBadge.swift; sourceTree = "<group>"; };
3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentValues.swift; sourceTree = "<group>"; };
3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnsubscribeAlertModifier.swift; sourceTree = "<group>"; };
3763495026DFF59D00B9A393 /* AppSidebarRecentlyOpened.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarRecentlyOpened.swift; sourceTree = "<group>"; };
376578842685429C00D4EA09 /* CaseIterable+Next.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CaseIterable+Next.swift"; sourceTree = "<group>"; };
376578882685471400D4EA09 /* Playlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Playlist.swift; sourceTree = "<group>"; };
376578902685490700D4EA09 /* PlaylistsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistsView.swift; sourceTree = "<group>"; };
37754C9C26B7500000DBD602 /* VideosView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideosView.swift; sourceTree = "<group>"; };
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = "<group>"; };
3788AC2226F683DE00F6BAA9 /* WatchNowPlaylistSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowPlaylistSection.swift; sourceTree = "<group>"; };
3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowSection.swift; sourceTree = "<group>"; };
3788AC2A26F6842D00F6BAA9 /* WatchNowSectionBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowSectionBody.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>"; };
379775922689365600DD52A8 /* Array+Next.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Next.swift"; sourceTree = "<group>"; };
37992DC726CC50BC003D4C27 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
379DDFED26DEDB0E00EA08E7 /* EnvironmentValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentValues.swift; sourceTree = "<group>"; };
379DDFF226DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsubscribeAlertModifier.swift; sourceTree = "<group>"; };
37A9965926D6F8CA006E3224 /* VideosCellsHorizontal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosCellsHorizontal.swift; sourceTree = "<group>"; };
37A9965D26D6F9B9006E3224 /* WatchNowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowView.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>"; };
37AAF28F26740715007FC770 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
@ -335,7 +355,7 @@
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>"; };
37F49BA226CAA59B00304AC0 /* Playlist+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Playlist+Fixtures.swift"; sourceTree = "<group>"; };
37F4AE7126828F0900BD60EA /* VideosCellsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosCellsView.swift; sourceTree = "<group>"; };
37F4AE7126828F0900BD60EA /* VideosCellsVertical.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosCellsVertical.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -458,7 +478,8 @@
isa = PBXGroup;
children = (
3748186D26A769D60084E870 /* DetailBadge.swift */,
37F4AE7126828F0900BD60EA /* VideosCellsView.swift */,
37A9965926D6F8CA006E3224 /* VideosCellsHorizontal.swift */,
37F4AE7126828F0900BD60EA /* VideosCellsVertical.swift */,
37AAF29926740A01007FC770 /* VideosListView.swift */,
37754C9C26B7500000DBD602 /* VideosView.swift */,
37D4B18B26717B3800C925CA /* VideoView.swift */,
@ -499,6 +520,14 @@
path = Fixtures;
sourceTree = "<group>";
};
3761AC0526F0F96100AA496F /* Modifiers */ = {
isa = PBXGroup;
children = (
3761AC0E26F0F9A600AA496F /* UnsubscribeAlertModifier.swift */,
);
path = Modifiers;
sourceTree = "<group>";
};
377FC7D1267A080300A6BBAF /* Frameworks */ = {
isa = PBXGroup;
children = (
@ -506,6 +535,17 @@
name = Frameworks;
sourceTree = "<group>";
};
3788AC2126F683AB00F6BAA9 /* Watch Now */ = {
isa = PBXGroup;
children = (
3788AC2226F683DE00F6BAA9 /* WatchNowPlaylistSection.swift */,
3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */,
3788AC2A26F6842D00F6BAA9 /* WatchNowSectionBody.swift */,
37A9965D26D6F9B9006E3224 /* WatchNowView.swift */,
);
path = "Watch Now";
sourceTree = "<group>";
};
37992DC826CC50CD003D4C27 /* iOS */ = {
isa = PBXGroup;
children = (
@ -514,14 +554,6 @@
path = iOS;
sourceTree = "<group>";
};
379DDFF126DEE2A800EA08E7 /* Modifiers */ = {
isa = PBXGroup;
children = (
379DDFF226DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift */,
);
path = Modifiers;
sourceTree = "<group>";
};
37BA796426DC40CB002A0235 /* Shared Tests */ = {
isa = PBXGroup;
children = (
@ -580,15 +612,16 @@
37D4B0C12671614700C925CA /* Shared */ = {
isa = PBXGroup;
children = (
3761AC0526F0F96100AA496F /* Modifiers */,
371AAE2326CEB9E800901972 /* Navigation */,
371AAE2426CEBA4100901972 /* Player */,
371AAE2626CEBF1600901972 /* Playlists */,
371AAE2526CEBF0B00901972 /* Trending */,
371AAE2726CEBF4700901972 /* Videos */,
371AAE2826CEC7D900901972 /* Views */,
379DDFF126DEE2A800EA08E7 /* Modifiers */,
3788AC2126F683AB00F6BAA9 /* Watch Now */,
372915E52687E3B900F5A35B /* Defaults.swift */,
379DDFED26DEDB0E00EA08E7 /* EnvironmentValues.swift */,
3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */,
37D4B0C22671614700C925CA /* PearvidiousApp.swift */,
37D4B0C42671614800C925CA /* Assets.xcassets */,
37BD07C42698ADEE003EBB87 /* Pearvidious.entitlements */,
@ -969,6 +1002,7 @@
37BA793B26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */,
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
37152EEA26EFEB95004FB96D /* LazyView.swift in Sources */,
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
37C7A1DA267CACF50010EAD6 /* TrendingCountry.swift in Sources */,
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
@ -977,8 +1011,9 @@
3711403F26B206A6005B3555 /* SearchState.swift in Sources */,
37B81AF926D2C9A700675966 /* VideoPlayerSizeModifier.swift in Sources */,
37BE0BD326A1D4780092E2DB /* Player.swift in Sources */,
37A9965E26D6F9B9006E3224 /* WatchNowView.swift in Sources */,
37CEE4C12677B697005A1EFE /* Stream.swift in Sources */,
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */,
37F4AE7226828F0900BD60EA /* VideosCellsVertical.swift in Sources */,
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
37BA794726DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */,
@ -990,26 +1025,30 @@
37B81B0526D2CEDA00675966 /* PlaybackState.swift in Sources */,
373CFADB269663F1003CB2C6 /* Thumbnail.swift in Sources */,
37C7A1DC267CE9D90010EAD6 /* Profile.swift in Sources */,
3788AC2B26F6842D00F6BAA9 /* WatchNowSectionBody.swift in Sources */,
373CFAC026966149003CB2C6 /* CoverSectionView.swift in Sources */,
379DDFF326DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift in Sources */,
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
377FC7E3267A084A00A6BBAF /* VideoView.swift in Sources */,
37BA794326DBA973002A0235 /* Playlists.swift in Sources */,
37AAF29026740715007FC770 /* Channel.swift in Sources */,
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
3761AC0F26F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */,
3788AC2326F683DE00F6BAA9 /* WatchNowPlaylistSection.swift in Sources */,
37B81AFF26D2CA3700675966 /* VideoDetails.swift in Sources */,
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */,
376578912685490700D4EA09 /* PlaylistsView.swift in Sources */,
377A20A92693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
37BD672426F13D65004BE0C1 /* AppSidebarPlaylists.swift in Sources */,
37B17DA2268A1F8A006AEE9B /* VideoContextMenuView.swift in Sources */,
379775932689365600DD52A8 /* Array+Next.swift in Sources */,
37B81AFC26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
37BA794F26DC3E0E002A0235 /* Int+Format.swift in Sources */,
37F49BA326CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
37BA794B26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */,
37A9965A26D6F8CA006E3224 /* VideosCellsHorizontal.swift in Sources */,
37B767DB2677C3CA0098BAA8 /* PlayerState.swift in Sources */,
3788AC2726F6840700F6BAA9 /* WatchNowSection.swift in Sources */,
373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
373CFAC226966159003CB2C6 /* CoverSectionRowView.swift in Sources */,
37141673267A8E10006CA35D /* Country.swift in Sources */,
@ -1020,7 +1059,6 @@
372915E62687E3B900F5A35B /* Defaults.swift in Sources */,
37D4B19726717E1500C925CA /* Video.swift in Sources */,
371F2F1A269B43D300E4A7AB /* NavigationState.swift in Sources */,
379DDFEE26DEDB0E00EA08E7 /* EnvironmentValues.swift in Sources */,
37BE0BCF26A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
37BD07BB2698AB60003EBB87 /* AppSidebarNavigation.swift in Sources */,
37D4B0E42671614900C925CA /* PearvidiousApp.swift in Sources */,
@ -1033,19 +1071,23 @@
buildActionMask = 2147483647;
files = (
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
3788AC2C26F6842D00F6BAA9 /* WatchNowSectionBody.swift in Sources */,
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
373CFABF26966149003CB2C6 /* CoverSectionView.swift in Sources */,
37BA794826DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */,
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
371F2F1B269B43D300E4A7AB /* NavigationState.swift in Sources */,
3761ABFE26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
37BA795026DC3E0E002A0235 /* Int+Format.swift in Sources */,
377FC7DD267A081A00A6BBAF /* PopularView.swift in Sources */,
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */,
37B81B0026D2CA3700675966 /* VideoDetails.swift in Sources */,
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
37F49BA426CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
3788AC2426F683DE00F6BAA9 /* WatchNowPlaylistSection.swift in Sources */,
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
3788AC2826F6840700F6BAA9 /* WatchNowSection.swift in Sources */,
37BA793C26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */,
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
37152EEB26EFEB95004FB96D /* LazyView.swift in Sources */,
@ -1064,9 +1106,11 @@
377A20AA2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
37B81B0326D2CAE700675966 /* PlaybackBar.swift in Sources */,
376578862685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
37F4AE7326828F0900BD60EA /* VideosCellsView.swift in Sources */,
37A9965F26D6F9B9006E3224 /* WatchNowView.swift in Sources */,
37F4AE7326828F0900BD60EA /* VideosCellsVertical.swift in Sources */,
37B81AFD26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
379DDFEF26DEDB0E00EA08E7 /* EnvironmentValues.swift in Sources */,
37A9965B26D6F8CA006E3224 /* VideosCellsHorizontal.swift in Sources */,
3761AC1026F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */,
379775942689365600DD52A8 /* Array+Next.swift in Sources */,
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */,
37BE0BDA26A214630092E2DB /* PlayerViewController.swift in Sources */,
@ -1082,7 +1126,6 @@
37D4B19826717E1500C925CA /* Video.swift in Sources */,
37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */,
37BD07C12698AD3B003EBB87 /* TrendingCountry.swift in Sources */,
379DDFF426DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift in Sources */,
37BA794026DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
3711404026B206A6005B3555 /* SearchState.swift in Sources */,
37BE0BD026A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
@ -1119,22 +1162,24 @@
files = (
37754C9F26B7500000DBD602 /* VideosView.swift in Sources */,
37AAF28026737550007FC770 /* SearchView.swift in Sources */,
3788AC2D26F6842D00F6BAA9 /* WatchNowSectionBody.swift in Sources */,
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
37F49BA526CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
37CEE4BF2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
37BE0BD426A1D47D0092E2DB /* Player.swift in Sources */,
37977585268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */,
37F4AE7426828F0900BD60EA /* VideosCellsVertical.swift in Sources */,
376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */,
3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
373CFAC926966188003CB2C6 /* SearchOptionsView.swift in Sources */,
37A9965C26D6F8CA006E3224 /* VideosCellsHorizontal.swift in Sources */,
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */,
37B17DA6268A285E006AEE9B /* VideoDetailsView.swift in Sources */,
37141671267A8ACC006CA35D /* TrendingView.swift in Sources */,
3788AC2926F6840700F6BAA9 /* WatchNowSection.swift in Sources */,
37BA794126DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
37AAF29226740715007FC770 /* Channel.swift in Sources */,
379DDFF526DEE2BA00EA08E7 /* UnsubscribeAlertModifier.swift in Sources */,
37EAD86D267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
37B81B0726D2D6CF00675966 /* PlaybackState.swift in Sources */,
3765788B2685471400D4EA09 /* Playlist.swift in Sources */,
@ -1144,9 +1189,11 @@
373CFABE26966148003CB2C6 /* CoverSectionView.swift in Sources */,
37B767DD2677C3CA0098BAA8 /* PlayerState.swift in Sources */,
373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
3761AC1126F0F9A600AA496F /* UnsubscribeAlertModifier.swift in Sources */,
37D4B18E26717B3800C925CA /* VideoView.swift in Sources */,
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
37AAF27E26737323007FC770 /* PopularView.swift in Sources */,
37A9966026D6F9B9006E3224 /* WatchNowView.swift in Sources */,
37AAF29A26740A01007FC770 /* VideosListView.swift in Sources */,
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
376578932685490700D4EA09 /* PlaylistsView.swift in Sources */,
@ -1163,7 +1210,6 @@
37BA793D26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */,
3711404126B206A6005B3555 /* SearchState.swift in Sources */,
379775952689365600DD52A8 /* Array+Next.swift in Sources */,
379DDFF026DEDB0E00EA08E7 /* EnvironmentValues.swift in Sources */,
3705B180267B4DFB00704544 /* TrendingCountry.swift in Sources */,
373CFACD26966264003CB2C6 /* SearchQuery.swift in Sources */,
37141675267A8E10006CA35D /* Country.swift in Sources */,
@ -1172,6 +1218,8 @@
373CFAC42696616C003CB2C6 /* CoverSectionRowView.swift in Sources */,
37D4B19926717E1500C925CA /* Video.swift in Sources */,
3705B184267B4E4900704544 /* TrendingCategory.swift in Sources */,
3788AC2526F683DE00F6BAA9 /* WatchNowPlaylistSection.swift in Sources */,
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
37AAF2A226741C97007FC770 /* SubscriptionsView.swift in Sources */,
372915E82687E3B900F5A35B /* Defaults.swift in Sources */,
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */,

View File

@ -5,9 +5,18 @@ private struct InNavigationViewKey: EnvironmentKey {
static let defaultValue = false
}
private struct HorizontalCellsKey: EnvironmentKey {
static let defaultValue = false
}
extension EnvironmentValues {
var inNavigationView: Bool {
get { self[InNavigationViewKey.self] }
set { self[InNavigationViewKey.self] = newValue }
}
var horizontalCells: Bool {
get { self[HorizontalCellsKey.self] }
set { self[HorizontalCellsKey.self] = newValue }
}
}

View File

@ -121,6 +121,14 @@ struct AppSidebarNavigation: View {
var mainNavigationLinks: some View {
Section("Videos") {
NavigationLink(tag: TabSelection.watchNow, selection: selection) {
WatchNowView()
}
label: {
Label("Watch Now", systemImage: "play.circle")
.accessibility(label: Text("Watch Now"))
}
NavigationLink(destination: LazyView(SubscriptionsView()), tag: TabSelection.subscriptions, selection: selection) {
Label("Subscriptions", systemImage: "star.circle.fill")
.accessibility(label: Text("Subscriptions"))

View File

@ -9,6 +9,15 @@ struct AppTabNavigation: View {
var body: some View {
TabView(selection: $navigationState.tabSelection) {
NavigationView {
WatchNowView()
}
.tabItem {
Label("Watch Now", systemImage: "play.circle")
.accessibility(label: Text("Subscriptions"))
}
.tag(TabSelection.watchNow)
NavigationView {
SubscriptionsView()
}
@ -18,14 +27,16 @@ struct AppTabNavigation: View {
}
.tag(TabSelection.subscriptions)
NavigationView {
PopularView()
}
.tabItem {
Label("Popular", systemImage: "chart.bar")
.accessibility(label: Text("Popular"))
}
.tag(TabSelection.popular)
// TODO: reenable with settings
// ============================
// NavigationView {
// PopularView()
// }
// .tabItem {
// Label("Popular", systemImage: "chart.bar")
// .accessibility(label: Text("Popular"))
// }
// .tag(TabSelection.popular)
NavigationView {
TrendingView()

View File

@ -64,7 +64,7 @@ struct PlaybackBar: View {
var closeButton: some View {
Button(action: { dismiss() }) {
Image(systemName: "chevron.down.circle.fill")
Image(systemName: "xmark.circle.fill")
}
.accessibilityLabel(Text("Close"))
.buttonStyle(.borderless)

View File

@ -3,15 +3,15 @@ import SwiftUI
struct VideoDetailsPaddingModifier: ViewModifier {
let geometry: GeometryProxy
let aspectRatio: CGFloat?
let minimumHeightLeft: CGFloat
let additionalPadding: CGFloat
let aspectRatio: Double?
let minimumHeightLeft: Double
let additionalPadding: Double
init(
geometry: GeometryProxy,
aspectRatio: CGFloat? = nil,
minimumHeightLeft: CGFloat? = nil,
additionalPadding: CGFloat = 35.00
aspectRatio: Double? = nil,
minimumHeightLeft: Double? = nil,
additionalPadding: Double = 35.00
) {
self.geometry = geometry
self.aspectRatio = aspectRatio ?? VideoPlayerView.defaultAspectRatio
@ -19,7 +19,7 @@ struct VideoDetailsPaddingModifier: ViewModifier {
self.additionalPadding = additionalPadding
}
var usedAspectRatio: CGFloat {
var usedAspectRatio: Double {
guard aspectRatio != nil else {
return VideoPlayerView.defaultAspectRatio
}
@ -27,11 +27,11 @@ struct VideoDetailsPaddingModifier: ViewModifier {
return [aspectRatio!, VideoPlayerView.defaultAspectRatio].min()!
}
var playerHeight: CGFloat {
var playerHeight: Double {
[geometry.size.width / usedAspectRatio, geometry.size.height - minimumHeightLeft].min()!
}
var topPadding: CGFloat {
var topPadding: Double {
playerHeight + additionalPadding
}

View File

@ -3,8 +3,8 @@ import SwiftUI
struct VideoPlayerSizeModifier: ViewModifier {
let geometry: GeometryProxy
let aspectRatio: CGFloat?
let minimumHeightLeft: CGFloat
let aspectRatio: Double?
let minimumHeightLeft: Double
#if os(iOS)
@Environment(\.verticalSizeClass) private var verticalSizeClass
@ -12,8 +12,8 @@ struct VideoPlayerSizeModifier: ViewModifier {
init(
geometry: GeometryProxy,
aspectRatio: CGFloat? = nil,
minimumHeightLeft: CGFloat? = nil
aspectRatio: Double? = nil,
minimumHeightLeft: Double? = nil
) {
self.geometry = geometry
self.aspectRatio = aspectRatio ?? VideoPlayerView.defaultAspectRatio
@ -27,7 +27,7 @@ struct VideoPlayerSizeModifier: ViewModifier {
.edgesIgnoringSafeArea(edgesIgnoringSafeArea)
}
var usedAspectRatio: CGFloat {
var usedAspectRatio: Double {
guard aspectRatio != nil else {
return VideoPlayerView.defaultAspectRatio
}
@ -50,7 +50,7 @@ struct VideoPlayerSizeModifier: ViewModifier {
#endif
}
var maxHeight: CGFloat {
var maxHeight: Double {
#if os(iOS)
verticalSizeClass == .regular ? geometry.size.height - minimumHeightLeft : .infinity
#else

View File

@ -3,8 +3,8 @@ import Siesta
import SwiftUI
struct VideoPlayerView: View {
static let defaultAspectRatio: CGFloat = 1.77777778
static var defaultMinimumHeightLeft: CGFloat {
static let defaultAspectRatio: Double = 1.77777778
static var defaultMinimumHeightLeft: Double {
#if os(macOS)
300
#else

View File

@ -25,7 +25,7 @@ struct PlaylistsView: View {
currentPlaylist?.videos ?? []
}
var videosViewMaxHeight: CGFloat {
var videosViewMaxHeight: Double {
#if os(tvOS)
videos.isEmpty ? 150 : .infinity
#else

View File

@ -9,6 +9,7 @@ struct VideoView: View {
#endif
@Environment(\.inNavigationView) private var inNavigationView
@Environment(\.horizontalCells) private var horizontalCells
var video: Video
var layout: ListingLayout
@ -34,7 +35,7 @@ struct VideoView: View {
VStack {
if layout == .cells {
#if os(iOS)
if verticalSizeClass == .compact {
if verticalSizeClass == .compact, !horizontalCells {
horizontalRow
.padding(.vertical, 4)
} else {
@ -64,14 +65,31 @@ struct VideoView: View {
.frame(maxWidth: 320)
VStack(alignment: .leading, spacing: 0) {
videoDetail(video.title)
videoDetail(video.title, lineLimit: 5)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
videoDetail(video.author)
if additionalDetailsAvailable {
Spacer()
additionalDetails
HStack {
if let date = video.publishedDate {
VStack {
Image(systemName: "calendar")
Text(date)
}
}
if video.views != 0 {
VStack {
Image(systemName: "eye")
Text(video.viewsCount!)
}
}
}
.foregroundColor(.secondary)
}
}
.padding()
.frame(minHeight: 180)
@ -101,11 +119,10 @@ struct VideoView: View {
}
#endif
}
.padding(.trailing)
}
var verticalRow: some View {
VStack(alignment: .leading) {
VStack(alignment: .leading, spacing: 0) {
thumbnail
VStack(alignment: .leading) {
@ -121,25 +138,6 @@ struct VideoView: View {
Group {
if additionalDetailsAvailable {
additionalDetails
} else {
Spacer()
}
}
.frame(minHeight: 30, alignment: .top)
.padding(.bottom, 10)
}
#if os(tvOS)
.padding(.horizontal, 8)
#endif
}
}
var additionalDetailsAvailable: Bool {
video.publishedDate != nil || video.views != 0
}
var additionalDetails: some View {
HStack(spacing: 8) {
if let date = video.publishedDate {
Image(systemName: "calendar")
@ -152,6 +150,23 @@ struct VideoView: View {
}
}
.foregroundColor(.secondary)
} else {
Spacer()
}
}
.frame(minHeight: 30, alignment: .top)
.padding(.bottom, 10)
}
.padding(.top, 4)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .topLeading)
#if os(tvOS)
.padding(.horizontal, 8)
#endif
}
}
var additionalDetailsAvailable: Bool {
video.publishedDate != nil || video.views != 0
}
var thumbnail: some View {
@ -184,8 +199,6 @@ struct VideoView: View {
.padding(10)
}
}
.padding([.leading, .top, .trailing], 4)
.frame(maxWidth: 600)
}
func thumbnailImage(quality: Thumbnail.Quality) -> some View {
@ -196,19 +209,17 @@ struct VideoView: View {
.resizable()
} placeholder: {
ProgressView()
.aspectRatio(contentMode: .fill)
}
} else {
Image(systemName: "exclamationmark.square")
}
}
.frame(minWidth: 300, maxWidth: .infinity, minHeight: 180, maxHeight: .infinity)
.background(.gray)
.mask(RoundedRectangle(cornerRadius: 12))
#if os(tvOS)
.frame(minHeight: layout == .cells ? 320 : 200)
#endif
.aspectRatio(1.777, contentMode: .fit)
.modifier(AspectRatioModifier())
}
func videoDetail(_ text: String, lineLimit: Int = 1) -> some View {
@ -218,6 +229,21 @@ struct VideoView: View {
.truncationMode(.middle)
}
struct AspectRatioModifier: ViewModifier {
@Environment(\.horizontalCells) private var horizontalCells
func body(content: Content) -> some View {
Group {
if horizontalCells {
content
} else {
content
.aspectRatio(1.777, contentMode: .fill)
}
}
}
}
struct ButtonStyleModifier: ViewModifier {
var layout: ListingLayout
@ -236,41 +262,3 @@ struct VideoView: View {
}
}
}
struct VideoListRowPreview: PreviewProvider {
static var previews: some View {
#if os(tvOS)
List {
ForEach(Video.allFixtures) { video in
VideoView(video: video, layout: .list)
}
}
.listStyle(.grouped)
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
}
}

View File

@ -0,0 +1,61 @@
import Defaults
import SwiftUI
struct VideosCellsHorizontal: View {
#if os(iOS)
@Environment(\.verticalSizeClass) private var verticalSizeClass
#endif
var videos = [Video]()
var body: some View {
ScrollViewReader { scrollView in
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(spacing: 20) {
ForEach(videos) { video in
VideoView(video: video, layout: .cells)
.environment(\.horizontalCells, true)
#if os(tvOS)
.frame(width: 580)
.padding(.trailing, 20)
.padding(.bottom, 40)
#else
.frame(maxWidth: 300)
#endif
}
}
#if os(tvOS)
.padding(.horizontal, 40)
.padding(.vertical, 30)
#else
.padding(.horizontal, 15)
.padding(.vertical, 20)
#endif
}
.onChange(of: videos) { [videos] newVideos in
#if !os(tvOS)
guard !videos.isEmpty, let video = newVideos.first else {
return
}
scrollView.scrollTo(video.id, anchor: .leading)
#endif
}
}
#if os(tvOS)
.frame(height: 560)
#else
.frame(height: 320)
#endif
.edgesIgnoringSafeArea(.horizontal)
}
}
struct VideoCellsHorizontal_Previews: PreviewProvider {
static var previews: some View {
VideosCellsHorizontal(videos: Video.allFixtures)
.environmentObject(NavigationState())
.environmentObject(Subscriptions())
}
}

View File

@ -1,7 +1,7 @@
import Defaults
import SwiftUI
struct VideosCellsView: View {
struct VideosCellsVertical: View {
#if os(iOS)
@Environment(\.verticalSizeClass) private var verticalSizeClass
#endif
@ -49,7 +49,7 @@ struct VideosCellsView: View {
[GridItem(.adaptive(minimum: adaptiveGridItemMinimumSize))]
}
var adaptiveGridItemMinimumSize: CGFloat {
var adaptiveGridItemMinimumSize: Double {
#if os(iOS)
return verticalSizeClass == .regular ? 320 : 800
#elseif os(tvOS)

View File

@ -14,12 +14,12 @@ struct VideosView: View {
VStack {
#if os(tvOS)
if layout == .cells {
VideosCellsView(videos: videos)
VideosCellsVertical(videos: videos)
} else {
VideosListView(videos: videos)
}
#else
VideosCellsView(videos: videos)
VideosCellsVertical(videos: videos)
#endif
}
#if os(macOS)

View File

@ -0,0 +1,25 @@
import Siesta
import SwiftUI
struct WatchNowPlaylistSection: View {
@ObservedObject private var store = Store<Playlist>()
let id: String
var resource: Resource {
InvidiousAPI.shared.playlist(id)
}
init(id: String) {
self.id = id
resource.addObserver(store)
}
var body: some View {
WatchNowSectionBody(label: store.item?.title ?? "Loading", videos: store.item?.videos ?? [])
.onAppear {
resource.loadIfNeeded()
}
}
}

View File

@ -0,0 +1,23 @@
import Siesta
import SwiftUI
struct WatchNowSection: View {
@ObservedObject private var store = Store<[Video]>()
let resource: Resource
let label: String
init(resource: Resource, label: String) {
self.resource = resource
self.label = label
self.resource.addObserver(store)
}
var body: some View {
WatchNowSectionBody(label: label, videos: store.collection)
.onAppear {
resource.loadIfNeeded()
}
}
}

View File

@ -0,0 +1,21 @@
import SwiftUI
struct WatchNowSectionBody: View {
let label: String
let videos: [Video]
var body: some View {
VStack(alignment: .leading, spacing: 2) {
Text(label)
.font(.title3.bold())
.foregroundColor(.secondary)
#if os(tvOS)
.padding(.leading, 40)
#else
.padding(.leading, 15)
#endif
VideosCellsHorizontal(videos: videos)
}
}
}

View File

@ -0,0 +1,38 @@
import Siesta
import SwiftUI
struct WatchNowView: View {
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading, spacing: 0) {
WatchNowSection(resource: InvidiousAPI.shared.feed, label: "Subscriptions")
WatchNowSection(resource: InvidiousAPI.shared.popular, label: "Popular")
WatchNowSection(resource: InvidiousAPI.shared.trending(category: .default, country: .pl), label: "Trending")
WatchNowSection(resource: InvidiousAPI.shared.trending(category: .movies, country: .pl), label: "Movies")
WatchNowSection(resource: InvidiousAPI.shared.trending(category: .music, country: .pl), label: "Music")
// TODO: adding sections to view
// ===================
// WatchNowPlaylistSection(id: "IVPLmRFYLGYZpq61SpujNw3EKbzzGNvoDmH")
// WatchNowSection(resource: InvidiousAPI.shared.channelVideos("UCBJycsmduvYEL83R_U4JriQ"), label: "MKBHD")
}
}
#if os(tvOS)
.edgesIgnoringSafeArea(.horizontal)
#else
.navigationTitle("Watch Now")
#endif
#if os(macOS)
.background()
.frame(minWidth: 360)
#endif
}
}
struct WatchNowView_Previews: PreviewProvider {
static var previews: some View {
WatchNowView()
.environmentObject(Subscriptions())
.environmentObject(NavigationState())
}
}

View File

@ -12,6 +12,10 @@ struct TVNavigationView: View {
var body: some View {
TabView(selection: $navigationState.tabSelection) {
WatchNowView()
.tabItem { Text("Watch Now") }
.tag(TabSelection.watchNow)
SubscriptionsView()
.tabItem { Text("Subscriptions") }
.tag(TabSelection.subscriptions)