mirror of
https://github.com/yattee/yattee.git
synced 2025-08-09 04:04:07 +00:00
Managing Favorites sections
This commit is contained in:
@@ -35,6 +35,10 @@ extension Defaults.Keys {
|
||||
static let sponsorBlockInstance = Key<String>("sponsorBlockInstance", default: "https://sponsor.ajay.app")
|
||||
static let sponsorBlockCategories = Key<Set<String>>("sponsorBlockCategories", default: Set(SponsorBlockAPI.categories))
|
||||
|
||||
static let favorites = Key<[FavoriteItem]>("favorites", default: [
|
||||
.init(section: .trending("US", nil))
|
||||
])
|
||||
|
||||
static let quality = Key<Stream.ResolutionSetting>("quality", default: .hd720pFirstThenBest)
|
||||
|
||||
static let recentlyOpened = Key<[RecentItem]>("recentlyOpened", default: [])
|
||||
|
35
Shared/Favorites/DropFavorite.swift
Normal file
35
Shared/Favorites/DropFavorite.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct DropFavorite: DropDelegate {
|
||||
let item: FavoriteItem
|
||||
@Binding var favorites: [FavoriteItem]
|
||||
@Binding var current: FavoriteItem?
|
||||
|
||||
func dropEntered(info _: DropInfo) {
|
||||
guard item != current else {
|
||||
return
|
||||
}
|
||||
|
||||
let from = favorites.firstIndex(of: current!)!
|
||||
let to = favorites.firstIndex(of: item)!
|
||||
|
||||
guard favorites[to].id != current!.id else {
|
||||
return
|
||||
}
|
||||
|
||||
favorites.move(
|
||||
fromOffsets: IndexSet(integer: from),
|
||||
toOffset: to > from ? to + 1 : to
|
||||
)
|
||||
}
|
||||
|
||||
func dropUpdated(info _: DropInfo) -> DropProposal? {
|
||||
DropProposal(operation: .move)
|
||||
}
|
||||
|
||||
func performDrop(info _: DropInfo) -> Bool {
|
||||
current = nil
|
||||
return true
|
||||
}
|
||||
}
|
11
Shared/Favorites/DropFavoriteOutside.swift
Normal file
11
Shared/Favorites/DropFavoriteOutside.swift
Normal file
@@ -0,0 +1,11 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct DropFavoriteOutside: DropDelegate {
|
||||
@Binding var current: FavoriteItem?
|
||||
|
||||
func performDrop(info _: DropInfo) -> Bool {
|
||||
current = nil
|
||||
return true
|
||||
}
|
||||
}
|
93
Shared/Favorites/FavoriteItemView.swift
Normal file
93
Shared/Favorites/FavoriteItemView.swift
Normal file
@@ -0,0 +1,93 @@
|
||||
import Defaults
|
||||
import Siesta
|
||||
import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
final class FavoriteResourceObserver: ObservableObject, ResourceObserver {
|
||||
@Published var videos = [Video]()
|
||||
|
||||
func resourceChanged(_ resource: Resource, event _: ResourceEvent) {
|
||||
if let videos: [Video] = resource.typedContent() {
|
||||
self.videos = videos
|
||||
} else if let channel: Channel = resource.typedContent() {
|
||||
videos = channel.videos
|
||||
} else if let playlist: ChannelPlaylist = resource.typedContent() {
|
||||
videos = playlist.videos
|
||||
} else if let playlist: Playlist = resource.typedContent() {
|
||||
videos = playlist.videos
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FavoriteItemView: View {
|
||||
let item: FavoriteItem
|
||||
let resource: Resource?
|
||||
|
||||
@StateObject private var store = FavoriteResourceObserver()
|
||||
|
||||
@Binding private var favorites: [FavoriteItem]
|
||||
@Binding private var dragging: FavoriteItem?
|
||||
|
||||
@EnvironmentObject<PlaylistsModel> private var playlistsModel
|
||||
|
||||
init(
|
||||
item: FavoriteItem,
|
||||
resource: Resource?,
|
||||
favorites: Binding<[FavoriteItem]>,
|
||||
dragging: Binding<FavoriteItem?>
|
||||
) {
|
||||
self.item = item
|
||||
self.resource = resource
|
||||
_favorites = favorites
|
||||
_dragging = dragging
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(label)
|
||||
.font(.title3.bold())
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
.contextMenu {
|
||||
Button {
|
||||
FavoritesModel.shared.remove(item)
|
||||
} label: {
|
||||
Label("Remove from Favorites", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
#if os(tvOS)
|
||||
.padding(.leading, 40)
|
||||
#else
|
||||
.padding(.leading, 15)
|
||||
#endif
|
||||
|
||||
HorizontalCells(items: store.videos.map { ContentItem(video: $0) })
|
||||
}
|
||||
|
||||
.contentShape(Rectangle())
|
||||
.opacity(dragging?.id == item.id ? 0.5 : 1)
|
||||
.onAppear {
|
||||
resource?.addObserver(store)
|
||||
resource?.loadIfNeeded()
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.onDrag {
|
||||
dragging = item
|
||||
return NSItemProvider(object: item.id as NSString)
|
||||
}
|
||||
.onDrop(
|
||||
of: [UTType.text],
|
||||
delegate: DropFavorite(item: item, favorites: $favorites, current: $dragging)
|
||||
)
|
||||
#endif
|
||||
}
|
||||
|
||||
var label: String {
|
||||
if case let .playlist(id) = item.section {
|
||||
return playlistsModel.find(id: id)?.title ?? "Unknown Playlist"
|
||||
}
|
||||
|
||||
return item.section.label
|
||||
}
|
||||
}
|
91
Shared/Favorites/FavoritesView.swift
Normal file
91
Shared/Favorites/FavoritesView.swift
Normal file
@@ -0,0 +1,91 @@
|
||||
import Defaults
|
||||
import Siesta
|
||||
import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
struct FavoritesView: View {
|
||||
@EnvironmentObject<AccountsModel> private var accounts
|
||||
@EnvironmentObject<PlaylistsModel> private var playlists
|
||||
|
||||
@State private var dragging: FavoriteItem?
|
||||
@State private var presentingEditFavorites = false
|
||||
|
||||
@Default(.favorites) private var favorites
|
||||
|
||||
var body: some View {
|
||||
PlayerControlsView {
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
if !accounts.current.isNil {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(favorites) { item in
|
||||
VStack {
|
||||
if let resource = resource(item) {
|
||||
FavoriteItemView(item: item, resource: resource, favorites: $favorites, dragging: $dragging)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if os(tvOS)
|
||||
Button {
|
||||
presentingEditFavorites = true
|
||||
} label: {
|
||||
Text("Edit Favorites...")
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.sheet(isPresented: $presentingEditFavorites) {
|
||||
EditFavorites()
|
||||
}
|
||||
.edgesIgnoringSafeArea(.horizontal)
|
||||
#else
|
||||
.onDrop(of: [UTType.text], delegate: DropFavoriteOutside(current: $dragging))
|
||||
.navigationTitle("Favorites")
|
||||
#endif
|
||||
#if os(macOS)
|
||||
.background()
|
||||
.frame(minWidth: 360)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
func resource(_ item: FavoriteItem) -> Resource? {
|
||||
switch item.section {
|
||||
case .subscriptions:
|
||||
if accounts.app.supportsSubscriptions {
|
||||
return accounts.api.feed
|
||||
}
|
||||
|
||||
case .popular:
|
||||
if accounts.app.supportsPopular {
|
||||
return accounts.api.popular
|
||||
}
|
||||
|
||||
case let .trending(country, category):
|
||||
let trendingCountry = Country(rawValue: country)!
|
||||
let trendingCategory = category.isNil ? nil : TrendingCategory(rawValue: category!)!
|
||||
|
||||
return accounts.api.trending(country: trendingCountry, category: trendingCategory)
|
||||
|
||||
case let .channel(id, _):
|
||||
return accounts.api.channelVideos(id)
|
||||
|
||||
case let .channelPlaylist(id, _):
|
||||
return accounts.api.channelPlaylist(id)
|
||||
|
||||
case let .playlist(id):
|
||||
return accounts.api.playlist(id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
struct Favorites_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
FavoritesView()
|
||||
.injectFixtureEnvironmentObjects()
|
||||
}
|
||||
}
|
@@ -11,14 +11,14 @@ struct AppTabNavigation: View {
|
||||
var body: some View {
|
||||
TabView(selection: navigation.tabSelectionBinding) {
|
||||
NavigationView {
|
||||
LazyView(WatchNowView())
|
||||
LazyView(FavoritesView())
|
||||
.toolbar { toolbarContent }
|
||||
}
|
||||
.tabItem {
|
||||
Label("Watch Now", systemImage: "play.circle")
|
||||
.accessibility(label: Text("Subscriptions"))
|
||||
Label("Favorites", systemImage: "heart")
|
||||
.accessibility(label: Text("Favorites"))
|
||||
}
|
||||
.tag(TabSelection.watchNow)
|
||||
.tag(TabSelection.favorites)
|
||||
|
||||
if accounts.app.supportsSubscriptions {
|
||||
NavigationView {
|
||||
|
@@ -28,9 +28,9 @@ struct Sidebar: View {
|
||||
|
||||
var mainNavigationLinks: some View {
|
||||
Section("Videos") {
|
||||
NavigationLink(destination: LazyView(WatchNowView()), tag: TabSelection.watchNow, selection: $navigation.tabSelection) {
|
||||
Label("Watch Now", systemImage: "play.circle")
|
||||
.accessibility(label: Text("Watch Now"))
|
||||
NavigationLink(destination: LazyView(FavoritesView()), tag: TabSelection.favorites, selection: $navigation.tabSelection) {
|
||||
Label("Favorites", systemImage: "heart")
|
||||
.accessibility(label: Text("Favorites"))
|
||||
}
|
||||
if accounts.app.supportsSubscriptions && accounts.signedIn {
|
||||
NavigationLink(destination: LazyView(SubscriptionsView()), tag: TabSelection.subscriptions, selection: $navigation.tabSelection) {
|
||||
|
@@ -13,13 +13,16 @@ struct VideoPlayerView: View {
|
||||
#endif
|
||||
}
|
||||
|
||||
@State private var playerSize: CGSize = .zero
|
||||
@State private var fullScreen = false
|
||||
|
||||
#if os(iOS)
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||
|
||||
private var idiom: UIUserInterfaceIdiom {
|
||||
UIDevice.current.userInterfaceIdiom
|
||||
}
|
||||
#endif
|
||||
|
||||
@EnvironmentObject<PlayerModel> private var player
|
||||
@@ -75,12 +78,6 @@ struct VideoPlayerView: View {
|
||||
#endif
|
||||
|
||||
.background(.black)
|
||||
.onAppear {
|
||||
self.playerSize = geometry.size
|
||||
}
|
||||
.onChange(of: geometry.size) { size in
|
||||
self.playerSize = size
|
||||
}
|
||||
|
||||
Group {
|
||||
#if os(iOS)
|
||||
@@ -134,7 +131,7 @@ struct VideoPlayerView: View {
|
||||
|
||||
#if os(iOS)
|
||||
var sidebarQueue: Bool {
|
||||
horizontalSizeClass == .regular && playerSize.width > 750
|
||||
horizontalSizeClass == .regular && idiom == .pad
|
||||
}
|
||||
|
||||
var sidebarQueueBinding: Binding<Bool> {
|
||||
|
@@ -75,6 +75,8 @@ struct PlaylistsView: View {
|
||||
editPlaylistButton
|
||||
}
|
||||
#endif
|
||||
FavoriteButton(item: FavoriteItem(section: .playlist(selectedPlaylistID)))
|
||||
|
||||
newPlaylistButton
|
||||
}
|
||||
|
||||
@@ -139,6 +141,11 @@ struct PlaylistsView: View {
|
||||
editPlaylistButton
|
||||
}
|
||||
|
||||
if let playlist = currentPlaylist {
|
||||
FavoriteButton(item: FavoriteItem(section: .playlist(playlist.id)))
|
||||
.labelStyle(.iconOnly)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
newPlaylistButton
|
||||
|
@@ -95,6 +95,8 @@ struct ServicesSettings: View {
|
||||
|
||||
struct ServicesSettings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ServicesSettings()
|
||||
VStack {
|
||||
ServicesSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,9 +11,11 @@ struct TrendingView: View {
|
||||
|
||||
@State private var presentingCountrySelection = false
|
||||
|
||||
@State private var favoriteItem: FavoriteItem?
|
||||
|
||||
@EnvironmentObject<AccountsModel> private var accounts
|
||||
|
||||
var popular: [ContentItem] {
|
||||
var trending: [ContentItem] {
|
||||
ContentItem.array(of: store.collection)
|
||||
}
|
||||
|
||||
@@ -36,12 +38,12 @@ struct TrendingView: View {
|
||||
VStack(alignment: .center, spacing: 0) {
|
||||
#if os(tvOS)
|
||||
toolbar
|
||||
HorizontalCells(items: popular)
|
||||
HorizontalCells(items: trending)
|
||||
.padding(.top, 40)
|
||||
|
||||
Spacer()
|
||||
#else
|
||||
VerticalCells(items: popular)
|
||||
VerticalCells(items: trending)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -62,6 +64,11 @@ struct TrendingView: View {
|
||||
.toolbar {
|
||||
#if os(macOS)
|
||||
ToolbarItemGroup {
|
||||
if let favoriteItem = favoriteItem {
|
||||
FavoriteButton(item: favoriteItem)
|
||||
.id(favoriteItem.id)
|
||||
}
|
||||
|
||||
if accounts.app.supportsTrendingCategories {
|
||||
categoryButton
|
||||
}
|
||||
@@ -70,8 +77,8 @@ struct TrendingView: View {
|
||||
#elseif os(iOS)
|
||||
ToolbarItemGroup(placement: .bottomBar) {
|
||||
Group {
|
||||
if accounts.app.supportsTrendingCategories {
|
||||
HStack {
|
||||
HStack {
|
||||
if accounts.app.supportsTrendingCategories {
|
||||
Text("Category")
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
@@ -80,7 +87,14 @@ struct TrendingView: View {
|
||||
// force redraw of the view when it changes
|
||||
.id(UUID())
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if let favoriteItem = favoriteItem {
|
||||
FavoriteButton(item: favoriteItem)
|
||||
.id(favoriteItem.id)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
@@ -96,6 +110,7 @@ struct TrendingView: View {
|
||||
}
|
||||
.onChange(of: resource) { _ in
|
||||
resource.load()
|
||||
updateFavoriteItem()
|
||||
}
|
||||
.onAppear {
|
||||
if videos.isEmpty {
|
||||
@@ -104,10 +119,12 @@ struct TrendingView: View {
|
||||
} else {
|
||||
store.replace(videos)
|
||||
}
|
||||
|
||||
updateFavoriteItem()
|
||||
}
|
||||
}
|
||||
|
||||
var toolbar: some View {
|
||||
private var toolbar: some View {
|
||||
HStack {
|
||||
if accounts.app.supportsTrendingCategories {
|
||||
HStack {
|
||||
@@ -128,17 +145,25 @@ struct TrendingView: View {
|
||||
|
||||
countryButton
|
||||
}
|
||||
|
||||
#if os(tvOS)
|
||||
if let favoriteItem = favoriteItem {
|
||||
FavoriteButton(item: favoriteItem)
|
||||
.id(favoriteItem.id)
|
||||
.labelStyle(.iconOnly)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
var categoryButton: some View {
|
||||
private var categoryButton: some View {
|
||||
#if os(tvOS)
|
||||
Button(category.name) {
|
||||
self.category = category.next()
|
||||
}
|
||||
.contextMenu {
|
||||
ForEach(TrendingCategory.allCases) { category in
|
||||
Button(category.name) { self.category = category }
|
||||
Button(category.controlLabel) { self.category = category }
|
||||
}
|
||||
|
||||
Button("Cancel", role: .cancel) {}
|
||||
@@ -147,13 +172,13 @@ struct TrendingView: View {
|
||||
#else
|
||||
Picker("Category", selection: $category) {
|
||||
ForEach(TrendingCategory.allCases) { category in
|
||||
Text(category.name).tag(category)
|
||||
Text(category.controlLabel).tag(category)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
var countryButton: some View {
|
||||
private var countryButton: some View {
|
||||
Button(action: {
|
||||
presentingCountrySelection.toggle()
|
||||
resource.removeObservers(ownedBy: store)
|
||||
@@ -161,6 +186,10 @@ struct TrendingView: View {
|
||||
Text("\(country.flag) \(country.id)")
|
||||
}
|
||||
}
|
||||
|
||||
private func updateFavoriteItem() {
|
||||
favoriteItem = FavoriteItem(section: .trending(country.rawValue, category.rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
struct TrendingView_Previews: PreviewProvider {
|
||||
|
@@ -143,24 +143,18 @@ struct VideoCell: View {
|
||||
#endif
|
||||
.padding(.bottom, 4)
|
||||
|
||||
Group {
|
||||
if additionalDetailsAvailable {
|
||||
HStack(spacing: 8) {
|
||||
if let date = video.publishedDate {
|
||||
Image(systemName: "calendar")
|
||||
Text(date)
|
||||
}
|
||||
HStack(spacing: 8) {
|
||||
if let date = video.publishedDate {
|
||||
Image(systemName: "calendar")
|
||||
Text(date)
|
||||
}
|
||||
|
||||
if video.views > 0 {
|
||||
Image(systemName: "eye")
|
||||
Text(video.viewsCount!)
|
||||
}
|
||||
}
|
||||
.foregroundColor(.secondary)
|
||||
} else {
|
||||
Spacer()
|
||||
if video.views > 0 {
|
||||
Image(systemName: "eye")
|
||||
Text(video.viewsCount!)
|
||||
}
|
||||
}
|
||||
.foregroundColor(.secondary)
|
||||
.frame(minHeight: 30, alignment: .top)
|
||||
#if os(tvOS)
|
||||
.padding(.bottom, 10)
|
||||
|
@@ -40,9 +40,16 @@ struct ChannelPlaylistView: View {
|
||||
var content: some View {
|
||||
VStack(alignment: .leading) {
|
||||
#if os(tvOS)
|
||||
Text(playlist.title)
|
||||
.font(.title2)
|
||||
.frame(alignment: .leading)
|
||||
HStack {
|
||||
Text(playlist.title)
|
||||
.font(.title2)
|
||||
.frame(alignment: .leading)
|
||||
|
||||
Spacer()
|
||||
|
||||
FavoriteButton(item: FavoriteItem(section: .channelPlaylist(playlist.id, playlist.title)))
|
||||
.labelStyle(.iconOnly)
|
||||
}
|
||||
#endif
|
||||
VerticalCells(items: items)
|
||||
}
|
||||
@@ -66,12 +73,8 @@ struct ChannelPlaylistView: View {
|
||||
)
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
if inNavigationView {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
ToolbarItem {
|
||||
FavoriteButton(item: FavoriteItem(section: .channelPlaylist(playlist.id, playlist.title)))
|
||||
}
|
||||
}
|
||||
.navigationTitle(playlist.title)
|
||||
|
@@ -51,6 +51,9 @@ struct ChannelVideosView: View {
|
||||
|
||||
Spacer()
|
||||
|
||||
FavoriteButton(item: FavoriteItem(section: .channel(channel.id, channel.name)))
|
||||
.labelStyle(.iconOnly)
|
||||
|
||||
if let subscribers = store.item?.subscriptionsString {
|
||||
Text("**\(subscribers)** subscribers")
|
||||
.foregroundColor(.secondary)
|
||||
@@ -87,14 +90,8 @@ struct ChannelVideosView: View {
|
||||
.opacity(store.item?.subscriptionsString != nil ? 1 : 0)
|
||||
|
||||
subscriptionToggleButton
|
||||
}
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
if inNavigationView {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
FavoriteButton(item: FavoriteItem(section: .channel(channel.id, channel.name)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
Shared/Views/FavoriteButton.swift
Normal file
25
Shared/Views/FavoriteButton.swift
Normal file
@@ -0,0 +1,25 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct FavoriteButton: View {
|
||||
let item: FavoriteItem
|
||||
let favorites = FavoritesModel.shared
|
||||
|
||||
@State private var isFavorite = false
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
favorites.toggle(item)
|
||||
isFavorite.toggle()
|
||||
} label: {
|
||||
if isFavorite {
|
||||
Label("Remove from Favorites", systemImage: "heart.fill")
|
||||
} else {
|
||||
Label("Add to Favorites", systemImage: "heart")
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
isFavorite = favorites.contains(item)
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,5 +19,10 @@ struct PlaylistVideosView: View {
|
||||
.navigationTitle("\(playlist.title) Playlist")
|
||||
#endif
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem {
|
||||
FavoriteButton(item: FavoriteItem(section: .playlist(playlist.id)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,5 +25,10 @@ struct PopularView: View {
|
||||
.navigationTitle("Popular")
|
||||
#endif
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .automatic) {
|
||||
FavoriteButton(item: FavoriteItem(section: .popular))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,11 @@ struct SubscriptionsView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .automatic) {
|
||||
FavoriteButton(item: FavoriteItem(section: .subscriptions))
|
||||
}
|
||||
}
|
||||
.refreshable {
|
||||
loadResources(force: true)
|
||||
}
|
||||
|
@@ -1,28 +0,0 @@
|
||||
import Defaults
|
||||
import Siesta
|
||||
import SwiftUI
|
||||
|
||||
struct WatchNowSection: View {
|
||||
let resource: Resource?
|
||||
let label: String
|
||||
|
||||
@StateObject private var store = Store<[Video]>()
|
||||
|
||||
@EnvironmentObject<AccountsModel> private var accounts
|
||||
|
||||
init(resource: Resource?, label: String) {
|
||||
self.resource = resource
|
||||
self.label = label
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
WatchNowSectionBody(label: label, videos: store.collection)
|
||||
.onAppear {
|
||||
resource?.addObserver(store)
|
||||
resource?.loadIfNeeded()
|
||||
}
|
||||
.onChange(of: accounts.current) { _ in
|
||||
resource?.load()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
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
|
||||
|
||||
HorizontalCells(items: ContentItem.array(of: videos))
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
import Defaults
|
||||
import Siesta
|
||||
import SwiftUI
|
||||
|
||||
struct WatchNowView: View {
|
||||
@EnvironmentObject<AccountsModel> private var accounts
|
||||
|
||||
var body: some View {
|
||||
PlayerControlsView {
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
if !accounts.current.isNil {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
if accounts.api.signedIn {
|
||||
WatchNowSection(resource: accounts.api.feed, label: "Subscriptions")
|
||||
}
|
||||
if accounts.app.supportsPopular {
|
||||
WatchNowSection(resource: accounts.api.popular, label: "Popular")
|
||||
}
|
||||
WatchNowSection(resource: accounts.api.trending(country: .pl, category: .default), label: "Trending")
|
||||
if accounts.app.supportsTrendingCategories {
|
||||
WatchNowSection(resource: accounts.api.trending(country: .pl, category: .movies), label: "Movies")
|
||||
WatchNowSection(resource: accounts.api.trending(country: .pl, category: .music), label: "Music")
|
||||
}
|
||||
|
||||
// TODO: adding sections to view
|
||||
// ===================
|
||||
// WatchNowPlaylistSection(id: "IVPLmRFYLGYZpq61SpujNw3EKbzzGNvoDmH")
|
||||
// WatchNowSection(resource: api.channelVideos("UCBJycsmduvYEL83R_U4JriQ"), label: "MKBHD")
|
||||
}
|
||||
}
|
||||
}
|
||||
.id(UUID())
|
||||
#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()
|
||||
.injectFixtureEnvironmentObjects()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user