Unwatched videos in subscriptions

This commit is contained in:
Arkadiusz Fal
2022-12-13 00:39:50 +01:00
parent 02b30394ed
commit 8c1d900a63
8 changed files with 154 additions and 17 deletions

View File

@@ -1,4 +1,5 @@
import Cache
import CoreData
import Foundation
import Siesta
import SwiftyJSON
@@ -9,11 +10,15 @@ final class FeedModel: ObservableObject, CacheModel {
@Published var isLoading = false
@Published var videos = [Video]()
@Published private var page = 1
@Published var unwatched = [Account: Int]()
private var cacheModel = FeedCacheModel.shared
private var accounts = AccountsModel.shared
var storage: Storage<String, JSON>?
private var backgroundContext = PersistenceController.shared.container.newBackgroundContext()
var feed: Resource? {
accounts.api.feed(page)
}
@@ -78,7 +83,8 @@ final class FeedModel: ObservableObject, CacheModel {
self.videos.append(contentsOf: videos)
} else {
self.videos = videos
FeedCacheModel.shared.storeFeed(account: account, videos: self.videos)
self.cacheModel.storeFeed(account: account, videos: self.videos)
self.calculateUnwatchedFeed()
}
}
}
@@ -99,9 +105,87 @@ final class FeedModel: ObservableObject, CacheModel {
loadFeed(force: true, paginating: true)
}
func calculateUnwatchedFeed() {
guard let account = accounts.current else { return }
let feed = cacheModel.retrieveFeed(account: account)
guard !feed.isEmpty else { return }
backgroundContext.perform { [weak self] in
guard let self else { return }
let watched = self.watchFetchRequestResult(feed, context: self.backgroundContext).filter { $0.finished }.count
let unwatched = feed.count - watched
DispatchQueue.main.async { [weak self] in
guard let self else { return }
if unwatched != self.unwatched[account] {
self.unwatched[account] = unwatched
}
}
}
}
func markAllFeedAsWatched() {
guard let account = accounts.current else { return }
guard !videos.isEmpty else { return }
backgroundContext.perform { [weak self] in
guard let self else { return }
self.videos.forEach { Watch.markAsWatched(videoID: $0.videoID, account: account, duration: $0.length, context: self.backgroundContext) }
self.calculateUnwatchedFeed()
}
}
func markAllFeedAsUnwatched() {
guard accounts.current != nil,
!videos.isEmpty else { return }
backgroundContext.perform { [weak self] in
guard let self else { return }
let watches = self.watchFetchRequestResult(self.videos, context: self.backgroundContext)
watches.forEach { self.backgroundContext.delete($0) }
try? self.backgroundContext.save()
self.calculateUnwatchedFeed()
}
}
func watchFetchRequestResult(_ videos: [Video], context: NSManagedObjectContext) -> [Watch] {
let watchFetchRequest = Watch.fetchRequest()
watchFetchRequest.predicate = NSPredicate(format: "videoID IN %@", videos.map(\.videoID) as [String])
return (try? context.fetch(watchFetchRequest)) ?? []
}
func playUnwatchedFeed() {
guard let account = accounts.current else { return }
let videos = cacheModel.retrieveFeed(account: account)
guard !videos.isEmpty else { return }
let watches = watchFetchRequestResult(videos, context: backgroundContext)
let watchesIDs = watches.map(\.videoID)
let unwatched = videos.filter { video in
if !watchesIDs.contains(video.videoID) {
return true
}
if let watch = watches.first(where: { $0.videoID == video.videoID }),
watch.finished
{
return false
}
return true
}
guard !unwatched.isEmpty else { return }
PlayerModel.shared.play(unwatched)
}
var feedTime: Date? {
if let account = accounts.current {
return FeedCacheModel.shared.getFeedTime(account: account)
return cacheModel.getFeedTime(account: account)
}
return nil
@@ -113,7 +197,7 @@ final class FeedModel: ObservableObject, CacheModel {
private func loadCachedFeed() {
guard let account = accounts.current else { return }
let cache = FeedCacheModel.shared.retrieveFeed(account: account)
let cache = cacheModel.retrieveFeed(account: account)
if !cache.isEmpty {
DispatchQueue.main.async(qos: .userInteractive) { [weak self] in
self?.videos = cache