Caching for favorites

This commit is contained in:
Arkadiusz Fal 2022-12-16 12:31:43 +01:00
parent a2c69e0fed
commit b8f693e213
4 changed files with 75 additions and 26 deletions

View File

@ -40,7 +40,7 @@ struct Playlist: Identifiable, Equatable, Hashable {
} }
var json: JSON { var json: JSON {
return [ [
"id": id, "id": id,
"title": title, "title": title,
"visibility": visibility.rawValue, "visibility": visibility.rawValue,
@ -51,7 +51,7 @@ struct Playlist: Identifiable, Equatable, Hashable {
} }
static func from(_ json: JSON) -> Self { static func from(_ json: JSON) -> Self {
return .init( .init(
id: json["id"].stringValue, id: json["id"].stringValue,
title: json["title"].stringValue, title: json["title"].stringValue,
visibility: .init(rawValue: json["visibility"].stringValue) ?? .public, visibility: .init(rawValue: json["visibility"].stringValue) ?? .public,

View File

@ -38,13 +38,15 @@ final class PlaylistsModel: ObservableObject {
} }
func load(force: Bool = false, onSuccess: @escaping () -> Void = {}) { func load(force: Bool = false, onSuccess: @escaping () -> Void = {}) {
guard accounts.app.supportsUserPlaylists, accounts.signedIn, let account = accounts.current else { guard accounts.app.supportsUserPlaylists, let account = accounts.current else {
playlists = [] playlists = []
return return
} }
loadCachedPlaylists(account) loadCachedPlaylists(account)
guard accounts.signedIn else { return }
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
guard let self else { return } guard let self else { return }
let request = force ? self.resource?.load() : self.resource?.loadIfNeeded() let request = force ? self.resource?.load() : self.resource?.loadIfNeeded()

View File

@ -67,12 +67,15 @@ struct ChannelPlaylistView: View {
} }
.environment(\.listingStyle, channelPlaylistListingStyle) .environment(\.listingStyle, channelPlaylistListingStyle)
.onAppear { .onAppear {
if navigationStyle == .tab { if let playlist = presentedPlaylist,
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { let cache = ChannelPlaylistsCacheModel.shared.retrievePlaylist(playlist.id)
resource?.loadIfNeeded() {
store.replace(cache)
}
resource?.loadIfNeeded()?.onSuccess { response in
if let playlist: ChannelPlaylist = response.typedContent() {
ChannelPlaylistsCacheModel.shared.storePlaylist(playlist: playlist)
} }
} else {
resource?.loadIfNeeded()
} }
} }
#if os(tvOS) #if os(tvOS)

View File

@ -45,21 +45,73 @@ struct FavoriteItemView: View {
.contentShape(Rectangle()) .contentShape(Rectangle())
.onAppear { .onAppear {
resource?.addObserver(store) resource?.addObserver(store)
if item.section == .subscriptions { loadCacheAndResource()
cacheFeed(resource?.loadIfNeeded())
} else {
resource?.loadIfNeeded()
}
} }
} }
} }
.onChange(of: accounts.current) { _ in .onChange(of: accounts.current) { _ in
resource?.addObserver(store) resource?.addObserver(store)
if item.section == .subscriptions { loadCacheAndResource(force: true)
cacheFeed(resource?.load()) }
} else { }
resource?.load()
func loadCacheAndResource(force: Bool = false) {
guard var resource else { return }
var onSuccess: (Entity<Any>) -> Void = { _ in }
var contentItems = [ContentItem]()
switch item.section {
case .subscriptions:
let feed = FeedCacheModel.shared.retrieveFeed(account: accounts.current)
contentItems = ContentItem.array(of: feed)
onSuccess = { response in
if let videos: [Video] = response.typedContent() {
FeedCacheModel.shared.storeFeed(account: accounts.current, videos: videos)
}
} }
case let .channel(_, id, name):
let channel = Channel(app: .invidious, id: id, name: name)
if let cache = ChannelsCacheModel.shared.retrieve(channel.cacheKey) {
contentItems = ContentItem.array(of: cache.videos)
}
onSuccess = { response in
if let channel: Channel = response.typedContent() {
ChannelsCacheModel.shared.store(channel)
}
}
case let .channelPlaylist(_, id, _):
if let cache = ChannelPlaylistsCacheModel.shared.retrievePlaylist(id),
!cache.videos.isEmpty
{
contentItems = ContentItem.array(of: cache.videos)
}
onSuccess = { response in
if let playlist: ChannelPlaylist = response.typedContent() {
ChannelPlaylistsCacheModel.shared.storePlaylist(playlist: playlist)
}
}
case let .playlist(_, id):
let playlists = PlaylistsCacheModel.shared.retrievePlaylists(account: accounts.current)
if let playlist = playlists.first(where: { $0.id == id }) {
contentItems = ContentItem.array(of: playlist.videos)
}
default:
contentItems = []
}
if !contentItems.isEmpty {
store.contentItems = contentItems
}
if force {
resource.load().onSuccess(onSuccess)
} else {
resource.loadIfNeeded()?.onSuccess(onSuccess)
} }
} }
@ -173,18 +225,10 @@ struct FavoriteItemView: View {
.padding(.trailing, 10) .padding(.trailing, 10)
} }
private func cacheFeed(_ request: Request?) {
request?.onSuccess { response in
if let videos: [Video] = response.typedContent() {
FeedCacheModel.shared.storeFeed(account: accounts.current, videos: videos)
}
}
}
private var isVisible: Bool { private var isVisible: Bool {
switch item.section { switch item.section {
case .subscriptions: case .subscriptions:
return accounts.app.supportsSubscriptions && accounts.signedIn return accounts.app.supportsSubscriptions
case .popular: case .popular:
return accounts.app.supportsPopular return accounts.app.supportsPopular
case let .channel(appType, _, _): case let .channel(appType, _, _):