mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Playlists and channels in the sidebar
This commit is contained in:
parent
1196a2a5e2
commit
1651110a5d
@ -3,7 +3,7 @@ import Defaults
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
|
||||||
struct Channel: Codable, Defaults.Serializable {
|
struct Channel: Codable, Identifiable, Defaults.Serializable {
|
||||||
var id: String
|
var id: String
|
||||||
var name: String
|
var name: String
|
||||||
var subscriptionsCount: String
|
var subscriptionsCount: String
|
||||||
|
@ -54,6 +54,10 @@ final class InvidiousAPI: Service {
|
|||||||
content.json.arrayValue.map(Playlist.init)
|
content.json.arrayValue.map(Playlist.init)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configureTransformer("/auth/playlists/*", requestMethods: [.get]) { (content: Entity<JSON>) -> Playlist in
|
||||||
|
Playlist(content.json)
|
||||||
|
}
|
||||||
|
|
||||||
configureTransformer("/auth/playlists", requestMethods: [.post, .patch]) { (content: Entity<Data>) -> Playlist in
|
configureTransformer("/auth/playlists", requestMethods: [.post, .patch]) { (content: Entity<Data>) -> Playlist in
|
||||||
// hacky, to verify if possible to get it in easier way
|
// hacky, to verify if possible to get it in easier way
|
||||||
Playlist(JSON(parseJSON: String(data: content.content, encoding: .utf8)!))
|
Playlist(JSON(parseJSON: String(data: content.content, encoding: .utf8)!))
|
||||||
|
@ -2,6 +2,10 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class NavigationState: ObservableObject {
|
final class NavigationState: ObservableObject {
|
||||||
|
enum TabSelection: Hashable {
|
||||||
|
case subscriptions, popular, trending, playlists, channel(String), playlist(String), search
|
||||||
|
}
|
||||||
|
|
||||||
@Published var tabSelection: TabSelection = .subscriptions
|
@Published var tabSelection: TabSelection = .subscriptions
|
||||||
|
|
||||||
@Published var showingChannel = false
|
@Published var showingChannel = false
|
||||||
@ -13,6 +17,12 @@ final class NavigationState: ObservableObject {
|
|||||||
|
|
||||||
@Published var returnToDetails = false
|
@Published var returnToDetails = false
|
||||||
|
|
||||||
|
@Published var presentingPlaylistForm = false
|
||||||
|
@Published var editedPlaylist: Playlist!
|
||||||
|
|
||||||
|
@Published var presentingUnsubscribeAlert = false
|
||||||
|
@Published var channelToUnsubscribe: Channel!
|
||||||
|
|
||||||
func openChannel(_ channel: Channel) {
|
func openChannel(_ channel: Channel) {
|
||||||
returnToDetails = false
|
returnToDetails = false
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
@ -54,4 +64,21 @@ final class NavigationState: ObservableObject {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func presentEditPlaylistForm(_ playlist: Playlist?) {
|
||||||
|
editedPlaylist = playlist
|
||||||
|
presentingPlaylistForm = editedPlaylist != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func presentNewPlaylistForm() {
|
||||||
|
editedPlaylist = nil
|
||||||
|
presentingPlaylistForm = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func presentUnsubscribeAlert(_ channel: Channel?) {
|
||||||
|
channelToUnsubscribe = channel
|
||||||
|
presentingUnsubscribeAlert = channelToUnsubscribe != nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typealias TabSelection = NavigationState.TabSelection
|
||||||
|
35
Model/Playlists.swift
Normal file
35
Model/Playlists.swift
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import Foundation
|
||||||
|
import Siesta
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
final class Playlists: ObservableObject {
|
||||||
|
@Published var playlists = [Playlist]()
|
||||||
|
|
||||||
|
var resource: Resource {
|
||||||
|
InvidiousAPI.shared.playlists
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
|
||||||
|
var all: [Playlist] {
|
||||||
|
playlists.sorted { $0.title.lowercased() < $1.title.lowercased() }
|
||||||
|
}
|
||||||
|
|
||||||
|
func find(id: Playlist.ID) -> Playlist? {
|
||||||
|
all.first { $0.id == id }
|
||||||
|
}
|
||||||
|
|
||||||
|
func reload() {
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func load() {
|
||||||
|
resource.load().onSuccess { resource in
|
||||||
|
if let playlists: [Playlist] = resource.typedContent() {
|
||||||
|
self.playlists = playlists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,10 @@ final class Subscriptions: ObservableObject {
|
|||||||
load()
|
load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var all: [Channel] {
|
||||||
|
channels.sorted { $0.name.lowercased() < $1.name.lowercased() }
|
||||||
|
}
|
||||||
|
|
||||||
func subscribe(_ channelID: String) {
|
func subscribe(_ channelID: String) {
|
||||||
performChannelSubscriptionRequest(channelID, method: .post)
|
performChannelSubscriptionRequest(channelID, method: .post)
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,19 @@
|
|||||||
37B81B0526D2CEDA00675966 /* PlaybackState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B81B0426D2CEDA00675966 /* PlaybackState.swift */; };
|
37B81B0526D2CEDA00675966 /* PlaybackState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B81B0426D2CEDA00675966 /* PlaybackState.swift */; };
|
||||||
37B81B0626D2CEDA00675966 /* PlaybackState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B81B0426D2CEDA00675966 /* PlaybackState.swift */; };
|
37B81B0626D2CEDA00675966 /* PlaybackState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B81B0426D2CEDA00675966 /* PlaybackState.swift */; };
|
||||||
37B81B0726D2D6CF00675966 /* PlaybackState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B81B0426D2CEDA00675966 /* PlaybackState.swift */; };
|
37B81B0726D2D6CF00675966 /* PlaybackState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B81B0426D2CEDA00675966 /* PlaybackState.swift */; };
|
||||||
|
37BA793B26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */; };
|
||||||
|
37BA793C26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */; };
|
||||||
|
37BA793D26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */; };
|
||||||
|
37BA793F26DB8F97002A0235 /* ChannelVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA793E26DB8F97002A0235 /* ChannelVideosView.swift */; };
|
||||||
|
37BA794026DB8F97002A0235 /* ChannelVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA793E26DB8F97002A0235 /* ChannelVideosView.swift */; };
|
||||||
|
37BA794126DB8F97002A0235 /* ChannelVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA793E26DB8F97002A0235 /* ChannelVideosView.swift */; };
|
||||||
|
37BA794326DBA973002A0235 /* Playlists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794226DBA973002A0235 /* Playlists.swift */; };
|
||||||
|
37BA794426DBA973002A0235 /* Playlists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA794226DBA973002A0235 /* Playlists.swift */; };
|
||||||
|
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 */; };
|
||||||
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */; };
|
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */; };
|
||||||
37BADCA52699FB72009BE4FB /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 37BADCA42699FB72009BE4FB /* Alamofire */; };
|
37BADCA52699FB72009BE4FB /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 37BADCA42699FB72009BE4FB /* Alamofire */; };
|
||||||
37BADCA7269A552E009BE4FB /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 37BADCA6269A552E009BE4FB /* Alamofire */; };
|
37BADCA7269A552E009BE4FB /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 37BADCA6269A552E009BE4FB /* Alamofire */; };
|
||||||
@ -136,7 +149,6 @@
|
|||||||
37BD07C72698B27B003EBB87 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07C62698B27B003EBB87 /* Introspect */; };
|
37BD07C72698B27B003EBB87 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07C62698B27B003EBB87 /* Introspect */; };
|
||||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
|
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
|
||||||
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07B42698AA4D003EBB87 /* ContentView.swift */; };
|
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07B42698AA4D003EBB87 /* ContentView.swift */; };
|
||||||
37BD07CA2698FBE5003EBB87 /* AppSidebarNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */; };
|
|
||||||
37BE0BCF26A0E2D50092E2DB /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */; };
|
37BE0BCF26A0E2D50092E2DB /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */; };
|
||||||
37BE0BD026A0E2D50092E2DB /* 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 */; };
|
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */; };
|
||||||
@ -260,6 +272,11 @@
|
|||||||
37B81AFE26D2CA3700675966 /* VideoDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDetails.swift; sourceTree = "<group>"; };
|
37B81AFE26D2CA3700675966 /* VideoDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDetails.swift; sourceTree = "<group>"; };
|
||||||
37B81B0126D2CAE700675966 /* PlaybackBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackBar.swift; sourceTree = "<group>"; };
|
37B81B0126D2CAE700675966 /* PlaybackBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackBar.swift; sourceTree = "<group>"; };
|
||||||
37B81B0426D2CEDA00675966 /* PlaybackState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackState.swift; sourceTree = "<group>"; };
|
37B81B0426D2CEDA00675966 /* PlaybackState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackState.swift; sourceTree = "<group>"; };
|
||||||
|
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistVideosView.swift; sourceTree = "<group>"; };
|
||||||
|
37BA793E26DB8F97002A0235 /* ChannelVideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelVideosView.swift; sourceTree = "<group>"; };
|
||||||
|
37BA794226DBA973002A0235 /* Playlists.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Playlists.swift; sourceTree = "<group>"; };
|
||||||
|
37BA794626DC2E56002A0235 /* AppSidebarSubscriptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarSubscriptions.swift; sourceTree = "<group>"; };
|
||||||
|
37BA794A26DC30EC002A0235 /* AppSidebarPlaylists.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarPlaylists.swift; sourceTree = "<group>"; };
|
||||||
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVNavigationView.swift; sourceTree = "<group>"; };
|
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVNavigationView.swift; sourceTree = "<group>"; };
|
||||||
37BD07B42698AA4D003EBB87 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
37BD07B42698AA4D003EBB87 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarNavigation.swift; sourceTree = "<group>"; };
|
37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarNavigation.swift; sourceTree = "<group>"; };
|
||||||
@ -362,6 +379,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */,
|
37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */,
|
||||||
|
37BA794A26DC30EC002A0235 /* AppSidebarPlaylists.swift */,
|
||||||
|
37BA794626DC2E56002A0235 /* AppSidebarSubscriptions.swift */,
|
||||||
37D4B0C32671614700C925CA /* AppTabNavigation.swift */,
|
37D4B0C32671614700C925CA /* AppTabNavigation.swift */,
|
||||||
37BD07B42698AA4D003EBB87 /* ContentView.swift */,
|
37BD07B42698AA4D003EBB87 /* ContentView.swift */,
|
||||||
);
|
);
|
||||||
@ -417,6 +436,8 @@
|
|||||||
371AAE2826CEC7D900901972 /* Views */ = {
|
371AAE2826CEC7D900901972 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
37BA793E26DB8F97002A0235 /* ChannelVideosView.swift */,
|
||||||
|
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */,
|
||||||
37AAF27D26737323007FC770 /* PopularView.swift */,
|
37AAF27D26737323007FC770 /* PopularView.swift */,
|
||||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||||
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
||||||
@ -574,6 +595,7 @@
|
|||||||
37B81B0426D2CEDA00675966 /* PlaybackState.swift */,
|
37B81B0426D2CEDA00675966 /* PlaybackState.swift */,
|
||||||
37B767DA2677C3CA0098BAA8 /* PlayerState.swift */,
|
37B767DA2677C3CA0098BAA8 /* PlayerState.swift */,
|
||||||
376578882685471400D4EA09 /* Playlist.swift */,
|
376578882685471400D4EA09 /* Playlist.swift */,
|
||||||
|
37BA794226DBA973002A0235 /* Playlists.swift */,
|
||||||
37C7A1DB267CE9D90010EAD6 /* Profile.swift */,
|
37C7A1DB267CE9D90010EAD6 /* Profile.swift */,
|
||||||
373CFACA26966264003CB2C6 /* SearchQuery.swift */,
|
373CFACA26966264003CB2C6 /* SearchQuery.swift */,
|
||||||
3711403E26B206A6005B3555 /* SearchState.swift */,
|
3711403E26B206A6005B3555 /* SearchState.swift */,
|
||||||
@ -842,10 +864,12 @@
|
|||||||
37CEE4BD2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
37CEE4BD2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
||||||
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
|
37BA793B26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */,
|
||||||
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
||||||
37C7A1DA267CACF50010EAD6 /* TrendingCountry.swift in Sources */,
|
37C7A1DA267CACF50010EAD6 /* TrendingCountry.swift in Sources */,
|
||||||
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
||||||
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
||||||
|
37BA793F26DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
|
||||||
37754C9D26B7500000DBD602 /* VideosView.swift in Sources */,
|
37754C9D26B7500000DBD602 /* VideosView.swift in Sources */,
|
||||||
3711403F26B206A6005B3555 /* SearchState.swift in Sources */,
|
3711403F26B206A6005B3555 /* SearchState.swift in Sources */,
|
||||||
37B81AF926D2C9A700675966 /* VideoPlayerSizeModifier.swift in Sources */,
|
37B81AF926D2C9A700675966 /* VideoPlayerSizeModifier.swift in Sources */,
|
||||||
@ -854,6 +878,7 @@
|
|||||||
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */,
|
||||||
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||||
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
|
37BA794726DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */,
|
||||||
377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */,
|
377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */,
|
||||||
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||||
37EAD86F267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD86F267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
@ -866,6 +891,7 @@
|
|||||||
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||||
377FC7E3267A084A00A6BBAF /* VideoView.swift in Sources */,
|
377FC7E3267A084A00A6BBAF /* VideoView.swift in Sources */,
|
||||||
|
37BA794326DBA973002A0235 /* Playlists.swift in Sources */,
|
||||||
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
||||||
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
||||||
37B81AFF26D2CA3700675966 /* VideoDetails.swift in Sources */,
|
37B81AFF26D2CA3700675966 /* VideoDetails.swift in Sources */,
|
||||||
@ -878,6 +904,7 @@
|
|||||||
37B81AFC26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
|
37B81AFC26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
|
||||||
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
||||||
37F49BA326CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
37F49BA326CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
||||||
|
37BA794B26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */,
|
||||||
37B767DB2677C3CA0098BAA8 /* PlayerState.swift in Sources */,
|
37B767DB2677C3CA0098BAA8 /* PlayerState.swift in Sources */,
|
||||||
373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
||||||
373CFAC226966159003CB2C6 /* CoverSectionRowView.swift in Sources */,
|
373CFAC226966159003CB2C6 /* CoverSectionRowView.swift in Sources */,
|
||||||
@ -903,6 +930,7 @@
|
|||||||
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
|
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
|
||||||
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
|
||||||
373CFABF26966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
373CFABF26966149003CB2C6 /* CoverSectionView.swift in Sources */,
|
||||||
|
37BA794826DC2E56002A0235 /* AppSidebarSubscriptions.swift in Sources */,
|
||||||
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86C267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
|
37CEE4C22677B697005A1EFE /* Stream.swift in Sources */,
|
||||||
371F2F1B269B43D300E4A7AB /* NavigationState.swift in Sources */,
|
371F2F1B269B43D300E4A7AB /* NavigationState.swift in Sources */,
|
||||||
@ -912,6 +940,7 @@
|
|||||||
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */,
|
||||||
37F49BA426CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
37F49BA426CAA59B00304AC0 /* Playlist+Fixtures.swift in Sources */,
|
||||||
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
|
37BA793C26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */,
|
||||||
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
37141670267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
377FC7E2267A084A00A6BBAF /* VideoView.swift in Sources */,
|
377FC7E2267A084A00A6BBAF /* VideoView.swift in Sources */,
|
||||||
37B81B0626D2CEDA00675966 /* PlaybackState.swift in Sources */,
|
37B81B0626D2CEDA00675966 /* PlaybackState.swift in Sources */,
|
||||||
@ -942,9 +971,11 @@
|
|||||||
3797758C2689345500DD52A8 /* Store.swift in Sources */,
|
3797758C2689345500DD52A8 /* Store.swift in Sources */,
|
||||||
37141674267A8E10006CA35D /* Country.swift in Sources */,
|
37141674267A8E10006CA35D /* Country.swift in Sources */,
|
||||||
37AAF2A126741C97007FC770 /* SubscriptionsView.swift in Sources */,
|
37AAF2A126741C97007FC770 /* SubscriptionsView.swift in Sources */,
|
||||||
|
37BA794C26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */,
|
||||||
37D4B19826717E1500C925CA /* Video.swift in Sources */,
|
37D4B19826717E1500C925CA /* Video.swift in Sources */,
|
||||||
37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */,
|
37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */,
|
||||||
37BD07C12698AD3B003EBB87 /* TrendingCountry.swift in Sources */,
|
37BD07C12698AD3B003EBB87 /* TrendingCountry.swift in Sources */,
|
||||||
|
37BA794026DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
|
||||||
3711404026B206A6005B3555 /* SearchState.swift in Sources */,
|
3711404026B206A6005B3555 /* SearchState.swift in Sources */,
|
||||||
37BE0BD026A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
37BE0BD026A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
||||||
373CFAEC26975CBF003CB2C6 /* PlaylistFormView.swift in Sources */,
|
373CFAEC26975CBF003CB2C6 /* PlaylistFormView.swift in Sources */,
|
||||||
@ -953,6 +984,7 @@
|
|||||||
3748186B26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
3748186B26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
||||||
373CFADC269663F1003CB2C6 /* Thumbnail.swift in Sources */,
|
373CFADC269663F1003CB2C6 /* Thumbnail.swift in Sources */,
|
||||||
373CFAF02697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
373CFAF02697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||||
|
37BA794426DBA973002A0235 /* Playlists.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -987,11 +1019,11 @@
|
|||||||
376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||||
37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */,
|
37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */,
|
||||||
3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
|
3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
|
||||||
37BD07CA2698FBE5003EBB87 /* AppSidebarNavigation.swift in Sources */,
|
|
||||||
373CFAC926966188003CB2C6 /* SearchOptionsView.swift in Sources */,
|
373CFAC926966188003CB2C6 /* SearchOptionsView.swift in Sources */,
|
||||||
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */,
|
37BD07C92698FBDB003EBB87 /* ContentView.swift in Sources */,
|
||||||
37B17DA6268A285E006AEE9B /* VideoDetailsView.swift in Sources */,
|
37B17DA6268A285E006AEE9B /* VideoDetailsView.swift in Sources */,
|
||||||
37141671267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
37141671267A8ACC006CA35D /* TrendingView.swift in Sources */,
|
||||||
|
37BA794126DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
|
||||||
37AAF29226740715007FC770 /* Channel.swift in Sources */,
|
37AAF29226740715007FC770 /* Channel.swift in Sources */,
|
||||||
37EAD86D267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86D267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
37B81B0726D2D6CF00675966 /* PlaybackState.swift in Sources */,
|
37B81B0726D2D6CF00675966 /* PlaybackState.swift in Sources */,
|
||||||
@ -1012,10 +1044,12 @@
|
|||||||
377A20AB2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
|
377A20AB2693C9A2002842B8 /* TypedContentAccessors.swift in Sources */,
|
||||||
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186826A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
371F2F1C269B43D300E4A7AB /* NavigationState.swift in Sources */,
|
371F2F1C269B43D300E4A7AB /* NavigationState.swift in Sources */,
|
||||||
|
37BA794526DBA973002A0235 /* Playlists.swift in Sources */,
|
||||||
37B17DA0268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */,
|
37B17DA0268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */,
|
||||||
37BE0BD726A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
37BE0BD726A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
||||||
37CEE4C32677B697005A1EFE /* Stream.swift in Sources */,
|
37CEE4C32677B697005A1EFE /* Stream.swift in Sources */,
|
||||||
37BE0BE526A336910092E2DB /* OptionsView.swift in Sources */,
|
37BE0BE526A336910092E2DB /* OptionsView.swift in Sources */,
|
||||||
|
37BA793D26DB8EE4002A0235 /* PlaylistVideosView.swift in Sources */,
|
||||||
3711404126B206A6005B3555 /* SearchState.swift in Sources */,
|
3711404126B206A6005B3555 /* SearchState.swift in Sources */,
|
||||||
379775952689365600DD52A8 /* Array+Next.swift in Sources */,
|
379775952689365600DD52A8 /* Array+Next.swift in Sources */,
|
||||||
37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */,
|
37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */,
|
||||||
|
@ -3,17 +3,17 @@ import SwiftUI
|
|||||||
import Introspect
|
import Introspect
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typealias TabSelection = AppSidebarNavigation.TabSelection
|
|
||||||
|
|
||||||
struct AppSidebarNavigation: View {
|
struct AppSidebarNavigation: View {
|
||||||
enum TabSelection: String {
|
|
||||||
case subscriptions, popular, trending, playlists, channel, search
|
|
||||||
}
|
|
||||||
|
|
||||||
@EnvironmentObject<NavigationState> private var navigationState
|
@EnvironmentObject<NavigationState> private var navigationState
|
||||||
|
@EnvironmentObject<Playlists> private var playlists
|
||||||
|
@EnvironmentObject<Subscriptions> private var subscriptions
|
||||||
|
|
||||||
@State private var didApplyPrimaryViewWorkAround = false
|
@State private var didApplyPrimaryViewWorkAround = false
|
||||||
|
|
||||||
|
var selection: Binding<TabSelection?> {
|
||||||
|
navigationState.tabSelectionOptionalBinding
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
content.introspectViewController { viewController in
|
content.introspectViewController { viewController in
|
||||||
@ -38,53 +38,18 @@ struct AppSidebarNavigation: View {
|
|||||||
NavigationView {
|
NavigationView {
|
||||||
sidebar
|
sidebar
|
||||||
.frame(minWidth: 180)
|
.frame(minWidth: 180)
|
||||||
|
|
||||||
Text("Select section")
|
Text("Select section")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sidebar: some View {
|
var sidebar: some View {
|
||||||
List {
|
List {
|
||||||
NavigationLink(tag: TabSelection.subscriptions, selection: navigationState.tabSelectionOptionalBinding) {
|
mainNavigationLinks
|
||||||
SubscriptionsView()
|
|
||||||
}
|
AppSidebarSubscriptions(selection: selection)
|
||||||
label: {
|
AppSidebarPlaylists(selection: selection)
|
||||||
Label("Subscriptions", systemImage: "star.circle.fill")
|
|
||||||
.accessibility(label: Text("Subscriptions"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(tag: TabSelection.popular, selection: navigationState.tabSelectionOptionalBinding) {
|
|
||||||
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)
|
#if os(macOS)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
Button(action: toggleSidebar) {
|
Button(action: toggleSidebar) {
|
||||||
@ -94,6 +59,59 @@ struct AppSidebarNavigation: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mainNavigationLinks: some View {
|
||||||
|
Group {
|
||||||
|
NavigationLink(tag: TabSelection.subscriptions, selection: selection) {
|
||||||
|
SubscriptionsView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Subscriptions", systemImage: "star.circle.fill")
|
||||||
|
.accessibility(label: Text("Subscriptions"))
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(tag: TabSelection.popular, selection: selection) {
|
||||||
|
PopularView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Popular", systemImage: "chart.bar")
|
||||||
|
.accessibility(label: Text("Popular"))
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(tag: TabSelection.trending, selection: selection) {
|
||||||
|
TrendingView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Trending", systemImage: "chart.line.uptrend.xyaxis")
|
||||||
|
.accessibility(label: Text("Trending"))
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(tag: TabSelection.playlists, selection: selection) {
|
||||||
|
PlaylistsView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Playlists", systemImage: "list.and.film")
|
||||||
|
.accessibility(label: Text("Playlists"))
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(tag: TabSelection.search, selection: selection) {
|
||||||
|
SearchView()
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
Label("Search", systemImage: "magnifyingglass")
|
||||||
|
.accessibility(label: Text("Search"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func symbolSystemImage(_ name: String) -> String {
|
||||||
|
let firstLetter = name.first?.lowercased()
|
||||||
|
let regex = #"^[a-z0-9]$"#
|
||||||
|
|
||||||
|
let symbolName = firstLetter?.range(of: regex, options: .regularExpression) != nil ? firstLetter! : "questionmark"
|
||||||
|
|
||||||
|
return "\(symbolName).square"
|
||||||
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
private func toggleSidebar() {
|
private func toggleSidebar() {
|
||||||
NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
|
NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
|
||||||
|
37
Shared/Navigation/AppSidebarPlaylists.swift
Normal file
37
Shared/Navigation/AppSidebarPlaylists.swift
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct AppSidebarPlaylists: View {
|
||||||
|
@EnvironmentObject<NavigationState> private var navigationState
|
||||||
|
@EnvironmentObject<Playlists> private var playlists
|
||||||
|
|
||||||
|
@Binding var selection: TabSelection?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Section(header: Text("Playlists")) {
|
||||||
|
ForEach(playlists.all) { playlist in
|
||||||
|
NavigationLink(tag: TabSelection.playlist(playlist.id), selection: $selection) {
|
||||||
|
PlaylistVideosView(playlist)
|
||||||
|
} label: {
|
||||||
|
Label(playlist.title, systemImage: AppSidebarNavigation.symbolSystemImage(playlist.title))
|
||||||
|
.badge(Text("\(playlist.videos.count)"))
|
||||||
|
}
|
||||||
|
.contextMenu {
|
||||||
|
Button("Edit") {
|
||||||
|
navigationState.presentEditPlaylistForm(playlists.find(id: playlist.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newPlaylistButton
|
||||||
|
.padding(.top, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newPlaylistButton: some View {
|
||||||
|
Button(action: { navigationState.presentNewPlaylistForm() }) {
|
||||||
|
Label("New Playlist", systemImage: "plus.square")
|
||||||
|
}
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
}
|
40
Shared/Navigation/AppSidebarSubscriptions.swift
Normal file
40
Shared/Navigation/AppSidebarSubscriptions.swift
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct AppSidebarSubscriptions: View {
|
||||||
|
@EnvironmentObject<NavigationState> private var navigationState
|
||||||
|
@EnvironmentObject<Subscriptions> private var subscriptions
|
||||||
|
|
||||||
|
@Binding var selection: TabSelection?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Section(header: Text("Subscriptions")) {
|
||||||
|
ForEach(subscriptions.all) { channel in
|
||||||
|
NavigationLink(tag: TabSelection.channel(channel.id), selection: $selection) {
|
||||||
|
ChannelVideosView(channel)
|
||||||
|
} label: {
|
||||||
|
Label(channel.name, systemImage: AppSidebarNavigation.symbolSystemImage(channel.name))
|
||||||
|
}
|
||||||
|
.contextMenu {
|
||||||
|
Button("Unsubscribe") {
|
||||||
|
navigationState.presentUnsubscribeAlert(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.alert(unsubscribeAlertTitle, isPresented: $navigationState.presentingUnsubscribeAlert) {
|
||||||
|
if let channel = navigationState.channelToUnsubscribe {
|
||||||
|
Button("Unsubscribe", role: .destructive) {
|
||||||
|
subscriptions.unsubscribe(channel.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unsubscribeAlertTitle: String {
|
||||||
|
if let channel = navigationState.channelToUnsubscribe {
|
||||||
|
return "Unsubscribe from \(channel.name)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown channel"
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ struct ContentView: View {
|
|||||||
@StateObject private var playbackState = PlaybackState()
|
@StateObject private var playbackState = PlaybackState()
|
||||||
@StateObject private var searchState = SearchState()
|
@StateObject private var searchState = SearchState()
|
||||||
@StateObject private var subscriptions = Subscriptions()
|
@StateObject private var subscriptions = Subscriptions()
|
||||||
|
@StateObject private var playlists = Playlists()
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||||
@ -37,11 +38,15 @@ struct ContentView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $navigationState.presentingPlaylistForm) {
|
||||||
|
PlaylistFormView(playlist: $navigationState.editedPlaylist)
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
.environmentObject(navigationState)
|
.environmentObject(navigationState)
|
||||||
.environmentObject(playbackState)
|
.environmentObject(playbackState)
|
||||||
.environmentObject(searchState)
|
.environmentObject(searchState)
|
||||||
.environmentObject(subscriptions)
|
.environmentObject(subscriptions)
|
||||||
|
.environmentObject(playlists)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ struct PlaylistFormView: View {
|
|||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
||||||
|
@EnvironmentObject<Playlists> private var playlists
|
||||||
|
|
||||||
var editing: Bool {
|
var editing: Bool {
|
||||||
playlist != nil
|
playlist != nil
|
||||||
}
|
}
|
||||||
@ -139,6 +141,8 @@ struct PlaylistFormView: View {
|
|||||||
playlist = modifiedPlaylist
|
playlist = modifiedPlaylist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playlists.reload()
|
||||||
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
27
Shared/Views/ChannelVideosView.swift
Normal file
27
Shared/Views/ChannelVideosView.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import Siesta
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ChannelVideosView: View {
|
||||||
|
@ObservedObject private var store = Store<[Video]>()
|
||||||
|
|
||||||
|
let channel: Channel
|
||||||
|
|
||||||
|
var resource: Resource {
|
||||||
|
InvidiousAPI.shared.channelVideos(channel.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ channel: Channel) {
|
||||||
|
self.channel = channel
|
||||||
|
resource.addObserver(store)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VideosView(videos: store.collection)
|
||||||
|
#if !os(tvOS)
|
||||||
|
.navigationTitle("\(channel.name) Channel")
|
||||||
|
#endif
|
||||||
|
.onAppear {
|
||||||
|
resource.loadIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Shared/Views/PlaylistVideosView.swift
Normal file
17
Shared/Views/PlaylistVideosView.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import Siesta
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct PlaylistVideosView: View {
|
||||||
|
let playlist: Playlist
|
||||||
|
|
||||||
|
init(_ playlist: Playlist) {
|
||||||
|
self.playlist = playlist
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VideosView(videos: playlist.videos)
|
||||||
|
#if !os(tvOS)
|
||||||
|
.navigationTitle("\(playlist.title) Playlist")
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user