From b336d2c512fa71a12c2c46b34ab753ccb62188b4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sat, 26 Jun 2021 11:39:35 +0200 Subject: [PATCH] Playlists support --- Apple TV/PlaylistsView.swift | 72 ++++++++++++++++++++ Apple TV/TrendingCategorySelectionView.swift | 29 -------- Apple TV/TrendingView.swift | 19 +++--- Apple TV/VideoCellView.swift | 20 +++--- Apple TV/VideoListRow.swift | 20 +++--- Apple TV/VideosCellsView.swift | 2 +- Extensions/AVKeyValueStatus+String.swift | 1 - Extensions/CaseIterable+Next.swift | 4 +- Model/Playlist.swift | 25 +++++++ Model/PlaylistsProvider.swift | 22 ++++++ Model/TrendingState.swift | 6 -- Pearvidious.xcodeproj/project.pbxproj | 42 +++++++----- Shared/ContentView.swift | 8 ++- Shared/TabSelection.swift | 4 +- 14 files changed, 189 insertions(+), 85 deletions(-) create mode 100644 Apple TV/PlaylistsView.swift delete mode 100644 Apple TV/TrendingCategorySelectionView.swift create mode 100644 Model/Playlist.swift create mode 100644 Model/PlaylistsProvider.swift delete mode 100644 Model/TrendingState.swift diff --git a/Apple TV/PlaylistsView.swift b/Apple TV/PlaylistsView.swift new file mode 100644 index 00000000..22e09a32 --- /dev/null +++ b/Apple TV/PlaylistsView.swift @@ -0,0 +1,72 @@ +import SwiftUI + +struct PlaylistsView: View { + @EnvironmentObject private var state: AppState + + @Binding var tabSelection: TabSelection + + @ObservedObject private var provider = PlaylistsProvider() + + @State private var selectedPlaylist: Playlist? + + var body: some View { + Section { + VStack(alignment: .leading, spacing: 2) { + HStack(alignment: .top) { + Spacer() + + selectPlaylistButton + + Spacer() + } + .padding(.bottom, 5) + + VStack { + if selectedPlaylist != nil { + VideosView(tabSelection: $tabSelection, videos: selectedPlaylist!.videos) + } + } + } + }.task { + Task { + provider.load { playlists in + selectedPlaylist = playlists.first + } + } + } + } + + var playlists: [Playlist] { + if provider.playlists.isEmpty { + provider.load() + } + + return provider.playlists + } + + var selectPlaylistButton: some View { + Button(selectedPlaylist?.title ?? "Select playlist") { + guard selectedPlaylist != nil else { + return + } + + selectedPlaylist = playlists.next(after: selectedPlaylist!) + } + .contextMenu { + ForEach(provider.playlists) { playlist in + Button(playlist.title) { + selectedPlaylist = playlist + } + } + } + } +} + +extension Array where Element: Equatable { + func next(after element: Element) -> Element? { + let idx = firstIndex(of: element)! + let next = index(after: idx) + + return self[next == endIndex ? startIndex : next] + } +} diff --git a/Apple TV/TrendingCategorySelectionView.swift b/Apple TV/TrendingCategorySelectionView.swift deleted file mode 100644 index 2370cd62..00000000 --- a/Apple TV/TrendingCategorySelectionView.swift +++ /dev/null @@ -1,29 +0,0 @@ -import SwiftUI - -struct TrendingCategorySelectionView: View { - @Environment(\.presentationMode) private var presentationMode - - @Binding var selectedCategory: TrendingCategory - - var body: some View { - ZStack { - VisualEffectView(effect: UIBlurEffect(style: .dark)) - - VStack(alignment: .leading) { - Spacer() - - ForEach(TrendingCategory.allCases) { category in - Button(category.name) { - selectedCategory = category - presentationMode.wrappedValue.dismiss() - } - } - .frame(width: 800) - - Spacer() - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - .edgesIgnoringSafeArea(.all) - } -} diff --git a/Apple TV/TrendingView.swift b/Apple TV/TrendingView.swift index 5b2c7d1a..9975b825 100644 --- a/Apple TV/TrendingView.swift +++ b/Apple TV/TrendingView.swift @@ -2,13 +2,14 @@ import SwiftUI struct TrendingView: View { @EnvironmentObject private var state: AppState - @EnvironmentObject private var trendingState: TrendingState @Binding var tabSelection: TabSelection @ObservedObject private var videosProvider = TrendingVideosProvider() - @State private var selectingCategory = false + @SceneStorage("category") var category: TrendingCategory = .default + @SceneStorage("country") var country: Country = .pl + @State private var selectingCountry = false var body: some View { @@ -31,35 +32,35 @@ struct TrendingView: View { } var videos: [Video] { - videosProvider.load(category: trendingState.category, country: trendingState.country) + videosProvider.load(category: category, country: country) return videosProvider.videos } var categoryButton: some View { - Button(trendingState.category.name) { - trendingState.category = trendingState.category.next() + Button(category.name) { + category = category.next() } .contextMenu { ForEach(TrendingCategory.allCases) { category in Button(category.name) { - trendingState.category = category + self.category = category } } } } var countryFlag: some View { - Text(trendingState.country.flag) + Text(country.flag) .font(.system(size: 60)) } var countryButton: some View { - Button(trendingState.country.rawValue) { + Button(country.rawValue) { selectingCountry.toggle() } .fullScreenCover(isPresented: $selectingCountry) { - TrendingCountrySelectionView(selectedCountry: $trendingState.country) + TrendingCountrySelectionView(selectedCountry: $country) } } } diff --git a/Apple TV/VideoCellView.swift b/Apple TV/VideoCellView.swift index 208e1558..0cf34241 100644 --- a/Apple TV/VideoCellView.swift +++ b/Apple TV/VideoCellView.swift @@ -51,17 +51,21 @@ struct VideoCellView: View { .frame(minHeight: 80, alignment: .top) .truncationMode(.middle) - HStack(spacing: 8) { - Image(systemName: "calendar") - Text(video.published) + if !video.published.isEmpty || video.views != 0 { + HStack(spacing: 8) { + if !video.published.isEmpty { + Image(systemName: "calendar") + Text(video.published) + } - if video.views != 0 { - Image(systemName: "eye") - Text(video.viewsCount) + if video.views != 0 { + Image(systemName: "eye") + Text(video.viewsCount) + } } + .padding([.horizontal, .bottom]) + .foregroundColor(.secondary) } - .padding([.horizontal, .bottom]) - .foregroundColor(.secondary) } } .frame(width: 550, alignment: .leading) diff --git a/Apple TV/VideoListRow.swift b/Apple TV/VideoListRow.swift index 4a738387..45beb38b 100644 --- a/Apple TV/VideoListRow.swift +++ b/Apple TV/VideoListRow.swift @@ -38,17 +38,21 @@ struct VideoListRow: View { .bold() .lineLimit(1) - HStack(spacing: 8) { - Image(systemName: "calendar") - Text(video.published) + if !video.published.isEmpty || video.views != 0 { + HStack(spacing: 8) { + if !video.published.isEmpty { + Image(systemName: "calendar") + Text(video.published) + } - if video.views != 0 { - Image(systemName: "eye") - Text(video.viewsCount) + if video.views != 0 { + Image(systemName: "eye") + Text(video.viewsCount) + } } + .foregroundColor(.secondary) + .padding(.top) } - .foregroundColor(.secondary) - .padding(.top) } .padding() diff --git a/Apple TV/VideosCellsView.swift b/Apple TV/VideosCellsView.swift index e40c480f..7f6e16f4 100644 --- a/Apple TV/VideosCellsView.swift +++ b/Apple TV/VideosCellsView.swift @@ -13,7 +13,7 @@ struct VideosCellsView: View { var videos = [Video]() var body: some View { - ScrollView(.vertical) { + ScrollView(.vertical, showsIndicators: false) { LazyVGrid(columns: items, spacing: 10) { ForEach(videos) { video in VideoCellView(video: video) diff --git a/Extensions/AVKeyValueStatus+String.swift b/Extensions/AVKeyValueStatus+String.swift index 3e70ca78..0e79bb1c 100644 --- a/Extensions/AVKeyValueStatus+String.swift +++ b/Extensions/AVKeyValueStatus+String.swift @@ -1,5 +1,4 @@ import AVFoundation -import Foundation extension AVKeyValueStatus { var string: String { diff --git a/Extensions/CaseIterable+Next.swift b/Extensions/CaseIterable+Next.swift index 42db6595..c1d8d110 100644 --- a/Extensions/CaseIterable+Next.swift +++ b/Extensions/CaseIterable+Next.swift @@ -1,8 +1,8 @@ extension CaseIterable where Self: Equatable { func next() -> Self { let all = Self.allCases - let idx = all.firstIndex(of: self)! - let next = all.index(after: idx) + let index = all.firstIndex(of: self)! + let next = all.index(after: index) return all[next == all.endIndex ? all.startIndex : next] } } diff --git a/Model/Playlist.swift b/Model/Playlist.swift new file mode 100644 index 00000000..8acf961f --- /dev/null +++ b/Model/Playlist.swift @@ -0,0 +1,25 @@ +import Foundation +import SwiftyJSON + +final class Playlist: Identifiable, ObservableObject, Equatable, Hashable { + let id: String + var title: String + var description: String + + var videos = [Video]() + + init(_ json: JSON) { + id = json["playlistId"].stringValue + title = json["title"].stringValue + description = json["description"].stringValue + videos = json["videos"].arrayValue.map { Video($0) } + } + + static func == (lhs: Playlist, rhs: Playlist) -> Bool { + lhs.id == rhs.id + } + + func hash(into hasher: inout Hasher) { + hasher.combine(id) + } +} diff --git a/Model/PlaylistsProvider.swift b/Model/PlaylistsProvider.swift new file mode 100644 index 00000000..aa1c53e1 --- /dev/null +++ b/Model/PlaylistsProvider.swift @@ -0,0 +1,22 @@ +import Alamofire +import Foundation +import SwiftyJSON + +final class PlaylistsProvider: DataProvider { + @Published var playlists = [Playlist]() + + let profile = Profile() + + func load(successHandler: @escaping ([Playlist]) -> Void = { _ in }) { + let headers = HTTPHeaders([HTTPHeader(name: "Cookie", value: "SID=\(profile.sid)")]) + DataProvider.request("auth/playlists", headers: headers).responseJSON { response in + switch response.result { + case let .success(value): + self.playlists = JSON(value).arrayValue.map { Playlist($0) } + successHandler(self.playlists) + case let .failure(error): + print(error) + } + } + } +} diff --git a/Model/TrendingState.swift b/Model/TrendingState.swift deleted file mode 100644 index 08013cd5..00000000 --- a/Model/TrendingState.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -final class TrendingState: ObservableObject { - @Published var category: TrendingCategory = .default - @Published var country: Country = .pl -} diff --git a/Pearvidious.xcodeproj/project.pbxproj b/Pearvidious.xcodeproj/project.pbxproj index 76535328..cbdcfa82 100644 --- a/Pearvidious.xcodeproj/project.pbxproj +++ b/Pearvidious.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 3705B17C267B4D9A00704544 /* VisualEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17B267B4D9A00704544 /* VisualEffectView.swift */; }; - 3705B17E267B4DDE00704544 /* TrendingCategorySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17D267B4DDE00704544 /* TrendingCategorySelectionView.swift */; }; 3705B180267B4DFB00704544 /* TrendingCountrySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */; }; 3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; }; 3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; }; @@ -25,9 +24,6 @@ 37141673267A8E10006CA35D /* Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37141672267A8E10006CA35D /* Country.swift */; }; 37141674267A8E10006CA35D /* Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37141672267A8E10006CA35D /* Country.swift */; }; 37141675267A8E10006CA35D /* Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37141672267A8E10006CA35D /* Country.swift */; }; - 37141677267A9AAD006CA35D /* TrendingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37141676267A9AAD006CA35D /* TrendingState.swift */; }; - 37141678267A9AAD006CA35D /* TrendingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37141676267A9AAD006CA35D /* TrendingState.swift */; }; - 37141679267A9AAD006CA35D /* TrendingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37141676267A9AAD006CA35D /* TrendingState.swift */; }; 3714167B267AA1CF006CA35D /* TrendingCountriesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3714167A267AA1CF006CA35D /* TrendingCountriesProvider.swift */; }; 3714167C267AA1CF006CA35D /* TrendingCountriesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3714167A267AA1CF006CA35D /* TrendingCountriesProvider.swift */; }; 3714167D267AA1CF006CA35D /* TrendingCountriesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3714167A267AA1CF006CA35D /* TrendingCountriesProvider.swift */; }; @@ -38,6 +34,15 @@ 376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578842685429C00D4EA09 /* CaseIterable+Next.swift */; }; 376578862685429C00D4EA09 /* CaseIterable+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578842685429C00D4EA09 /* CaseIterable+Next.swift */; }; 376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578842685429C00D4EA09 /* CaseIterable+Next.swift */; }; + 376578892685471400D4EA09 /* Playlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578882685471400D4EA09 /* Playlist.swift */; }; + 3765788A2685471400D4EA09 /* Playlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578882685471400D4EA09 /* Playlist.swift */; }; + 3765788B2685471400D4EA09 /* Playlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578882685471400D4EA09 /* Playlist.swift */; }; + 3765788D2685487700D4EA09 /* PlaylistsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3765788C2685487700D4EA09 /* PlaylistsProvider.swift */; }; + 3765788E2685487700D4EA09 /* PlaylistsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3765788C2685487700D4EA09 /* PlaylistsProvider.swift */; }; + 3765788F2685487700D4EA09 /* PlaylistsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3765788C2685487700D4EA09 /* PlaylistsProvider.swift */; }; + 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 */; }; 377FC7D3267A080300A6BBAF /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7D2267A080300A6BBAF /* Alamofire */; }; 377FC7D5267A080300A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7D4267A080300A6BBAF /* SwiftyJSON */; }; 377FC7D7267A080300A6BBAF /* URLImage in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7D6267A080300A6BBAF /* URLImage */; }; @@ -91,7 +96,6 @@ 37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; }; 37C7A1D6267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; }; 37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; }; - 37C7A1D8267CACE10010EAD6 /* TrendingCategorySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17D267B4DDE00704544 /* TrendingCategorySelectionView.swift */; }; 37C7A1D9267CACE60010EAD6 /* VisualEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17B267B4D9A00704544 /* VisualEffectView.swift */; }; 37C7A1DA267CACF50010EAD6 /* TrendingCountrySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */; }; 37C7A1DC267CE9D90010EAD6 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1DB267CE9D90010EAD6 /* Profile.swift */; }; @@ -183,18 +187,19 @@ /* Begin PBXFileReference section */ 3705B17B267B4D9A00704544 /* VisualEffectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisualEffectView.swift; sourceTree = ""; }; - 3705B17D267B4DDE00704544 /* TrendingCategorySelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCategorySelectionView.swift; sourceTree = ""; }; 3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCountrySelectionView.swift; sourceTree = ""; }; 3705B181267B4E4900704544 /* TrendingCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCategory.swift; sourceTree = ""; }; 371231832683E62F0000B307 /* VideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosView.swift; sourceTree = ""; }; 37141667267A83F9006CA35D /* StreamAVPlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamAVPlayerViewController.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 = ""; }; - 37141676267A9AAD006CA35D /* TrendingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingState.swift; sourceTree = ""; }; 3714167A267AA1CF006CA35D /* TrendingCountriesProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCountriesProvider.swift; sourceTree = ""; }; 3714167E267AB55D006CA35D /* TrendingVideosProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingVideosProvider.swift; sourceTree = ""; }; 3741B52F2676213400125C5E /* PlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerViewController.swift; sourceTree = ""; }; 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 = ""; }; + 3765788C2685487700D4EA09 /* PlaylistsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistsProvider.swift; sourceTree = ""; }; + 376578902685490700D4EA09 /* PlaylistsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistsView.swift; sourceTree = ""; }; 37AAF27D26737323007FC770 /* PopularVideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopularVideosView.swift; sourceTree = ""; }; 37AAF27F26737550007FC770 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; 37AAF2812673791F007FC770 /* SearchedVideosProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchedVideosProvider.swift; sourceTree = ""; }; @@ -378,21 +383,21 @@ 37AAF2892673AB89007FC770 /* ChannelView.swift */, 37D4B1822671681B00C925CA /* PlayerView.swift */, 3741B52F2676213400125C5E /* PlayerViewController.swift */, + 376578902685490700D4EA09 /* PlaylistsView.swift */, 37AAF27D26737323007FC770 /* PopularVideosView.swift */, 37AAF27F26737550007FC770 /* SearchView.swift */, 37141667267A83F9006CA35D /* StreamAVPlayerViewController.swift */, 37AAF29F26741C97007FC770 /* SubscriptionsView.swift */, - 3705B17D267B4DDE00704544 /* TrendingCategorySelectionView.swift */, 3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */, 3714166E267A8ACC006CA35D /* TrendingView.swift */, 37F4AE752682908700BD60EA /* VideoCellView.swift */, + 37D4B18B26717B3800C925CA /* VideoListRow.swift */, 37F4AE7126828F0900BD60EA /* VideosCellsView.swift */, 37AAF29926740A01007FC770 /* VideosListView.swift */, - 37D4B18B26717B3800C925CA /* VideoListRow.swift */, + 371231832683E62F0000B307 /* VideosView.swift */, 3705B17B267B4D9A00704544 /* VisualEffectView.swift */, 37D4B15E267164AF00C925CA /* Assets.xcassets */, 37D4B1AE26729DEB00C925CA /* Info.plist */, - 371231832683E62F0000B307 /* VideosView.swift */, ); path = "Apple TV"; sourceTree = ""; @@ -413,6 +418,8 @@ 37AAF28B2673ABD3007FC770 /* ChannelVideosProvider.swift */, 37D4B1AF2672A01000C925CA /* DataProvider.swift */, 37B767DA2677C3CA0098BAA8 /* PlayerState.swift */, + 376578882685471400D4EA09 /* Playlist.swift */, + 3765788C2685487700D4EA09 /* PlaylistsProvider.swift */, 37D4B19226717CE100C925CA /* PopularVideosProvider.swift */, 37C7A1DB267CE9D90010EAD6 /* Profile.swift */, 37AAF2812673791F007FC770 /* SearchedVideosProvider.swift */, @@ -425,7 +432,6 @@ 37AAF29B26741B5F007FC770 /* SubscriptionVideosProvider.swift */, 3705B181267B4E4900704544 /* TrendingCategory.swift */, 3714167A267AA1CF006CA35D /* TrendingCountriesProvider.swift */, - 37141676267A9AAD006CA35D /* TrendingState.swift */, 3714167E267AB55D006CA35D /* TrendingVideosProvider.swift */, 37D4B19626717E1500C925CA /* Video.swift */, 37D4B1B32672A30700C925CA /* VideoDetailsProvider.swift */, @@ -683,13 +689,13 @@ 37AAF29C26741B5F007FC770 /* SubscriptionVideosProvider.swift in Sources */, 37141668267A83F9006CA35D /* StreamAVPlayerViewController.swift in Sources */, 37EAD86B267B9C5600D9E01B /* SponsorBlockSegmentsProvider.swift in Sources */, + 3765788D2685487700D4EA09 /* PlaylistsProvider.swift in Sources */, 37F4AE762682908700BD60EA /* VideoCellView.swift in Sources */, 37C7A1DA267CACF50010EAD6 /* TrendingCountrySelectionView.swift in Sources */, 377FC7E6267A085600A6BBAF /* PlayerView.swift in Sources */, 37CEE4C12677B697005A1EFE /* Stream.swift in Sources */, 37F4AE7226828F0900BD60EA /* VideosCellsView.swift in Sources */, 376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */, - 37141677267A9AAD006CA35D /* TrendingState.swift in Sources */, 37C7A1D9267CACE60010EAD6 /* VisualEffectView.swift in Sources */, 37D4B0E62671614900C925CA /* ContentView.swift in Sources */, 377FC7DC267A081800A6BBAF /* PopularVideosView.swift in Sources */, @@ -697,6 +703,7 @@ 3714167F267AB55D006CA35D /* TrendingVideosProvider.swift in Sources */, 3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */, 37EAD86F267B9ED100D9E01B /* Segment.swift in Sources */, + 376578892685471400D4EA09 /* Playlist.swift in Sources */, 37CEE4B52677B628005A1EFE /* StreamType.swift in Sources */, 37C7A1DC267CE9D90010EAD6 /* Profile.swift in Sources */, 3714166F267A8ACC006CA35D /* TrendingView.swift in Sources */, @@ -708,6 +715,7 @@ 37AAF28C2673ABD3007FC770 /* ChannelVideosProvider.swift in Sources */, 377FC7E9267A085D00A6BBAF /* PlayerViewController.swift in Sources */, 377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */, + 376578912685490700D4EA09 /* PlaylistsView.swift in Sources */, 377FC7E1267A082600A6BBAF /* ChannelView.swift in Sources */, 37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */, 37C7A9042679059200E721B4 /* AVKeyValueStatus+String.swift in Sources */, @@ -717,7 +725,6 @@ 37AAF2A026741C97007FC770 /* SubscriptionsView.swift in Sources */, 3714167B267AA1CF006CA35D /* TrendingCountriesProvider.swift in Sources */, 377FC7DF267A082200A6BBAF /* VideosListView.swift in Sources */, - 37C7A1D8267CACE10010EAD6 /* TrendingCategorySelectionView.swift in Sources */, 37D4B19726717E1500C925CA /* Video.swift in Sources */, 37D4B0E42671614900C925CA /* PearvidiousApp.swift in Sources */, 37CEE4B92677B63F005A1EFE /* StreamResolution.swift in Sources */, @@ -736,7 +743,7 @@ 37EAD86C267B9C5600D9E01B /* SponsorBlockSegmentsProvider.swift in Sources */, 377FC7E7267A085600A6BBAF /* PlayerView.swift in Sources */, 37CEE4C22677B697005A1EFE /* Stream.swift in Sources */, - 37141678267A9AAD006CA35D /* TrendingState.swift in Sources */, + 3765788E2685487700D4EA09 /* PlaylistsProvider.swift in Sources */, 37D4B0E72671614900C925CA /* ContentView.swift in Sources */, 377FC7DD267A081A00A6BBAF /* PopularVideosView.swift in Sources */, 37141680267AB55D006CA35D /* TrendingVideosProvider.swift in Sources */, @@ -746,8 +753,10 @@ 37141670267A8ACC006CA35D /* TrendingView.swift in Sources */, 377FC7E2267A084A00A6BBAF /* VideoListRow.swift in Sources */, 37AAF2832673791F007FC770 /* SearchedVideosProvider.swift in Sources */, + 3765788A2685471400D4EA09 /* Playlist.swift in Sources */, 37AAF29126740715007FC770 /* AppState.swift in Sources */, 37AAF2952674086B007FC770 /* TabSelection.swift in Sources */, + 376578922685490700D4EA09 /* PlaylistsView.swift in Sources */, 37D4B1B12672A01000C925CA /* DataProvider.swift in Sources */, 37AAF28D2673ABD3007FC770 /* ChannelVideosProvider.swift in Sources */, 377FC7E8267A085D00A6BBAF /* PlayerViewController.swift in Sources */, @@ -796,10 +805,10 @@ 37CEE4BF2677B670005A1EFE /* AudioVideoStream.swift in Sources */, 37CEE4B72677B628005A1EFE /* StreamType.swift in Sources */, 3714166A267A83F9006CA35D /* StreamAVPlayerViewController.swift in Sources */, + 3765788F2685487700D4EA09 /* PlaylistsProvider.swift in Sources */, 37F4AE782682908700BD60EA /* VideoCellView.swift in Sources */, 37D4B19526717CE100C925CA /* PopularVideosProvider.swift in Sources */, 37AAF29E26741B5F007FC770 /* SubscriptionVideosProvider.swift in Sources */, - 37141679267A9AAD006CA35D /* TrendingState.swift in Sources */, 37F4AE7426828F0900BD60EA /* VideosCellsView.swift in Sources */, 376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */, 37D4B1842671684E00C925CA /* PlayerView.swift in Sources */, @@ -810,6 +819,7 @@ 37141671267A8ACC006CA35D /* TrendingView.swift in Sources */, 37AAF29226740715007FC770 /* AppState.swift in Sources */, 37EAD86D267B9C5600D9E01B /* SponsorBlockSegmentsProvider.swift in Sources */, + 3765788B2685471400D4EA09 /* Playlist.swift in Sources */, 3705B17C267B4D9A00704544 /* VisualEffectView.swift in Sources */, 37C7A1DE267CE9D90010EAD6 /* Profile.swift in Sources */, 3741B5302676213400125C5E /* PlayerViewController.swift in Sources */, @@ -821,6 +831,7 @@ 37AAF29A26740A01007FC770 /* VideosListView.swift in Sources */, 37AAF2962674086B007FC770 /* TabSelection.swift in Sources */, 37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */, + 376578932685490700D4EA09 /* PlaylistsView.swift in Sources */, 37CEE4C32677B697005A1EFE /* Stream.swift in Sources */, 37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */, 37AAF28E2673ABD3007FC770 /* ChannelVideosProvider.swift in Sources */, @@ -833,7 +844,6 @@ 37D4B1812671653A00C925CA /* ContentView.swift in Sources */, 37AAF2842673791F007FC770 /* SearchedVideosProvider.swift in Sources */, 37CEE4BB2677B63F005A1EFE /* StreamResolution.swift in Sources */, - 3705B17E267B4DDE00704544 /* TrendingCategorySelectionView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Shared/ContentView.swift b/Shared/ContentView.swift index 24c9cc06..14ff3fa9 100644 --- a/Shared/ContentView.swift +++ b/Shared/ContentView.swift @@ -2,9 +2,8 @@ import SwiftUI struct ContentView: View { @ObservedObject private var state = AppState() - @StateObject private var trendingState = TrendingState() - @State private var tabSelection = TabSelection.popular + @SceneStorage("tabSelection") var tabSelection = TabSelection.subscriptions var body: some View { NavigationView { @@ -27,13 +26,16 @@ struct ContentView: View { .tabItem { Text("Trending") } .tag(TabSelection.trending) + PlaylistsView(tabSelection: $tabSelection) + .tabItem { Text("Playlists") } + .tag(TabSelection.playlists) + SearchView(tabSelection: $tabSelection) .tabItem { Image(systemName: "magnifyingglass") } .tag(TabSelection.search) } } .environmentObject(state) - .environmentObject(trendingState) } } diff --git a/Shared/TabSelection.swift b/Shared/TabSelection.swift index cbea2c14..0d943749 100644 --- a/Shared/TabSelection.swift +++ b/Shared/TabSelection.swift @@ -1,5 +1,5 @@ import Foundation -enum TabSelection { - case subscriptions, popular, trending, channel, search +enum TabSelection: String { + case subscriptions, popular, trending, playlists, channel, search }