Stateful - Set cleanup and `final` classes (#1465)
* cleanup * Update Stateful.swift
This commit is contained in:
parent
16efcbefdc
commit
4a63b52b17
|
@ -6,17 +6,11 @@
|
|||
// Copyright (c) 2025 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import OrderedCollections
|
||||
|
||||
// TODO: documentation
|
||||
// TODO: find a better way to handle backgroundStates on action/state transitions
|
||||
// so that conformers don't have to manually insert/remove them
|
||||
// TODO: better/official way for subclasses of conformers to perform actions during
|
||||
// parent class actions
|
||||
// TODO: official way for a cleaner `respond` method so it doesn't have all Task
|
||||
// construction and get bloated
|
||||
// TODO: move backgroundStates to just a `Set`
|
||||
|
||||
protocol Stateful: AnyObject {
|
||||
|
||||
|
@ -27,9 +21,8 @@ protocol Stateful: AnyObject {
|
|||
/// Background states that the conformer can be in.
|
||||
/// Usually used to indicate background events that shouldn't
|
||||
/// set the conformer to a primary state.
|
||||
var backgroundStates: OrderedSet<BackgroundState> { get set }
|
||||
var backgroundStates: Set<BackgroundState> { get set }
|
||||
|
||||
var lastAction: Action? { get set }
|
||||
var state: State { get set }
|
||||
|
||||
/// Respond to a sent action and return the new state
|
||||
|
@ -44,21 +37,15 @@ protocol Stateful: AnyObject {
|
|||
|
||||
extension Stateful {
|
||||
|
||||
var lastAction: Action? {
|
||||
get { nil }
|
||||
set {}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func send(_ action: Action) {
|
||||
state = respond(to: action)
|
||||
lastAction = action
|
||||
}
|
||||
}
|
||||
|
||||
extension Stateful where BackgroundState == Never {
|
||||
|
||||
var backgroundStates: OrderedSet<Never> {
|
||||
var backgroundStates: Set<Never> {
|
||||
get {
|
||||
assertionFailure("Attempted to access `backgroundStates` when there are none")
|
||||
return []
|
||||
|
|
|
@ -34,9 +34,9 @@ final class APIKeysViewModel: ViewModel, Stateful {
|
|||
// MARK: Published Variables
|
||||
|
||||
@Published
|
||||
final var apiKeys: [AuthenticationInfo] = []
|
||||
var apiKeys: [AuthenticationInfo] = []
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
// MARK: Action Responses
|
||||
|
||||
|
|
|
@ -36,11 +36,11 @@ final class ActiveSessionsViewModel: ViewModel, Stateful {
|
|||
}
|
||||
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
final var sessions: OrderedDictionary<String, BindingBox<SessionInfo?>> = [:]
|
||||
var sessions: OrderedDictionary<String, BindingBox<SessionInfo?>> = [:]
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
private let activeWithinSeconds: Int = 960
|
||||
private var sessionTask: AnyCancellable?
|
||||
|
@ -52,7 +52,7 @@ final class ActiveSessionsViewModel: ViewModel, Stateful {
|
|||
|
||||
sessionTask = Task { [weak self] in
|
||||
await MainActor.run {
|
||||
let _ = self?.backgroundStates.append(.gettingSessions)
|
||||
let _ = self?.backgroundStates.insert(.gettingSessions)
|
||||
}
|
||||
|
||||
do {
|
||||
|
|
|
@ -45,7 +45,7 @@ final class AddServerUserViewModel: ViewModel, Eventful, Stateful, Identifiable
|
|||
}
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
private var userTask: AnyCancellable?
|
||||
private var eventSubject: PassthroughSubject<Event, Never> = .init()
|
||||
|
|
|
@ -11,7 +11,7 @@ import Foundation
|
|||
import JellyfinAPI
|
||||
import OrderedCollections
|
||||
|
||||
class DeviceDetailViewModel: ViewModel, Stateful, Eventful {
|
||||
final class DeviceDetailViewModel: ViewModel, Stateful, Eventful {
|
||||
|
||||
enum Event {
|
||||
case error(JellyfinAPIError)
|
||||
|
@ -31,7 +31,7 @@ class DeviceDetailViewModel: ViewModel, Stateful, Eventful {
|
|||
}
|
||||
|
||||
@Published
|
||||
var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
var state: State = .initial
|
||||
|
||||
|
@ -57,7 +57,7 @@ class DeviceDetailViewModel: ViewModel, Stateful, Eventful {
|
|||
|
||||
Task {
|
||||
await MainActor.run {
|
||||
_ = backgroundStates.append(.updating)
|
||||
_ = backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
do {
|
||||
|
|
|
@ -47,11 +47,11 @@ final class DevicesViewModel: ViewModel, Eventful, Stateful {
|
|||
// MARK: Published Values
|
||||
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
final var devices: [DeviceInfo] = []
|
||||
var devices: [DeviceInfo] = []
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
var events: AnyPublisher<Event, Never> {
|
||||
eventSubject
|
||||
|
@ -69,7 +69,7 @@ final class DevicesViewModel: ViewModel, Eventful, Stateful {
|
|||
case .refresh:
|
||||
deviceTask?.cancel()
|
||||
|
||||
backgroundStates.append(.refreshing)
|
||||
backgroundStates.insert(.refreshing)
|
||||
|
||||
deviceTask = Task { [weak self] in
|
||||
do {
|
||||
|
@ -98,7 +98,7 @@ final class DevicesViewModel: ViewModel, Eventful, Stateful {
|
|||
case let .delete(ids):
|
||||
deviceTask?.cancel()
|
||||
|
||||
backgroundStates.append(.deleting)
|
||||
backgroundStates.insert(.deleting)
|
||||
|
||||
deviceTask = Task { [weak self] in
|
||||
do {
|
||||
|
|
|
@ -48,9 +48,9 @@ final class ServerTaskObserver: ViewModel, Stateful, Eventful, Identifiable {
|
|||
// MARK: Published Values
|
||||
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
@Published
|
||||
private(set) var task: TaskInfo
|
||||
|
||||
|
@ -138,7 +138,7 @@ final class ServerTaskObserver: ViewModel, Stateful, Eventful, Identifiable {
|
|||
.appending(trigger)
|
||||
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.updatingTriggers)
|
||||
_ = self.backgroundStates.insert(.updatingTriggers)
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -165,7 +165,7 @@ final class ServerTaskObserver: ViewModel, Stateful, Eventful, Identifiable {
|
|||
updatedTriggers.removeAll { $0 == trigger }
|
||||
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.updatingTriggers)
|
||||
_ = self.backgroundStates.insert(.updatingTriggers)
|
||||
}
|
||||
|
||||
do {
|
||||
|
|
|
@ -41,11 +41,11 @@ final class ServerTasksViewModel: ViewModel, Stateful {
|
|||
}
|
||||
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
@Published
|
||||
final var tasks: OrderedDictionary<String, [ServerTaskObserver]> = [:]
|
||||
var tasks: OrderedDictionary<String, [ServerTaskObserver]> = [:]
|
||||
|
||||
private var getTasksCancellable: AnyCancellable?
|
||||
|
||||
|
|
|
@ -49,9 +49,9 @@ final class ServerUserAdminViewModel: ViewModel, Eventful, Stateful, Identifiabl
|
|||
// MARK: - Published Values
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
|
||||
@Published
|
||||
private(set) var user: UserDto
|
||||
|
@ -99,7 +99,7 @@ final class ServerUserAdminViewModel: ViewModel, Eventful, Stateful, Identifiabl
|
|||
userTaskCancellable = Task {
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = backgroundStates.append(.refreshing)
|
||||
_ = backgroundStates.insert(.refreshing)
|
||||
}
|
||||
|
||||
try await loadDetails()
|
||||
|
@ -126,7 +126,7 @@ final class ServerUserAdminViewModel: ViewModel, Eventful, Stateful, Identifiabl
|
|||
userTaskCancellable = Task {
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = backgroundStates.append(.refreshing)
|
||||
_ = backgroundStates.insert(.refreshing)
|
||||
}
|
||||
|
||||
try await loadLibraries(isHidden: isHidden)
|
||||
|
@ -153,7 +153,7 @@ final class ServerUserAdminViewModel: ViewModel, Eventful, Stateful, Identifiabl
|
|||
userTaskCancellable = Task {
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = backgroundStates.append(.updating)
|
||||
_ = backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
try await updatePolicy(policy: policy)
|
||||
|
@ -181,7 +181,7 @@ final class ServerUserAdminViewModel: ViewModel, Eventful, Stateful, Identifiabl
|
|||
userTaskCancellable = Task {
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = backgroundStates.append(.updating)
|
||||
_ = backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
try await updateConfiguration(configuration: configuration)
|
||||
|
@ -209,7 +209,7 @@ final class ServerUserAdminViewModel: ViewModel, Eventful, Stateful, Identifiabl
|
|||
userTaskCancellable = Task {
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = backgroundStates.append(.updating)
|
||||
_ = backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
try await updateUsername(username: username)
|
||||
|
|
|
@ -50,13 +50,13 @@ final class ServerUsersViewModel: ViewModel, Eventful, Stateful, Identifiable {
|
|||
// MARK: Published Values
|
||||
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
|
||||
@Published
|
||||
final var users: IdentifiedArrayOf<UserDto> = []
|
||||
var users: IdentifiedArrayOf<UserDto> = []
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
var events: AnyPublisher<Event, Never> {
|
||||
eventSubject
|
||||
|
@ -88,7 +88,7 @@ final class ServerUsersViewModel: ViewModel, Eventful, Stateful, Identifiable {
|
|||
switch action {
|
||||
case let .refreshUser(userID):
|
||||
userTask?.cancel()
|
||||
backgroundStates.append(.gettingUsers)
|
||||
backgroundStates.insert(.gettingUsers)
|
||||
|
||||
userTask = Task {
|
||||
do {
|
||||
|
@ -114,7 +114,7 @@ final class ServerUsersViewModel: ViewModel, Eventful, Stateful, Identifiable {
|
|||
|
||||
case let .getUsers(isHidden, isDisabled):
|
||||
userTask?.cancel()
|
||||
backgroundStates.append(.gettingUsers)
|
||||
backgroundStates.insert(.gettingUsers)
|
||||
|
||||
userTask = Task {
|
||||
do {
|
||||
|
@ -140,7 +140,7 @@ final class ServerUsersViewModel: ViewModel, Eventful, Stateful, Identifiable {
|
|||
|
||||
case let .deleteUsers(ids):
|
||||
userTask?.cancel()
|
||||
backgroundStates.append(.deletingUsers)
|
||||
backgroundStates.insert(.deletingUsers)
|
||||
|
||||
userTask = Task {
|
||||
do {
|
||||
|
@ -167,7 +167,7 @@ final class ServerUsersViewModel: ViewModel, Eventful, Stateful, Identifiable {
|
|||
|
||||
case let .appendUser(user):
|
||||
userTask?.cancel()
|
||||
backgroundStates.append(.appendingUsers)
|
||||
backgroundStates.insert(.appendingUsers)
|
||||
|
||||
userTask = Task {
|
||||
do {
|
||||
|
|
|
@ -48,7 +48,7 @@ final class ConnectToServerViewModel: ViewModel, Eventful, Stateful {
|
|||
}
|
||||
|
||||
@Published
|
||||
var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
|
||||
// no longer-found servers are not cleared, but not an issue
|
||||
@Published
|
||||
|
|
|
@ -46,7 +46,7 @@ final class FilterViewModel: ViewModel, Stateful {
|
|||
|
||||
/// ViewModel Background State(s)
|
||||
@Published
|
||||
var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
|
||||
/// ViewModel State
|
||||
@Published
|
||||
|
@ -89,13 +89,13 @@ final class FilterViewModel: ViewModel, Stateful {
|
|||
queryFiltersTask = Task {
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.gettingQueryFilters)
|
||||
_ = self.backgroundStates.insert(.gettingQueryFilters)
|
||||
}
|
||||
|
||||
try await setQueryFilters()
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.failedToGetQueryFilters)
|
||||
_ = self.backgroundStates.insert(.failedToGetQueryFilters)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,9 +45,7 @@ final class HomeViewModel: ViewModel, Stateful {
|
|||
var resumeItems: OrderedSet<BaseItemDto> = []
|
||||
|
||||
@Published
|
||||
var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
@Published
|
||||
var lastAction: Action? = nil
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
var state: State = .initial
|
||||
|
||||
|
@ -83,7 +81,7 @@ final class HomeViewModel: ViewModel, Stateful {
|
|||
case .backgroundRefresh:
|
||||
|
||||
backgroundRefreshTask?.cancel()
|
||||
backgroundStates.append(.refresh)
|
||||
backgroundStates.insert(.refresh)
|
||||
|
||||
backgroundRefreshTask = Task { [weak self] in
|
||||
do {
|
||||
|
|
|
@ -10,7 +10,7 @@ import Combine
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class DeleteItemViewModel: ViewModel, Stateful, Eventful {
|
||||
final class DeleteItemViewModel: ViewModel, Stateful, Eventful {
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
|
@ -33,7 +33,7 @@ class DeleteItemViewModel: ViewModel, Stateful, Eventful {
|
|||
}
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
// MARK: - Published Item
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import Get
|
|||
import JellyfinAPI
|
||||
import OrderedCollections
|
||||
|
||||
class IdentifyItemViewModel: ViewModel, Stateful, Eventful {
|
||||
final class IdentifyItemViewModel: ViewModel, Stateful, Eventful {
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import Combine
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class GenreEditorViewModel: ItemEditorViewModel<String> {
|
||||
final class GenreEditorViewModel: ItemEditorViewModel<String> {
|
||||
|
||||
// MARK: - Populate the Trie
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class ItemEditorViewModel<Element: Equatable>: ViewModel, Stateful, Eventful {
|
|||
}
|
||||
|
||||
@Published
|
||||
var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
var item: BaseItemDto
|
||||
@Published
|
||||
|
@ -60,7 +60,7 @@ class ItemEditorViewModel<Element: Equatable>: ViewModel, Stateful, Eventful {
|
|||
@Published
|
||||
var state: State = .initial
|
||||
|
||||
final var trie = Trie<String, Element>()
|
||||
var trie = Trie<String, Element>()
|
||||
|
||||
private var loadTask: AnyCancellable?
|
||||
private var updateTask: AnyCancellable?
|
||||
|
@ -69,7 +69,7 @@ class ItemEditorViewModel<Element: Equatable>: ViewModel, Stateful, Eventful {
|
|||
|
||||
private let eventSubject = PassthroughSubject<Event, Never>()
|
||||
|
||||
var events: AnyPublisher<Event, Never> {
|
||||
final var events: AnyPublisher<Event, Never> {
|
||||
eventSubject.receive(on: RunLoop.main).eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ class ItemEditorViewModel<Element: Equatable>: ViewModel, Stateful, Eventful {
|
|||
await MainActor.run {
|
||||
self.matches = []
|
||||
self.state = .initial
|
||||
_ = self.backgroundStates.append(.loading)
|
||||
_ = self.backgroundStates.insert(.loading)
|
||||
}
|
||||
|
||||
let allElements = try await self.fetchElements()
|
||||
|
@ -178,7 +178,7 @@ class ItemEditorViewModel<Element: Equatable>: ViewModel, Stateful, Eventful {
|
|||
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.searching)
|
||||
_ = self.backgroundStates.insert(.searching)
|
||||
}
|
||||
|
||||
let results = try await self.searchElements(searchTerm)
|
||||
|
@ -247,7 +247,7 @@ class ItemEditorViewModel<Element: Equatable>: ViewModel, Stateful, Eventful {
|
|||
guard let itemId = item.id else { return }
|
||||
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.refreshing)
|
||||
_ = self.backgroundStates.insert(.refreshing)
|
||||
}
|
||||
|
||||
let request = Paths.getItem(userID: userSession.user.id, itemID: itemId)
|
||||
|
|
|
@ -10,7 +10,7 @@ import Combine
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class PeopleEditorViewModel: ItemEditorViewModel<BaseItemPerson> {
|
||||
final class PeopleEditorViewModel: ItemEditorViewModel<BaseItemPerson> {
|
||||
|
||||
// MARK: - Populate the Trie
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import Combine
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class StudioEditorViewModel: ItemEditorViewModel<NameGuidPair> {
|
||||
final class StudioEditorViewModel: ItemEditorViewModel<NameGuidPair> {
|
||||
|
||||
// MARK: - Populate the Trie
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import Combine
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class TagEditorViewModel: ItemEditorViewModel<String> {
|
||||
final class TagEditorViewModel: ItemEditorViewModel<String> {
|
||||
|
||||
// MARK: - Populate the Trie
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import JellyfinAPI
|
|||
import OrderedCollections
|
||||
import SwiftUI
|
||||
|
||||
class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
||||
final class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
||||
|
||||
enum Event: Equatable {
|
||||
case updated
|
||||
|
@ -50,7 +50,7 @@ class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
|||
@Published
|
||||
var state: State = .initial
|
||||
@Published
|
||||
var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
|
||||
private var task: AnyCancellable?
|
||||
private let eventSubject = PassthroughSubject<Event, Never>()
|
||||
|
@ -85,7 +85,7 @@ class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
|||
guard let self else { return }
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.updating)
|
||||
_ = self.backgroundStates.insert(.updating)
|
||||
self.images.removeAll()
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
|||
guard let self = self else { return }
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.updating)
|
||||
_ = self.backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
try await self.setImage(remoteImageInfo)
|
||||
|
@ -144,7 +144,7 @@ class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
|||
guard let self = self else { return }
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.updating)
|
||||
_ = self.backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
try await self.uploadPhoto(image, type: type)
|
||||
|
@ -174,7 +174,7 @@ class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
|||
guard let self = self else { return }
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.updating)
|
||||
_ = self.backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
try await self.uploadFile(url, type: type)
|
||||
|
@ -204,7 +204,7 @@ class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
|||
guard let self = self else { return }
|
||||
do {
|
||||
await MainActor.run {
|
||||
_ = self.backgroundStates.append(.updating)
|
||||
_ = self.backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
try await deleteImage(imageInfo)
|
||||
|
@ -384,7 +384,7 @@ class ItemImagesViewModel: ViewModel, Stateful, Eventful {
|
|||
guard let itemID = item.id else { return }
|
||||
|
||||
await MainActor.run {
|
||||
_ = backgroundStates.append(.updating)
|
||||
_ = backgroundStates.insert(.updating)
|
||||
}
|
||||
|
||||
let request = Paths.getItem(
|
||||
|
|
|
@ -10,7 +10,7 @@ import Combine
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class RefreshMetadataViewModel: ViewModel, Stateful, Eventful {
|
||||
final class RefreshMetadataViewModel: ViewModel, Stateful, Eventful {
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
|
@ -37,7 +37,7 @@ class RefreshMetadataViewModel: ViewModel, Stateful, Eventful {
|
|||
}
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
// MARK: - Published Items
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class RemoteImageInfoViewModel: PagingLibraryViewModel<RemoteImageInfo> {
|
||||
final class RemoteImageInfoViewModel: PagingLibraryViewModel<RemoteImageInfo> {
|
||||
|
||||
// Image providers come from the paging call
|
||||
@Published
|
||||
|
|
|
@ -18,27 +18,24 @@ final class EpisodeItemViewModel: ItemViewModel {
|
|||
|
||||
private var seriesItemTask: AnyCancellable?
|
||||
|
||||
override init(item: BaseItemDto) {
|
||||
super.init(item: item)
|
||||
override func respond(to action: ItemViewModel.Action) -> ItemViewModel.State {
|
||||
|
||||
$lastAction
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .refresh:
|
||||
seriesItemTask?.cancel()
|
||||
|
||||
if action == .refresh {
|
||||
seriesItemTask?.cancel()
|
||||
seriesItemTask = Task {
|
||||
let seriesItem = try await self.getSeriesItem()
|
||||
|
||||
seriesItemTask = Task {
|
||||
let seriesItem = try await self.getSeriesItem()
|
||||
|
||||
await MainActor.run {
|
||||
self.seriesItem = seriesItem
|
||||
}
|
||||
}
|
||||
.asAnyCancellable()
|
||||
await MainActor.run {
|
||||
self.seriesItem = seriesItem
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
.asAnyCancellable()
|
||||
default: break
|
||||
}
|
||||
|
||||
return super.respond(to: action)
|
||||
}
|
||||
|
||||
private func getSeriesItem() async throws -> BaseItemDto {
|
||||
|
|
|
@ -74,11 +74,9 @@ class ItemViewModel: ViewModel, Stateful {
|
|||
private(set) var specialFeatures: [BaseItemDto] = []
|
||||
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
final var lastAction: Action? = nil
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
// tasks
|
||||
|
||||
|
@ -121,7 +119,7 @@ class ItemViewModel: ViewModel, Stateful {
|
|||
switch action {
|
||||
case .backgroundRefresh:
|
||||
|
||||
backgroundStates.append(.refresh)
|
||||
backgroundStates.insert(.refresh)
|
||||
|
||||
Task { [weak self] in
|
||||
guard let self else { return }
|
||||
|
@ -212,7 +210,7 @@ class ItemViewModel: ViewModel, Stateful {
|
|||
return .refreshing
|
||||
case let .replace(newItem):
|
||||
|
||||
backgroundStates.append(.refresh)
|
||||
backgroundStates.insert(.refresh)
|
||||
|
||||
Task { [weak self] in
|
||||
guard let self else { return }
|
||||
|
|
|
@ -92,27 +92,25 @@ class PagingLibraryViewModel<Element: Poster>: ViewModel, Eventful, Stateful {
|
|||
}
|
||||
|
||||
@Published
|
||||
final var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
/// - Keys: the `hashValue` of the `Element.ID`
|
||||
@Published
|
||||
final var elements: IdentifiedArray<Int, Element>
|
||||
var elements: IdentifiedArray<Int, Element>
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
@Published
|
||||
final var lastAction: Action? = nil
|
||||
var state: State = .initial
|
||||
|
||||
final let filterViewModel: FilterViewModel?
|
||||
final let parent: (any LibraryParent)?
|
||||
|
||||
var events: AnyPublisher<Event, Never> {
|
||||
final var events: AnyPublisher<Event, Never> {
|
||||
eventSubject
|
||||
.receive(on: RunLoop.main)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
let pageSize: Int
|
||||
private(set) final var currentPage = 0
|
||||
private(set) final var hasNextPage = true
|
||||
private(set) var currentPage = 0
|
||||
private(set) var hasNextPage = true
|
||||
|
||||
private let eventSubject: PassthroughSubject<Event, Never> = .init()
|
||||
private let isStatic: Bool
|
||||
|
@ -282,7 +280,7 @@ class PagingLibraryViewModel<Element: Poster>: ViewModel, Eventful, Stateful {
|
|||
|
||||
guard hasNextPage else { return state }
|
||||
|
||||
backgroundStates.append(.gettingNextPage)
|
||||
backgroundStates.insert(.gettingNextPage)
|
||||
|
||||
pagingTask = Task { [weak self] in
|
||||
do {
|
||||
|
|
|
@ -13,7 +13,7 @@ import JellyfinAPI
|
|||
// with the channel retrieving method below and is mainly just for reference
|
||||
// for how I should probably handle getting the channels of programs elsewhere.
|
||||
|
||||
class LiveVideoPlayerManager: VideoPlayerManager {
|
||||
final class LiveVideoPlayerManager: VideoPlayerManager {
|
||||
|
||||
@Published
|
||||
var program: ChannelProgram?
|
||||
|
|
|
@ -36,9 +36,10 @@ final class MediaViewModel: ViewModel, Stateful {
|
|||
var mediaItems: OrderedSet<MediaType> = []
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
|
||||
@Published
|
||||
final var lastAction: Action? = nil
|
||||
var state: State = .initial
|
||||
|
||||
func respond(to action: Action) -> State {
|
||||
switch action {
|
||||
|
|
|
@ -31,7 +31,7 @@ final class ParentalRatingsViewModel: ViewModel, Stateful {
|
|||
private(set) var parentalRatings: [ParentalRating] = []
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
private var currentRefreshTask: AnyCancellable?
|
||||
|
||||
|
|
|
@ -51,9 +51,7 @@ final class ProgramsViewModel: ViewModel, Stateful {
|
|||
private(set) var sports: [BaseItemDto] = []
|
||||
|
||||
@Published
|
||||
final var lastAction: Action? = nil
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
var state: State = .initial
|
||||
|
||||
private var currentRefreshTask: AnyCancellable?
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ final class QuickConnectAuthorizeViewModel: ViewModel, Eventful, Stateful {
|
|||
case initial
|
||||
}
|
||||
|
||||
@Published
|
||||
var lastAction: Action? = nil
|
||||
@Published
|
||||
var state: State = .initial
|
||||
|
||||
|
|
|
@ -49,9 +49,7 @@ final class SearchViewModel: ViewModel, Stateful {
|
|||
private(set) var suggestions: [BaseItemDto] = []
|
||||
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
@Published
|
||||
final var lastAction: Action? = nil
|
||||
var state: State = .initial
|
||||
|
||||
private var searchTask: AnyCancellable?
|
||||
private var searchQuery: CurrentValueSubject<String, Never> = .init("")
|
||||
|
|
|
@ -14,7 +14,7 @@ import JellyfinAPI
|
|||
import KeychainSwift
|
||||
import OrderedCollections
|
||||
|
||||
class SelectUserViewModel: ViewModel, Eventful, Stateful {
|
||||
final class SelectUserViewModel: ViewModel, Eventful, Stateful {
|
||||
|
||||
// MARK: Event
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import Factory
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class ServerCheckViewModel: ViewModel, Stateful {
|
||||
final class ServerCheckViewModel: ViewModel, Stateful {
|
||||
|
||||
enum Action: Equatable {
|
||||
case checkServer
|
||||
|
|
|
@ -10,7 +10,7 @@ import CoreStore
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class ServerConnectionViewModel: ViewModel {
|
||||
final class ServerConnectionViewModel: ViewModel {
|
||||
|
||||
@Published
|
||||
var server: ServerState
|
||||
|
|
|
@ -26,9 +26,7 @@ final class ServerLogsViewModel: ViewModel, Stateful {
|
|||
@Published
|
||||
private(set) var logs: OrderedSet<LogFile> = []
|
||||
@Published
|
||||
final var state: State = .initial
|
||||
@Published
|
||||
final var lastAction: Action?
|
||||
var state: State = .initial
|
||||
|
||||
func respond(to action: Action) -> State {
|
||||
switch action {
|
||||
|
|
|
@ -10,7 +10,7 @@ import Combine
|
|||
import Foundation
|
||||
import KeychainSwift
|
||||
|
||||
class UserLocalSecurityViewModel: ViewModel, Eventful {
|
||||
final class UserLocalSecurityViewModel: ViewModel, Eventful {
|
||||
|
||||
enum Event: Hashable {
|
||||
case error(JellyfinAPIError)
|
||||
|
|
|
@ -12,7 +12,7 @@ import JellyfinAPI
|
|||
import Nuke
|
||||
import UIKit
|
||||
|
||||
class UserProfileImageViewModel: ViewModel, Eventful, Stateful {
|
||||
final class UserProfileImageViewModel: ViewModel, Eventful, Stateful {
|
||||
|
||||
// MARK: - Action
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ final class UserSignInViewModel: ViewModel, Eventful, Stateful {
|
|||
}
|
||||
|
||||
@Published
|
||||
var backgroundStates: OrderedSet<BackgroundState> = []
|
||||
var backgroundStates: Set<BackgroundState> = []
|
||||
@Published
|
||||
var isQuickConnectEnabled = false
|
||||
@Published
|
||||
|
@ -106,7 +106,7 @@ final class UserSignInViewModel: ViewModel, Eventful, Stateful {
|
|||
do {
|
||||
|
||||
await MainActor.run {
|
||||
let _ = self?.backgroundStates.append(.gettingPublicData)
|
||||
let _ = self?.backgroundStates.insert(.gettingPublicData)
|
||||
}
|
||||
|
||||
let isQuickConnectEnabled = try await self?.retrieveQuickConnectEnabled()
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class DownloadVideoPlayerManager: VideoPlayerManager {
|
||||
final class DownloadVideoPlayerManager: VideoPlayerManager {
|
||||
|
||||
init(downloadTask: DownloadTask) {
|
||||
super.init()
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
class OnlineVideoPlayerManager: VideoPlayerManager {
|
||||
final class OnlineVideoPlayerManager: VideoPlayerManager {
|
||||
|
||||
init(item: BaseItemDto, mediaSource: MediaSourceInfo) {
|
||||
super.init()
|
||||
|
|
|
@ -14,7 +14,7 @@ import JellyfinAPI
|
|||
import UIKit
|
||||
import VLCUI
|
||||
|
||||
class VideoPlayerViewModel: ViewModel {
|
||||
final class VideoPlayerViewModel: ViewModel {
|
||||
|
||||
let playbackURL: URL
|
||||
let item: BaseItemDto
|
||||
|
|
Loading…
Reference in New Issue