diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index cf06d89c..7e3fa144 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -117,6 +117,7 @@ 628B95382670CDAB0091AF3B /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */; }; 628B953A2670CE250091AF3B /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 628B95392670CE250091AF3B /* KeychainSwift */; }; 628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* StringExtensions.swift */; }; + 62E632DA267D2BC40063E547 /* LatestMediaViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632D9267D2BC40063E547 /* LatestMediaViewModel.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 */; }; @@ -265,6 +266,7 @@ 628B952A2670CABE0091AF3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 628B95362670CB800091AF3B /* JellyfinWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinWidget.swift; sourceTree = ""; }; 628B953B2670D1FC0091AF3B /* WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetExtension.entitlements; sourceTree = ""; }; + 62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestMediaViewModel.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 = ""; }; @@ -326,6 +328,7 @@ 625CB5762678C34300530A6E /* ConnectToServerViewModel.swift */, 625CB57B2678CE1000530A6E /* ViewModel.swift */, 536D3D75267BA9BB0004248C /* MainTabViewModel.swift */, + 62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -742,6 +745,7 @@ 53F8377D265FF67C00F456B3 /* VideoPlayerSettingsView.swift in Sources */, 53192D5D265AA78A008A4215 /* DeviceProfileBuilder.swift in Sources */, 62133890265F83A900A81A2A /* LibraryListView.swift in Sources */, + 62E632DA267D2BC40063E547 /* LatestMediaViewModel.swift in Sources */, 625CB56F2678C23300530A6E /* HomeView.swift in Sources */, 53892770263C25230035E14B /* NextUpView.swift in Sources */, 625CB5682678B6FB00530A6E /* SplashView.swift in Sources */, diff --git a/JellyfinPlayer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/JellyfinPlayer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 80b243dc..ef329286 100644 --- a/JellyfinPlayer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/JellyfinPlayer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -29,7 +29,7 @@ } }, { - "package": "jellyfin-sdk-swift", + "package": "JellyfinAPI", "repositoryURL": "https://github.com/jellyfin/jellyfin-sdk-swift", "state": { "branch": "main", @@ -38,7 +38,7 @@ } }, { - "package": "keychain-swift", + "package": "KeychainSwift", "repositoryURL": "https://github.com/evgenyneu/keychain-swift", "state": { "branch": null, @@ -74,7 +74,7 @@ } }, { - "package": "SwiftUI-Introspect", + "package": "Introspect", "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect", "state": { "branch": null, diff --git a/JellyfinPlayer/HomeView.swift b/JellyfinPlayer/HomeView.swift index b01803cb..ee5e0512 100644 --- a/JellyfinPlayer/HomeView.swift +++ b/JellyfinPlayer/HomeView.swift @@ -53,7 +53,7 @@ struct HomeView: View { } } }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) - LatestMediaView(usingParentID: libraryID) + LatestMediaView(viewModel: .init(libraryID: libraryID)) }.padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0)) } } diff --git a/JellyfinPlayer/LatestMediaView.swift b/JellyfinPlayer/LatestMediaView.swift index c1acee9f..b4760031 100644 --- a/JellyfinPlayer/LatestMediaView.swift +++ b/JellyfinPlayer/LatestMediaView.swift @@ -5,44 +5,20 @@ * Copyright 2021 Aiden Vigue & Jellyfin Contributors */ -import SwiftUI -import JellyfinAPI import Combine +import JellyfinAPI +import SwiftUI struct LatestMediaView: View { - @StateObject - var tempViewModel = ViewModel() - @State var items: [BaseItemDto] = [] - private var library_id: String = "" - @State private var viewDidLoad: Bool = false - - init(usingParentID: String) { - library_id = usingParentID - } - - func onAppear() { - if viewDidLoad == true { - return - } - viewDidLoad = true - - DispatchQueue.global(qos: .userInitiated).async { - UserLibraryAPI.getLatestMedia(userId: SessionManager.current.user.user_id!, parentId: library_id, fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people], enableUserData: true, limit: 12) - .sink(receiveCompletion: { completion in - print(completion) - }, receiveValue: { response in - items = response - }) - .store(in: &tempViewModel.cancellables) - } - } + var viewModel: LatestMediaViewModel var body: some View { - ScrollView(.horizontal, showsIndicators: false) { + ScrollView(.horizontal, showsIndicators: false) { + ZStack { LazyHStack { Spacer().frame(width: 16) - ForEach(items, id: \.id) { item in + ForEach(viewModel.items, id: \.id) { item in if item.type == "Series" || item.type == "Movie" { NavigationLink(destination: ItemView(item: item)) { VStack(alignment: .leading) { @@ -69,10 +45,13 @@ struct LatestMediaView: View { } } } + if viewModel.isLoading { + ProgressView() + } } - .frame(height: 190) } - .onAppear(perform: onAppear) - .padding(EdgeInsets(top: -2, leading: 0, bottom: 0, trailing: 0)).frame(height: 190) + .frame(height: 190) + } + .padding(EdgeInsets(top: -2, leading: 0, bottom: 0, trailing: 0)).frame(height: 190) } } diff --git a/Shared/ViewModels/LatestMediaViewModel.swift b/Shared/ViewModels/LatestMediaViewModel.swift new file mode 100644 index 00000000..e6732738 --- /dev/null +++ b/Shared/ViewModels/LatestMediaViewModel.swift @@ -0,0 +1,46 @@ +// +/* + * 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 Combine +import Foundation +import JellyfinAPI + +final class LatestMediaViewModel: ViewModel { + @Published + var items = [BaseItemDto]() + + var libraryID: String + + init(libraryID: String) { + self.libraryID = libraryID + super.init() + + refresh() + } + + func refresh() { + UserLibraryAPI.getLatestMedia(userId: SessionManager.current.user.user_id!, parentId: libraryID, + fields: [ + .primaryImageAspectRatio, + .seriesPrimaryImage, + .seasonUserData, + .overview, + .genres, + .people, + ], + enableUserData: true, limit: 12) + .trackActivity(loading) + .sink(receiveCompletion: { [weak self] completion in + self?.HandleAPIRequestCompletion(completion: completion) + }, receiveValue: { [weak self] response in + self?.items = response + }) + .store(in: &cancellables) + } +}