Fix favorites view redrawing

This commit is contained in:
Arkadiusz Fal 2021-11-05 23:44:52 +01:00
parent ef9143263f
commit 9a4e404389
5 changed files with 75 additions and 71 deletions

View File

@ -273,6 +273,9 @@
37B17DA0268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */; }; 37B17DA0268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */; };
37B17DA1268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */; }; 37B17DA1268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */; };
37B17DA2268A1F8A006AEE9B /* VideoContextMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */; }; 37B17DA2268A1F8A006AEE9B /* VideoContextMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */; };
37B2631A2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B263192735EAAB00FE0D40 /* FavoriteResourceObserver.swift */; };
37B2631B2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B263192735EAAB00FE0D40 /* FavoriteResourceObserver.swift */; };
37B2631C2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B263192735EAAB00FE0D40 /* FavoriteResourceObserver.swift */; };
37B767DB2677C3CA0098BAA8 /* PlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */; }; 37B767DB2677C3CA0098BAA8 /* PlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */; };
37B767DC2677C3CA0098BAA8 /* PlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */; }; 37B767DC2677C3CA0098BAA8 /* PlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */; };
37B767DD2677C3CA0098BAA8 /* PlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */; }; 37B767DD2677C3CA0098BAA8 /* PlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */; };
@ -607,6 +610,7 @@
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsView.swift; sourceTree = "<group>"; }; 37AAF29F26741C97007FC770 /* SubscriptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsView.swift; sourceTree = "<group>"; };
37B044B626F7AB9000E1419D /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; }; 37B044B626F7AB9000E1419D /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoContextMenuView.swift; sourceTree = "<group>"; }; 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoContextMenuView.swift; sourceTree = "<group>"; };
37B263192735EAAB00FE0D40 /* FavoriteResourceObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteResourceObserver.swift; sourceTree = "<group>"; };
37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerModel.swift; sourceTree = "<group>"; }; 37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerModel.swift; sourceTree = "<group>"; };
37B81AF826D2C9A700675966 /* VideoPlayerSizeModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerSizeModifier.swift; sourceTree = "<group>"; }; 37B81AF826D2C9A700675966 /* VideoPlayerSizeModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerSizeModifier.swift; sourceTree = "<group>"; };
37B81AFB26D2C9C900675966 /* VideoDetailsPaddingModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDetailsPaddingModifier.swift; sourceTree = "<group>"; }; 37B81AFB26D2C9C900675966 /* VideoDetailsPaddingModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDetailsPaddingModifier.swift; sourceTree = "<group>"; };
@ -957,9 +961,10 @@
3788AC2126F683AB00F6BAA9 /* Favorites */ = { 3788AC2126F683AB00F6BAA9 /* Favorites */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
37BF661E27308884008CCFB0 /* DropFavoriteOutside.swift */,
37BF661B27308859008CCFB0 /* DropFavorite.swift */, 37BF661B27308859008CCFB0 /* DropFavorite.swift */,
37BF661E27308884008CCFB0 /* DropFavoriteOutside.swift */,
3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */, 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */,
37B263192735EAAB00FE0D40 /* FavoriteResourceObserver.swift */,
37A9965D26D6F9B9006E3224 /* FavoritesView.swift */, 37A9965D26D6F9B9006E3224 /* FavoritesView.swift */,
); );
path = Favorites; path = Favorites;
@ -1756,6 +1761,7 @@
37C3A24927235FAA0087A57A /* ChannelPlaylistCell.swift in Sources */, 37C3A24927235FAA0087A57A /* ChannelPlaylistCell.swift in Sources */,
373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */, 373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
37141673267A8E10006CA35D /* Country.swift in Sources */, 37141673267A8E10006CA35D /* Country.swift in Sources */,
37B2631A2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */,
3748186E26A769D60084E870 /* DetailBadge.swift in Sources */, 3748186E26A769D60084E870 /* DetailBadge.swift in Sources */,
376BE50B27349108009AD608 /* BrowsingSettings.swift in Sources */, 376BE50B27349108009AD608 /* BrowsingSettings.swift in Sources */,
37AAF2A026741C97007FC770 /* SubscriptionsView.swift in Sources */, 37AAF2A026741C97007FC770 /* SubscriptionsView.swift in Sources */,
@ -1887,6 +1893,7 @@
37732FF12703A26300F04329 /* AccountValidationStatus.swift in Sources */, 37732FF12703A26300F04329 /* AccountValidationStatus.swift in Sources */,
37BA794C26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */, 37BA794C26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */,
37CC3F46270CE30600608308 /* PlayerQueueItem.swift in Sources */, 37CC3F46270CE30600608308 /* PlayerQueueItem.swift in Sources */,
37B2631B2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */,
3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */, 3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */,
376BE50C27349108009AD608 /* BrowsingSettings.swift in Sources */, 376BE50C27349108009AD608 /* BrowsingSettings.swift in Sources */,
37D4B19826717E1500C925CA /* Video.swift in Sources */, 37D4B19826717E1500C925CA /* Video.swift in Sources */,
@ -2016,6 +2023,7 @@
37484C3326FCB8F900287258 /* AccountValidator.swift in Sources */, 37484C3326FCB8F900287258 /* AccountValidator.swift in Sources */,
37CEE4C32677B697005A1EFE /* Stream.swift in Sources */, 37CEE4C32677B697005A1EFE /* Stream.swift in Sources */,
37F64FE626FE70A60081B69E /* RedrawOnModifier.swift in Sources */, 37F64FE626FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
37B2631C2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */,
37484C2B26FC83FF00287258 /* AccountForm.swift in Sources */, 37484C2B26FC83FF00287258 /* AccountForm.swift in Sources */,
37FB2860272225E800A57617 /* ContentItemView.swift in Sources */, 37FB2860272225E800A57617 /* ContentItemView.swift in Sources */,
374C053727242D9F009BDDBE /* ServicesSettings.swift in Sources */, 374C053727242D9F009BDDBE /* ServicesSettings.swift in Sources */,

View File

@ -3,42 +3,24 @@ import Siesta
import SwiftUI import SwiftUI
import UniformTypeIdentifiers 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 { struct FavoriteItemView: View {
let item: FavoriteItem let item: FavoriteItem
let resource: Resource?
@StateObject private var store = FavoriteResourceObserver() @StateObject private var store = FavoriteResourceObserver()
@Binding private var favorites: [FavoriteItem] @Default(.favorites) private var favorites
@Binding private var dragging: FavoriteItem? @Binding private var dragging: FavoriteItem?
@EnvironmentObject<PlaylistsModel> private var playlistsModel @EnvironmentObject<AccountsModel> private var accounts
@EnvironmentObject<PlaylistsModel> private var playlists
private var favoritesModel = FavoritesModel.shared
init( init(
item: FavoriteItem, item: FavoriteItem,
resource: Resource?,
favorites: Binding<[FavoriteItem]>,
dragging: Binding<FavoriteItem?> dragging: Binding<FavoriteItem?>
) { ) {
self.item = item self.item = item
self.resource = resource
_favorites = favorites
_dragging = dragging _dragging = dragging
} }
@ -47,10 +29,9 @@ struct FavoriteItemView: View {
Text(label) Text(label)
.font(.title3.bold()) .font(.title3.bold())
.foregroundColor(.secondary) .foregroundColor(.secondary)
.contextMenu { .contextMenu {
Button { Button {
FavoritesModel.shared.remove(item) favoritesModel.remove(item)
} label: { } label: {
Label("Remove from Favorites", systemImage: "trash") Label("Remove from Favorites", systemImage: "trash")
} }
@ -62,7 +43,7 @@ struct FavoriteItemView: View {
.padding(.leading, 15) .padding(.leading, 15)
#endif #endif
HorizontalCells(items: store.videos.map { ContentItem(video: $0) }) HorizontalCells(items: store.contentItems)
} }
.contentShape(Rectangle()) .contentShape(Rectangle())
@ -83,9 +64,40 @@ struct FavoriteItemView: View {
#endif #endif
} }
var label: String { private var resource: 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
}
private var label: String {
if case let .playlist(id) = item.section { if case let .playlist(id) = item.section {
return playlistsModel.find(id: id)?.title ?? "Playlist" return playlists.find(id: id)?.title ?? "Playlist"
} }
return item.section.label return item.section.label

View File

@ -0,0 +1,22 @@
import Foundation
import Siesta
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
}
}
var contentItems: [ContentItem] {
videos.map { ContentItem(video: $0) }
}
}

View File

@ -10,20 +10,12 @@ struct FavoritesView: View {
@State private var dragging: FavoriteItem? @State private var dragging: FavoriteItem?
@State private var presentingEditFavorites = false @State private var presentingEditFavorites = false
@Default(.favorites) private var favorites
var body: some View { var body: some View {
PlayerControlsView { PlayerControlsView {
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
if !accounts.current.isNil { if !accounts.current.isNil {
VStack(alignment: .leading, spacing: 0) { ForEach(Defaults[.favorites]) { item in
ForEach(favorites) { item in FavoriteItemView(item: item, dragging: $dragging)
VStack {
if let resource = resource(item) {
FavoriteItemView(item: item, resource: resource, favorites: $favorites, dragging: $dragging)
}
}
}
} }
#if os(tvOS) #if os(tvOS)
@ -35,6 +27,7 @@ struct FavoritesView: View {
#endif #endif
} }
} }
.redrawOn(change: presentingEditFavorites)
#if os(tvOS) #if os(tvOS)
.sheet(isPresented: $presentingEditFavorites) { .sheet(isPresented: $presentingEditFavorites) {
EditFavorites() EditFavorites()
@ -50,37 +43,6 @@ struct FavoritesView: View {
#endif #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 { struct Favorites_Previews: PreviewProvider {

View File

@ -267,7 +267,7 @@ struct VideoCell: View {
} }
.retryOnAppear(false) .retryOnAppear(false)
.onFailure { _ in .onFailure { _ in
thumbnails.insertUnloadable(url) thumbnails.insertUnloadable(url)
} }
.indicator(.activity) .indicator(.activity)