diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index 35373edb..d0e47bb1 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -133,6 +133,8 @@ 62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */; }; 62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */; }; 62E632F0267D43320063E547 /* LibraryFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */; }; + 62E632F3267D54030063E547 /* DetailItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632F2267D54030063E547 /* DetailItemViewModel.swift */; }; + 62E632F4267D54030063E547 /* DetailItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632F2267D54030063E547 /* DetailItemViewModel.swift */; }; 62EC3527267665D8000E9F2D /* MobileVLCKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53D5E3DC264B47EE00BADDC8 /* MobileVLCKit.xcframework */; }; 62EC3528267665D8000E9F2D /* MobileVLCKit.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 53D5E3DC264B47EE00BADDC8 /* MobileVLCKit.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 62EC352C26766675000E9F2D /* ServerEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC352B26766675000E9F2D /* ServerEnvironment.swift */; }; @@ -289,6 +291,7 @@ 62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonItemViewModel.swift; sourceTree = ""; }; 62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeriesItemViewModel.swift; sourceTree = ""; }; 62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryFilterViewModel.swift; sourceTree = ""; }; + 62E632F2267D54030063E547 /* DetailItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailItemViewModel.swift; sourceTree = ""; }; 62EC352B26766675000E9F2D /* ServerEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerEnvironment.swift; sourceTree = ""; }; 62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = ""; }; 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = ""; }; @@ -358,6 +361,7 @@ 62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */, 62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */, 62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */, + 62E632F2267D54030063E547 /* DetailItemViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -396,6 +400,7 @@ 535870752669D60C00D05A09 /* Shared */ = { isa = PBXGroup; children = ( + 62E632F1267D53B00063E547 /* Protocols */, 62EC352A26766657000E9F2D /* Singleton */, 532175392671BCED005491E6 /* ViewModels */, 621338912660106C00A81A2A /* Extensions */, @@ -531,6 +536,13 @@ path = WidgetExtension; sourceTree = ""; }; + 62E632F1267D53B00063E547 /* Protocols */ = { + isa = PBXGroup; + children = ( + ); + path = Protocols; + sourceTree = ""; + }; 62EC352A26766657000E9F2D /* Singleton */ = { isa = PBXGroup; children = ( @@ -736,6 +748,7 @@ 62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */, 62E632F0267D43320063E547 /* LibraryFilterViewModel.swift in Sources */, 53ABFDE6267974EF00886593 /* SettingsViewModel.swift in Sources */, + 62E632F4267D54030063E547 /* DetailItemViewModel.swift in Sources */, 6267B3D826710B9800A7371D /* CollectionExtensions.swift in Sources */, 62E632E7267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */, 535870A52669D8AE00D05A09 /* ParallaxHeader.swift in Sources */, @@ -798,6 +811,7 @@ 53A089D0264DA9DA00D57806 /* MovieItemView.swift in Sources */, 62E632E9267D3FF50063E547 /* SeasonItemViewModel.swift in Sources */, 625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */, + 62E632F3267D54030063E547 /* DetailItemViewModel.swift in Sources */, 53DE4BD2267098F300739748 /* SearchBarView.swift in Sources */, 53E4E649263F725B00F67C6B /* MultiSelectorView.swift in Sources */, 621338B32660A07800A81A2A /* LazyView.swift in Sources */, diff --git a/Shared/ViewModels/DetailItemViewModel.swift b/Shared/ViewModels/DetailItemViewModel.swift new file mode 100644 index 00000000..0869cc2b --- /dev/null +++ b/Shared/ViewModels/DetailItemViewModel.swift @@ -0,0 +1,75 @@ +// + /* + * 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 2021 Aiden Vigue & Jellyfin Contributors + */ + +import Foundation +import Foundation +import JellyfinAPI + +class DetailItemViewModel: ViewModel { + @Published + var item: BaseItemDto + + @Published + var isWatched = false + @Published + var isFavorited = false + + init(item: BaseItemDto) { + self.item = item + isFavorited = item.userData?.isFavorite ?? false + isWatched = item.userData?.played ?? false + super.init() + } + + func updateWatchState() { + guard let id = item.id else { return } + if isWatched { + PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: id) + .trackActivity(loading) + .sink(receiveCompletion: { [weak self] completion in + self?.handleAPIRequestCompletion(completion: completion) + }, receiveValue: { [weak self] _ in + self?.isWatched = false + }) + .store(in: &cancellables) + } else { + PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: id) + .trackActivity(loading) + .sink(receiveCompletion: { [weak self] completion in + self?.handleAPIRequestCompletion(completion: completion) + }, receiveValue: { [weak self] _ in + self?.isWatched = true + }) + .store(in: &cancellables) + } + } + + func updateFavoriteState() { + guard let id = item.id else { return } + if isFavorited { + UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id) + .trackActivity(loading) + .sink(receiveCompletion: { [weak self] completion in + self?.handleAPIRequestCompletion(completion: completion) + }, receiveValue: { [weak self] _ in + self?.isFavorited = false + }) + .store(in: &cancellables) + } else { + UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id) + .trackActivity(loading) + .sink(receiveCompletion: { [weak self] completion in + self?.handleAPIRequestCompletion(completion: completion) + }, receiveValue: { [weak self] _ in + self?.isFavorited = true + }) + .store(in: &cancellables) + } + } +} diff --git a/Shared/ViewModels/EpisodeItemViewModel.swift b/Shared/ViewModels/EpisodeItemViewModel.swift index 552f6bc1..b43b99ef 100644 --- a/Shared/ViewModels/EpisodeItemViewModel.swift +++ b/Shared/ViewModels/EpisodeItemViewModel.swift @@ -11,65 +11,5 @@ import Combine import Foundation import JellyfinAPI -final class EpisodeItemViewModel: ViewModel { - @Published - var item: BaseItemDto - - @Published - var isWatched = false - @Published - var isFavorited = false - - init(item: BaseItemDto) { - self.item = item - isFavorited = item.userData?.isFavorite ?? false - isWatched = item.userData?.played ?? false - super.init() - } - - func updateWatchState() { - guard let id = item.id else { return } - if isWatched { - PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isWatched = false - }) - .store(in: &cancellables) - } else { - PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isWatched = true - }) - .store(in: &cancellables) - } - } - - func updateFavoriteState() { - guard let id = item.id else { return } - if isFavorited { - UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isFavorited = false - }) - .store(in: &cancellables) - } else { - UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isFavorited = true - }) - .store(in: &cancellables) - } - } +final class EpisodeItemViewModel: DetailItemViewModel { } diff --git a/Shared/ViewModels/MovieItemViewModel.swift b/Shared/ViewModels/MovieItemViewModel.swift index 82f45cea..d37a9281 100644 --- a/Shared/ViewModels/MovieItemViewModel.swift +++ b/Shared/ViewModels/MovieItemViewModel.swift @@ -11,65 +11,5 @@ import Combine import Foundation import JellyfinAPI -final class MovieItemViewModel: ViewModel { - @Published - var item: BaseItemDto - - @Published - var isWatched = false - @Published - var isFavorited = false - - init(item: BaseItemDto) { - self.item = item - isFavorited = item.userData?.isFavorite ?? false - isWatched = item.userData?.played ?? false - super.init() - } - - func updateWatchState() { - guard let id = item.id else { return } - if isWatched { - PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isWatched = false - }) - .store(in: &cancellables) - } else { - PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isWatched = true - }) - .store(in: &cancellables) - } - } - - func updateFavoriteState() { - guard let id = item.id else { return } - if isFavorited { - UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isFavorited = false - }) - .store(in: &cancellables) - } else { - UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id) - .trackActivity(loading) - .sink(receiveCompletion: { [weak self] completion in - self?.handleAPIRequestCompletion(completion: completion) - }, receiveValue: { [weak self] _ in - self?.isFavorited = true - }) - .store(in: &cancellables) - } - } +final class MovieItemViewModel: DetailItemViewModel { }