From 6ad3b3e0f24957e6cd6cccc478609cbb8788f719 Mon Sep 17 00:00:00 2001 From: Ethan Pippin Date: Wed, 5 Jan 2022 22:57:07 -0700 Subject: [PATCH] tvos home view updates --- .../Views/ContinueWatchingView.swift | 46 ----------- .../ContinueWatchingCard.swift | 71 ++++++++++++++++ .../ContinueWatchingView.swift | 37 +++++++++ JellyfinPlayer tvOS/Views/HomeView.swift | 82 ++++++++----------- .../CinematicEpisodeItemView.swift | 5 +- .../CinematicMovieItemView.swift | 5 +- .../Views/ItemView/PortraitItemsRowView.swift | 9 +- .../Views/LatestMediaView.swift | 50 +++-------- JellyfinPlayer tvOS/Views/NextUpView.swift | 45 ---------- .../Views/NextUpView/NextUpCard.swift | 46 +++++++++++ .../Views/NextUpView/NextUpView.swift | 37 +++++++++ JellyfinPlayer.xcodeproj/project.pbxproj | 28 ++++++- Shared/ViewModels/LatestMediaViewModel.swift | 10 +-- 13 files changed, 282 insertions(+), 189 deletions(-) delete mode 100644 JellyfinPlayer tvOS/Views/ContinueWatchingView.swift create mode 100644 JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingCard.swift create mode 100644 JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingView.swift delete mode 100644 JellyfinPlayer tvOS/Views/NextUpView.swift create mode 100644 JellyfinPlayer tvOS/Views/NextUpView/NextUpCard.swift create mode 100644 JellyfinPlayer tvOS/Views/NextUpView/NextUpView.swift diff --git a/JellyfinPlayer tvOS/Views/ContinueWatchingView.swift b/JellyfinPlayer tvOS/Views/ContinueWatchingView.swift deleted file mode 100644 index 02a85f82..00000000 --- a/JellyfinPlayer tvOS/Views/ContinueWatchingView.swift +++ /dev/null @@ -1,46 +0,0 @@ -/* - * JellyfinPlayer/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 SwiftUI -import JellyfinAPI -import Combine -import Stinsen - -struct ContinueWatchingView: View { - var items: [BaseItemDto] - @Namespace private var namespace - - var homeRouter: HomeCoordinator.Router? = RouterStore.shared.retrieve() - - var body: some View { - VStack(alignment: .leading) { - if items.count > 0 { - L10n.continueWatching.text - .font(.headline) - .fontWeight(.semibold) - .padding(.leading, 90) - ScrollView(.horizontal, showsIndicators: false) { - LazyHStack { - Spacer().frame(width: 45) - ForEach(items, id: \.id) { item in - Button { - self.homeRouter?.route(to: \.modalItem, item) - } label: { - LandscapeItemElement(item: item) - } - .buttonStyle(PlainNavigationLinkButtonStyle()) - } - Spacer().frame(width: 45) - } - }.frame(height: 350) - } else { - EmptyView() - } - } - } -} diff --git a/JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingCard.swift b/JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingCard.swift new file mode 100644 index 00000000..979561f6 --- /dev/null +++ b/JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingCard.swift @@ -0,0 +1,71 @@ +// + /* + * 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 JellyfinAPI +import SwiftUI + +struct ContinueWatchingCard: View { + + @EnvironmentObject var homeRouter: HomeCoordinator.Router + let item: BaseItemDto + + var body: some View { + VStack(alignment: .leading) { + Button { + homeRouter.route(to: \.modalItem, item) + } label: { + ZStack(alignment: .bottom) { + + ImageView(src: item.getBackdropImage(maxWidth: 500)) + .frame(width: 500, height: 281.25) + + VStack(alignment: .leading, spacing: 0) { + Text(item.getItemProgressString() ?? "") + .font(.subheadline) + .padding(.vertical, 5) + .padding(.leading, 10) + .foregroundColor(.white) + + HStack { + Color(UIColor.systemPurple) + .frame(width: 500 * (item.userData?.playedPercentage ?? 0) / 100, height: 13) + + Spacer(minLength: 0) + } + } + .background { + LinearGradient(colors: [.clear, .black.opacity(0.5), .black.opacity(0.7)], + startPoint: .top, + endPoint: .bottom) + .ignoresSafeArea() + } + } + .frame(width: 500, height: 281.25) + } + .buttonStyle(CardButtonStyle()) + .padding(.top) + + VStack(alignment: .leading) { + Text("\(item.seriesName ?? item.name ?? "")") + .font(.callout) + .fontWeight(.semibold) + .foregroundColor(.primary) + .lineLimit(1) + + if item.itemType == .episode { + Text(item.getEpisodeLocator() ?? "") + .font(.callout) + .fontWeight(.medium) + .foregroundColor(.secondary) + .lineLimit(1) + } + } + } + } +} diff --git a/JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingView.swift b/JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingView.swift new file mode 100644 index 00000000..b1b80cbd --- /dev/null +++ b/JellyfinPlayer tvOS/Views/ContinueWatchingView/ContinueWatchingView.swift @@ -0,0 +1,37 @@ +/* + * JellyfinPlayer/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 SwiftUI +import JellyfinAPI +import Combine +import Stinsen + +struct ContinueWatchingView: View { + + @EnvironmentObject var homeRouter: HomeCoordinator.Router + let items: [BaseItemDto] + + var body: some View { + VStack(alignment: .leading) { + + L10n.continueWatching.text + .font(.title3) + .fontWeight(.semibold) + .padding(.leading, 50) + + ScrollView(.horizontal, showsIndicators: false) { + LazyHStack { + ForEach(items, id: \.self) { item in + ContinueWatchingCard(item: item) + } + } + .padding(.horizontal, 50) + } + } + } +} diff --git a/JellyfinPlayer tvOS/Views/HomeView.swift b/JellyfinPlayer tvOS/Views/HomeView.swift index 243ea8d6..0c67b482 100644 --- a/JellyfinPlayer tvOS/Views/HomeView.swift +++ b/JellyfinPlayer tvOS/Views/HomeView.swift @@ -11,62 +11,48 @@ import Foundation import SwiftUI struct HomeView: View { + @EnvironmentObject var homeRouter: HomeCoordinator.Router - @StateObject var viewModel = HomeViewModel() + @ObservedObject var viewModel = HomeViewModel() @State var showingSettings = false var body: some View { - ZStack { - Color.black - .ignoresSafeArea() - - if viewModel.isLoading { - ProgressView() - .scaleEffect(2) - } else { - ScrollView { - LazyVStack(alignment: .leading) { - if !viewModel.resumeItems.isEmpty { - ContinueWatchingView(items: viewModel.resumeItems) - } - - if !viewModel.nextUpItems.isEmpty { - NextUpView(items: viewModel.nextUpItems) - } - - ForEach(viewModel.libraries, id: \.self) { library in - Button { - self.homeRouter.route(to: \.modalLibrary, (.init(parentID: library.id, filters: viewModel.recentFilterSet), title: library.name ?? "")) - } label: { - HStack { - Text(L10n.latestWithString(library.name ?? "")) - .font(.headline) - .fontWeight(.semibold) - Image(systemName: "chevron.forward.circle.fill") - } - }.padding(EdgeInsets(top: 0, leading: 90, bottom: 0, trailing: 0)) - - LatestMediaView(usingParentID: library.id ?? "") - } - - Spacer(minLength: 100) - - HStack { - Spacer() - - Button { - viewModel.refresh() - } label: { - Text("Refresh") - } - - Spacer() - } - .focusSection() + if viewModel.isLoading { + ProgressView() + .scaleEffect(2) + } else { + ScrollView { + LazyVStack(alignment: .leading) { + if !viewModel.resumeItems.isEmpty { + ContinueWatchingView(items: viewModel.resumeItems) } + + if !viewModel.nextUpItems.isEmpty { + NextUpView(items: viewModel.nextUpItems) + } + + ForEach(viewModel.libraries, id: \.self) { library in + LatestMediaView(viewModel: LatestMediaViewModel(library: library)) + } + + Spacer(minLength: 100) + + HStack { + Spacer() + + Button { + viewModel.refresh() + } label: { + Text("Refresh") + } + + Spacer() + } + .focusSection() } } + .edgesIgnoringSafeArea(.horizontal) } } } diff --git a/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift b/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift index e438421d..915099c9 100644 --- a/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift +++ b/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift @@ -13,6 +13,7 @@ import SwiftUI struct CinematicEpisodeItemView: View { + @EnvironmentObject var itemRouter: ItemCoordinator.Router @ObservedObject var viewModel: EpisodeItemViewModel @State var wrappedScrollView: UIScrollView? @Default(.showPosterLabels) var showPosterLabels @@ -46,7 +47,9 @@ struct CinematicEpisodeItemView: View { if !viewModel.similarItems.isEmpty { PortraitItemsRowView(rowTitle: "Recommended", items: viewModel.similarItems, - showItemTitles: showPosterLabels) + showItemTitles: showPosterLabels) { item in + itemRouter.route(to: \.item, item) + } } ItemDetailsView(viewModel: viewModel) diff --git a/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift b/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift index 6363fcf5..42d24639 100644 --- a/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift +++ b/JellyfinPlayer tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift @@ -13,6 +13,7 @@ import SwiftUI struct CinematicMovieItemView: View { + @EnvironmentObject var itemRouter: ItemCoordinator.Router @ObservedObject var viewModel: MovieItemViewModel @State var wrappedScrollView: UIScrollView? @Default(.showPosterLabels) var showPosterLabels @@ -42,7 +43,9 @@ struct CinematicMovieItemView: View { if !viewModel.similarItems.isEmpty { PortraitItemsRowView(rowTitle: "Recommended", items: viewModel.similarItems, - showItemTitles: showPosterLabels) + showItemTitles: showPosterLabels) { item in + itemRouter.route(to: \.item, item) + } } ItemDetailsView(viewModel: viewModel) diff --git a/JellyfinPlayer tvOS/Views/ItemView/PortraitItemsRowView.swift b/JellyfinPlayer tvOS/Views/ItemView/PortraitItemsRowView.swift index 08358d3b..72c69de2 100644 --- a/JellyfinPlayer tvOS/Views/ItemView/PortraitItemsRowView.swift +++ b/JellyfinPlayer tvOS/Views/ItemView/PortraitItemsRowView.swift @@ -17,11 +17,16 @@ struct PortraitItemsRowView: View { let rowTitle: String let items: [BaseItemDto] let showItemTitles: Bool + let selectedAction: (BaseItemDto) -> Void - init(rowTitle: String, items: [BaseItemDto], showItemTitles: Bool = true) { + init(rowTitle: String, + items: [BaseItemDto], + showItemTitles: Bool = true, + selectedAction: @escaping (BaseItemDto) -> Void) { self.rowTitle = rowTitle self.items = items self.showItemTitles = showItemTitles + self.selectedAction = selectedAction } var body: some View { @@ -37,7 +42,7 @@ struct PortraitItemsRowView: View { VStack(spacing: 15) { Button { - itemRouter.route(to: \.item, item) + selectedAction(item) } label: { ImageView(src: item.portraitHeaderViewURL(maxWidth: 257)) .frame(width: 257, height: 380) diff --git a/JellyfinPlayer tvOS/Views/LatestMediaView.swift b/JellyfinPlayer tvOS/Views/LatestMediaView.swift index 79905357..5f5d14ea 100644 --- a/JellyfinPlayer tvOS/Views/LatestMediaView.swift +++ b/JellyfinPlayer tvOS/Views/LatestMediaView.swift @@ -5,49 +5,21 @@ * Copyright 2021 Aiden Vigue & Jellyfin Contributors */ -import SwiftUI +import Defaults import JellyfinAPI -import Combine +import SwiftUI struct LatestMediaView: View { - - @StateObject var tempViewModel = ViewModel() - @State var items: [BaseItemDto] = [] - @State private var viewDidLoad: Bool = false - private var library_id: String = "" - - init(usingParentID: String) { - library_id = usingParentID - } - - func onAppear() { - if viewDidLoad == true { - return - } - viewDidLoad = true - - UserLibraryAPI.getLatestMedia(userId: SessionManager.main.currentLogin.user.id, parentId: library_id, fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people, .chapters], enableUserData: true, limit: 12) - .sink(receiveCompletion: { completion in - print(completion) - }, receiveValue: { response in - items = response - }) - .store(in: &tempViewModel.cancellables) - } - + @EnvironmentObject var homeRouter: HomeCoordinator.Router + @StateObject var viewModel: LatestMediaViewModel + @Default(.showPosterLabels) var showPosterLabels + var body: some View { - ScrollView(.horizontal, showsIndicators: false) { - LazyHStack { - Spacer().frame(width: 45) - ForEach(items, id: \.id) { item in - NavigationLink(destination: LazyView { ItemView(item: item) }) { - PortraitItemElement(item: item) - }.buttonStyle(PlainNavigationLinkButtonStyle()) - } - Spacer().frame(width: 45) - } - }.frame(height: 480) - .onAppear(perform: onAppear) + PortraitItemsRowView(rowTitle: L10n.latestWithString(viewModel.library.name ?? ""), + items: viewModel.items, + showItemTitles: showPosterLabels) { item in + homeRouter.route(to: \.modalItem, item) + } } } diff --git a/JellyfinPlayer tvOS/Views/NextUpView.swift b/JellyfinPlayer tvOS/Views/NextUpView.swift deleted file mode 100644 index aa68e8ac..00000000 --- a/JellyfinPlayer tvOS/Views/NextUpView.swift +++ /dev/null @@ -1,45 +0,0 @@ -/* - * JellyfinPlayer/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 SwiftUI -import JellyfinAPI -import Combine -import Stinsen - -struct NextUpView: View { - var items: [BaseItemDto] - - var homeRouter: HomeCoordinator.Router? = RouterStore.shared.retrieve() - - var body: some View { - VStack(alignment: .leading) { - if items.count > 0 { - L10n.nextUp.text - .font(.headline) - .fontWeight(.semibold) - .padding(.leading, 90) - ScrollView(.horizontal, showsIndicators: false) { - LazyHStack { - Spacer().frame(width: 45) - ForEach(items, id: \.id) { item in - Button { - self.homeRouter?.route(to: \.modalItem, item) - } label: { - LandscapeItemElement(item: item) - }.buttonStyle(PlainNavigationLinkButtonStyle()) - } - Spacer().frame(width: 45) - } - }.frame(height: 350) - .offset(y: -10) - } else { - EmptyView() - } - } - } -} diff --git a/JellyfinPlayer tvOS/Views/NextUpView/NextUpCard.swift b/JellyfinPlayer tvOS/Views/NextUpView/NextUpCard.swift new file mode 100644 index 00000000..b9668785 --- /dev/null +++ b/JellyfinPlayer tvOS/Views/NextUpView/NextUpCard.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 JellyfinAPI +import SwiftUI + +struct NextUpCard: View { + + @EnvironmentObject var homeRouter: HomeCoordinator.Router + let item: BaseItemDto + + var body: some View { + VStack(alignment: .leading) { + Button { + homeRouter.route(to: \.modalItem, item) + } label: { + ImageView(src: item.getBackdropImage(maxWidth: 500)) + .frame(width: 500, height: 281.25) + } + .buttonStyle(CardButtonStyle()) + .padding(.top) + + VStack(alignment: .leading) { + Text("\(item.seriesName ?? item.name ?? "")") + .font(.callout) + .fontWeight(.semibold) + .foregroundColor(.primary) + .lineLimit(1) + + if item.itemType == .episode { + Text(item.getEpisodeLocator() ?? "") + .font(.callout) + .fontWeight(.medium) + .foregroundColor(.secondary) + .lineLimit(1) + } + } + } + } +} diff --git a/JellyfinPlayer tvOS/Views/NextUpView/NextUpView.swift b/JellyfinPlayer tvOS/Views/NextUpView/NextUpView.swift new file mode 100644 index 00000000..b4d8062c --- /dev/null +++ b/JellyfinPlayer tvOS/Views/NextUpView/NextUpView.swift @@ -0,0 +1,37 @@ +/* + * JellyfinPlayer/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 SwiftUI +import JellyfinAPI +import Combine +import Stinsen + +struct NextUpView: View { + var items: [BaseItemDto] + + var homeRouter: HomeCoordinator.Router? = RouterStore.shared.retrieve() + + var body: some View { + VStack(alignment: .leading) { + + L10n.nextUp.text + .font(.title3) + .fontWeight(.semibold) + .padding(.leading, 50) + + ScrollView(.horizontal, showsIndicators: false) { + LazyHStack { + ForEach(items, id: \.id) { item in + NextUpCard(item: item) + } + } + .padding(.horizontal, 50) + } + } + } +} diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index d1aa7b36..92cf26f1 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -366,6 +366,8 @@ E1AD105C26D9ABDD003E4A08 /* PillHStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD105B26D9ABDD003E4A08 /* PillHStackView.swift */; }; E1AD105F26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */; }; E1AD106226D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD106126D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift */; }; + E1B59FD52786ADE500A5287E /* ContinueWatchingCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B59FD42786ADE500A5287E /* ContinueWatchingCard.swift */; }; + E1B59FD92786AE4600A5287E /* NextUpCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B59FD82786AE4600A5287E /* NextUpCard.swift */; }; E1B6DCE8271A23780015B715 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = E1B6DCE7271A23780015B715 /* CombineExt */; }; E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = E1B6DCE9271A23880015B715 /* SwiftyJSON */; }; E1C812BC277A8E5D00918266 /* PlaybackSpeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1C812B4277A8E5D00918266 /* PlaybackSpeed.swift */; }; @@ -680,6 +682,8 @@ E1AD105B26D9ABDD003E4A08 /* PillHStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillHStackView.swift; sourceTree = ""; }; E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameGUIDPairExtensions.swift; sourceTree = ""; }; E1AD106126D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemPortraitHeaderOverlayView.swift; sourceTree = ""; }; + E1B59FD42786ADE500A5287E /* ContinueWatchingCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinueWatchingCard.swift; sourceTree = ""; }; + E1B59FD82786AE4600A5287E /* NextUpCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextUpCard.swift; sourceTree = ""; }; E1C812B4277A8E5D00918266 /* PlaybackSpeed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaybackSpeed.swift; sourceTree = ""; }; E1C812B5277A8E5D00918266 /* PlayerOverlayDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerOverlayDelegate.swift; sourceTree = ""; }; E1C812B6277A8E5D00918266 /* VLCPlayerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VLCPlayerViewController.swift; sourceTree = ""; }; @@ -1295,7 +1299,7 @@ children = ( 53ABFDEA2679753200886593 /* ConnectToServerView.swift */, E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */, - 531690EB267ABF46005D8AB9 /* ContinueWatchingView.swift */, + E1B59FD62786AE2C00A5287E /* ContinueWatchingView */, 531690E6267ABD79005D8AB9 /* HomeView.swift */, E193D54E271942C000900D82 /* ItemView */, 536D3D7E267BDF100004248C /* LatestMediaView.swift */, @@ -1308,7 +1312,7 @@ C4BE078D27298817003F4AD1 /* LiveTVHomeView.swift */, C40CD927271F8DAB000FB198 /* MovieLibrariesView.swift */, C4BE0768271FC164003F4AD1 /* TVLibrariesView.swift */, - 531690EE267ABF72005D8AB9 /* NextUpView.swift */, + E1B59FD72786AE3E00A5287E /* NextUpView */, E193D54F2719430400900D82 /* ServerDetailView.swift */, E193D54A271941D300900D82 /* ServerListView.swift */, E1E5D54D2783E66600692DFE /* SettingsView */, @@ -1481,6 +1485,24 @@ path = Views; sourceTree = ""; }; + E1B59FD62786AE2C00A5287E /* ContinueWatchingView */ = { + isa = PBXGroup; + children = ( + E1B59FD42786ADE500A5287E /* ContinueWatchingCard.swift */, + 531690EB267ABF46005D8AB9 /* ContinueWatchingView.swift */, + ); + path = ContinueWatchingView; + sourceTree = ""; + }; + E1B59FD72786AE3E00A5287E /* NextUpView */ = { + isa = PBXGroup; + children = ( + 531690EE267ABF72005D8AB9 /* NextUpView.swift */, + E1B59FD82786AE4600A5287E /* NextUpCard.swift */, + ); + path = NextUpView; + sourceTree = ""; + }; E1C812CF277AE4C700918266 /* VideoPlayerCoordinator */ = { isa = PBXGroup; children = ( @@ -1993,6 +2015,7 @@ 531690ED267ABF46005D8AB9 /* ContinueWatchingView.swift in Sources */, E17885A4278105170094FBCF /* SFSymbolButton.swift in Sources */, E13DD3ED27178A54009D4DAF /* UserSignInViewModel.swift in Sources */, + E1B59FD92786AE4600A5287E /* NextUpCard.swift in Sources */, 62EC3530267666A5000E9F2D /* SessionManager.swift in Sources */, E1E5D5372783A52C00692DFE /* CinematicEpisodeItemView.swift in Sources */, C4BE078E27298818003F4AD1 /* LiveTVHomeView.swift in Sources */, @@ -2064,6 +2087,7 @@ E1E5D54F2783E67100692DFE /* OverlaySettingsView.swift in Sources */, 53272537268C1DBB0035FBF1 /* SeasonItemView.swift in Sources */, 09389CC526814E4500AE350E /* DeviceProfileBuilder.swift in Sources */, + E1B59FD52786ADE500A5287E /* ContinueWatchingCard.swift in Sources */, E1C812D2277AE50A00918266 /* URLComponentsExtensions.swift in Sources */, E1E00A36278628A40022235B /* DoubleExtensions.swift in Sources */, E1FA2F7427818A8800B4C270 /* SmallMenuOverlay.swift in Sources */, diff --git a/Shared/ViewModels/LatestMediaViewModel.swift b/Shared/ViewModels/LatestMediaViewModel.swift index cca5b38e..88cc1564 100644 --- a/Shared/ViewModels/LatestMediaViewModel.swift +++ b/Shared/ViewModels/LatestMediaViewModel.swift @@ -14,11 +14,11 @@ import JellyfinAPI final class LatestMediaViewModel: ViewModel { @Published var items = [BaseItemDto]() + + let library: BaseItemDto - var libraryID: String - - init(libraryID: String) { - self.libraryID = libraryID + init(library: BaseItemDto) { + self.library = library super.init() requestLatestMedia() @@ -27,7 +27,7 @@ final class LatestMediaViewModel: ViewModel { func requestLatestMedia() { LogManager.shared.log.debug("Requesting latest media for user id \(SessionManager.main.currentLogin.user.id)") UserLibraryAPI.getLatestMedia(userId: SessionManager.main.currentLogin.user.id, - parentId: libraryID, + parentId: library.id ?? "", fields: [ .primaryImageAspectRatio, .seriesPrimaryImage,