jellyflood/Shared/ViewModels/ItemViewModel/ItemViewModel.swift

205 lines
5.6 KiB
Swift

//
// Swiftfin is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2023 Jellyfin & Jellyfin Contributors
//
import Combine
import Factory
import Foundation
import JellyfinAPI
import UIKit
class ItemViewModel: ViewModel {
@Published
var item: BaseItemDto {
willSet {
switch item.type {
case .episode, .movie:
guard !item.isMissing else { return }
playButtonItem = newValue
default: ()
}
}
}
@Published
var playButtonItem: BaseItemDto? {
willSet {
if let newValue {
selectedMediaSource = newValue.mediaSources?.first
}
}
}
@Published
var isFavorited = false
@Published
var isPlayed = false
@Published
var selectedMediaSource: MediaSourceInfo?
@Published
var similarItems: [BaseItemDto] = []
@Published
var specialFeatures: [BaseItemDto] = []
init(item: BaseItemDto) {
self.item = item
super.init()
getFullItem()
isFavorited = item.userData?.isFavorite ?? false
isPlayed = item.userData?.isPlayed ?? false
getSimilarItems()
getSpecialFeatures()
Notifications[.didSendStopReport].subscribe(self, selector: #selector(receivedStopReport(_:)))
}
private func getFullItem() {
Task {
await MainActor.run {
isLoading = true
}
let parameters = Paths.GetItemsParameters(
userID: userSession.user.id,
fields: ItemFields.allCases,
enableUserData: true,
ids: [item.id!]
)
let request = Paths.getItems(parameters: parameters)
let response = try await userSession.client.send(request)
guard let fullItem = response.value.items?.first else { return }
await MainActor.run {
self.item = fullItem
isLoading = false
}
}
}
@objc
private func receivedStopReport(_ notification: NSNotification) {
guard let itemID = notification.object as? String else { return }
if itemID == item.id {
updateItem()
} else {
// Remove if necessary. Note that this cannot be in deinit as
// holding as an observer won't allow the object to be deinit-ed
Notifications[.didSendStopReport].unsubscribe(self)
}
}
// TODO: remove and have views handle
func playButtonText() -> String {
if item.isUnaired {
return L10n.unaired
}
if item.isMissing {
return L10n.missing
}
if let itemProgressString = item.progressLabel {
return itemProgressString
}
return L10n.play
}
func getSimilarItems() {
Task {
let parameters = Paths.GetSimilarItemsParameters(
userID: userSession.user.id,
limit: 20,
fields: ItemFields.minimumCases
)
let request = Paths.getSimilarItems(
itemID: item.id!,
parameters: parameters
)
let response = try await userSession.client.send(request)
await MainActor.run {
similarItems = response.value.items ?? []
}
}
}
func getSpecialFeatures() {
Task {
let request = Paths.getSpecialFeatures(
userID: userSession.user.id,
itemID: item.id!
)
let response = try await userSession.client.send(request)
await MainActor.run {
specialFeatures = response.value.filter { $0.extraType?.isVideo ?? false }
}
}
}
func toggleWatchState() {
// let current = isPlayed
// isPlayed.toggle()
// let request: AnyPublisher<UserItemDataDto, Error>
// if current {
// request = PlaystateAPI.markUnplayedItem(userId: "123abc", itemId: item.id!)
// } else {
// request = PlaystateAPI.markPlayedItem(userId: "123abc", itemId: item.id!)
// }
// request
// .trackActivity(loading)
// .sink(receiveCompletion: { [weak self] completion in
// switch completion {
// case .failure:
// self?.isPlayed = !current
// case .finished: ()
// }
// self?.handleAPIRequestError(completion: completion)
// }, receiveValue: { _ in })
// .store(in: &cancellables)
}
func toggleFavoriteState() {
// let current = isFavorited
// isFavorited.toggle()
// let request: AnyPublisher<UserItemDataDto, Error>
// if current {
// request = UserLibraryAPI.unmarkFavoriteItem(userId: "123abc", itemId: item.id!)
// } else {
// request = UserLibraryAPI.markFavoriteItem(userId: "123abc", itemId: item.id!)
// }
// request
// .trackActivity(loading)
// .sink(receiveCompletion: { [weak self] completion in
// switch completion {
// case .failure:
// self?.isFavorited = !current
// case .finished: ()
// }
// self?.handleAPIRequestError(completion: completion)
// }, receiveValue: { _ in })
// .store(in: &cancellables)
}
// Overridden by subclasses
func updateItem() {}
}