more responsive UI when Favorites are used.

- The reloading of items in the favorite widgets is now done async, so it does not block the UI when opening Home.
- Tasks that check for changes of the widget and favorites are now terminated when another view e.g. Subscriptions is opened.
- We only update the Favourites when the player is not in the foreground, to avoid unresponsiveness.
This commit is contained in:
Toni Förster 2024-05-24 13:49:07 +02:00
parent d6cfadab9a
commit 94f19d55c8
No known key found for this signature in database
GPG Key ID: 292F3E5086C83FC7
2 changed files with 83 additions and 39 deletions

View File

@ -88,28 +88,40 @@ struct FavoriteItemView: View {
reloadVisibleWatches() reloadVisibleWatches()
} else { } else {
resource?.addObserver(store) resource?.addObserver(store)
loadCacheAndResource() DispatchQueue.main.async {
self.loadCacheAndResource()
}
} }
} }
.onDisappear { .onDisappear {
resource?.removeObservers(ownedBy: store) resource?.removeObservers(ownedBy: store)
} }
.onChange(of: player.currentVideo) { _ in reloadVisibleWatches() } .onChange(of: player.currentVideo) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
.onChange(of: hideShorts) { _ in reloadVisibleWatches() } .onChange(of: hideShorts) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
.onChange(of: hideWatched) { _ in reloadVisibleWatches() } .onChange(of: hideWatched) { _ in if !player.presentingPlayer { reloadVisibleWatches() } }
.onChange(of: favoritesChanged) { _ in reloadVisibleWatches() } // Delay is necessary to update the list with the new items.
.onChange(of: favoritesChanged) { _ in if !player.presentingPlayer { Delay.by(1.0) { reloadVisibleWatches() } } }
.onChange(of: player.presentingPlayer) { _ in
if player.presentingPlayer {
resource?.removeObservers(ownedBy: store)
} else {
resource?.addObserver(store)
}
}
} }
} }
.id(watchModel.historyToken) .id(watchModel.historyToken)
.onChange(of: accounts.current) { _ in .onChange(of: accounts.current) { _ in
resource?.removeObservers(ownedBy: store) DispatchQueue.main.async {
resource?.addObserver(store)
loadCacheAndResource(force: true) loadCacheAndResource(force: true)
} }
}
.onChange(of: watchModel.historyToken) { _ in .onChange(of: watchModel.historyToken) { _ in
if !player.presentingPlayer {
reloadVisibleWatches() reloadVisibleWatches()
} }
} }
}
var emptyItemsText: String { var emptyItemsText: String {
var filterText = "" var filterText = ""
@ -159,6 +171,7 @@ struct FavoriteItemView: View {
} }
func reloadVisibleWatches() { func reloadVisibleWatches() {
DispatchQueue.main.async {
guard item.section == .history else { return } guard item.section == .history else { return }
visibleWatches = [] visibleWatches = []
@ -181,6 +194,7 @@ struct FavoriteItemView: View {
} }
} }
} }
}
var limitedItems: [ContentItem] { var limitedItems: [ContentItem] {
var items: [ContentItem] var items: [ContentItem]
@ -227,6 +241,9 @@ struct FavoriteItemView: View {
onSuccess = { response in onSuccess = { response in
if let videos: [Video] = response.typedContent() { if let videos: [Video] = response.typedContent() {
FeedCacheModel.shared.storeFeed(account: accounts.current, videos: videos) FeedCacheModel.shared.storeFeed(account: accounts.current, videos: videos)
DispatchQueue.main.async {
store.contentItems = contentItems
}
} }
} }
case let .channel(_, id, name): case let .channel(_, id, name):
@ -239,6 +256,7 @@ struct FavoriteItemView: View {
} }
onSuccess = { response in onSuccess = { response in
DispatchQueue.main.async {
if let channel: Channel = response.typedContent() { if let channel: Channel = response.typedContent() {
ChannelsCacheModel.shared.store(channel) ChannelsCacheModel.shared.store(channel)
store.contentItems = ContentItem.array(of: channel.videos) store.contentItems = ContentItem.array(of: channel.videos)
@ -254,6 +272,7 @@ struct FavoriteItemView: View {
store.contentItems = channelPage.results store.contentItems = channelPage.results
} }
} }
}
case let .channelPlaylist(_, id, title): case let .channelPlaylist(_, id, title):
if let cache = ChannelPlaylistsCacheModel.shared.retrievePlaylist(.init(id: id, title: title)), if let cache = ChannelPlaylistsCacheModel.shared.retrievePlaylist(.init(id: id, title: title)),
!cache.videos.isEmpty !cache.videos.isEmpty
@ -264,6 +283,9 @@ struct FavoriteItemView: View {
onSuccess = { response in onSuccess = { response in
if let playlist: ChannelPlaylist = response.typedContent() { if let playlist: ChannelPlaylist = response.typedContent() {
ChannelPlaylistsCacheModel.shared.storePlaylist(playlist: playlist) ChannelPlaylistsCacheModel.shared.storePlaylist(playlist: playlist)
DispatchQueue.main.async {
store.contentItems = contentItems
}
} }
} }
case let .playlist(_, id): case let .playlist(_, id):
@ -272,13 +294,17 @@ struct FavoriteItemView: View {
if let playlist = playlists.first(where: { $0.id == id }) { if let playlist = playlists.first(where: { $0.id == id }) {
contentItems = ContentItem.array(of: playlist.videos) contentItems = ContentItem.array(of: playlist.videos)
} }
DispatchQueue.main.async {
store.contentItems = contentItems
}
default: default:
contentItems = [] contentItems = []
}
if !contentItems.isEmpty { DispatchQueue.main.async {
store.contentItems = contentItems store.contentItems = contentItems
} }
}
if force { if force {
resource.load().onSuccess(onSuccess) resource.load().onSuccess(onSuccess)

View File

@ -5,9 +5,11 @@ import UniformTypeIdentifiers
struct HomeView: View { struct HomeView: View {
@ObservedObject private var accounts = AccountsModel.shared @ObservedObject private var accounts = AccountsModel.shared
@ObservedObject private var player = PlayerModel.shared
@State private var presentingHomeSettings = false @State private var presentingHomeSettings = false
@State private var favoritesChanged = false @State private var favoritesChanged = false
@State private var updateTask: Task<Void, Never>?
@FetchRequest(sortDescriptors: [.init(key: "watchedAt", ascending: false)]) @FetchRequest(sortDescriptors: [.init(key: "watchedAt", ascending: false)])
var watches: FetchedResults<Watch> var watches: FetchedResults<Watch>
@ -16,8 +18,6 @@ struct HomeView: View {
@State private var recentDocumentsID = UUID() @State private var recentDocumentsID = UUID()
#endif #endif
var favoritesObserver: Any?
#if !os(tvOS) #if !os(tvOS)
@Default(.favorites) private var favorites @Default(.favorites) private var favorites
@Default(.widgetsSettings) private var widgetsSettings @Default(.widgetsSettings) private var widgetsSettings
@ -124,6 +124,24 @@ struct HomeView: View {
} }
} }
} }
.onDisappear {
updateTask?.cancel()
}
.onChange(of: player.presentingPlayer) { _ in
if player.presentingPlayer {
updateTask?.cancel()
} else {
Task {
for await _ in Defaults.updates(.favorites) {
favoritesChanged.toggle()
}
for await _ in Defaults.updates(.widgetsSettings) {
favoritesChanged.toggle()
}
}
}
}
.redrawOn(change: favoritesChanged) .redrawOn(change: favoritesChanged)