mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
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:
parent
d6cfadab9a
commit
94f19d55c8
@ -88,26 +88,38 @@ 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
|
||||||
reloadVisibleWatches()
|
if !player.presentingPlayer {
|
||||||
|
reloadVisibleWatches()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,24 +171,26 @@ struct FavoriteItemView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func reloadVisibleWatches() {
|
func reloadVisibleWatches() {
|
||||||
guard item.section == .history else { return }
|
DispatchQueue.main.async {
|
||||||
|
guard item.section == .history else { return }
|
||||||
|
|
||||||
visibleWatches = []
|
visibleWatches = []
|
||||||
|
|
||||||
let watches = Array(
|
let watches = Array(
|
||||||
watches
|
watches
|
||||||
.filter { $0.videoID != player.currentVideo?.videoID && itemVisible(.init(video: $0.video)) }
|
.filter { $0.videoID != player.currentVideo?.videoID && itemVisible(.init(video: $0.video)) }
|
||||||
.prefix(favoritesModel.limit(item))
|
.prefix(favoritesModel.limit(item))
|
||||||
)
|
)
|
||||||
let last = watches.last
|
let last = watches.last
|
||||||
|
|
||||||
for watch in watches {
|
for watch in watches {
|
||||||
player.loadHistoryVideoDetails(watch) {
|
player.loadHistoryVideoDetails(watch) {
|
||||||
guard let video = player.historyVideo(watch.videoID), itemVisible(.init(video: video)) else { return }
|
guard let video = player.historyVideo(watch.videoID), itemVisible(.init(video: video)) else { return }
|
||||||
visibleWatches.append(watch)
|
visibleWatches.append(watch)
|
||||||
|
|
||||||
if watch == last {
|
if watch == last {
|
||||||
visibleWatches.sort { $0.watchedAt ?? Date() > $1.watchedAt ?? Date() }
|
visibleWatches.sort { $0.watchedAt ?? Date() > $1.watchedAt ?? Date() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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,19 +256,21 @@ struct FavoriteItemView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSuccess = { response in
|
onSuccess = { response in
|
||||||
if let channel: Channel = response.typedContent() {
|
DispatchQueue.main.async {
|
||||||
ChannelsCacheModel.shared.store(channel)
|
if let channel: Channel = response.typedContent() {
|
||||||
store.contentItems = ContentItem.array(of: channel.videos)
|
|
||||||
} else if let videos: [Video] = response.typedContent() {
|
|
||||||
channel.videos = videos
|
|
||||||
ChannelsCacheModel.shared.store(channel)
|
|
||||||
store.contentItems = ContentItem.array(of: videos)
|
|
||||||
} else if let channelPage: ChannelPage = response.typedContent() {
|
|
||||||
if let channel = channelPage.channel {
|
|
||||||
ChannelsCacheModel.shared.store(channel)
|
ChannelsCacheModel.shared.store(channel)
|
||||||
}
|
store.contentItems = ContentItem.array(of: channel.videos)
|
||||||
|
} else if let videos: [Video] = response.typedContent() {
|
||||||
|
channel.videos = videos
|
||||||
|
ChannelsCacheModel.shared.store(channel)
|
||||||
|
store.contentItems = ContentItem.array(of: videos)
|
||||||
|
} else if let channelPage: ChannelPage = response.typedContent() {
|
||||||
|
if let channel = channelPage.channel {
|
||||||
|
ChannelsCacheModel.shared.store(channel)
|
||||||
|
}
|
||||||
|
|
||||||
store.contentItems = channelPage.results
|
store.contentItems = channelPage.results
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .channelPlaylist(_, id, title):
|
case let .channelPlaylist(_, id, title):
|
||||||
@ -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,12 +294,16 @@ 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 {
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user