add MovieItemViewModel
This commit is contained in:
parent
0265f46171
commit
7267b37cb7
|
@ -123,6 +123,8 @@
|
|||
62E632DE267D2E170063E547 /* LatestMediaViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */; };
|
||||
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DF267D30CA0063E547 /* LibraryViewModel.swift */; };
|
||||
62E632E1267D30CA0063E547 /* LibraryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DF267D30CA0063E547 /* LibraryViewModel.swift */; };
|
||||
62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632E2267D3BA60063E547 /* MovieItemViewModel.swift */; };
|
||||
62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632E2267D3BA60063E547 /* MovieItemViewModel.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 */; };
|
||||
|
@ -274,6 +276,7 @@
|
|||
62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestMediaViewModel.swift; sourceTree = "<group>"; };
|
||||
62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = "<group>"; };
|
||||
62E632DF267D30CA0063E547 /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = "<group>"; };
|
||||
62E632E2267D3BA60063E547 /* MovieItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieItemViewModel.swift; sourceTree = "<group>"; };
|
||||
62EC352B26766675000E9F2D /* ServerEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerEnvironment.swift; sourceTree = "<group>"; };
|
||||
62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = "<group>"; };
|
||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
||||
|
@ -338,6 +341,7 @@
|
|||
62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */,
|
||||
62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */,
|
||||
62E632DF267D30CA0063E547 /* LibraryViewModel.swift */,
|
||||
62E632E2267D3BA60063E547 /* MovieItemViewModel.swift */,
|
||||
);
|
||||
path = ViewModels;
|
||||
sourceTree = "<group>";
|
||||
|
@ -722,6 +726,7 @@
|
|||
531690E5267ABD5C005D8AB9 /* MainTabView.swift in Sources */,
|
||||
53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */,
|
||||
53ABFDEE26799DCD00886593 /* ImageView.swift in Sources */,
|
||||
62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||
5358706C2669D21700D05A09 /* PersistenceController.swift in Sources */,
|
||||
535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */,
|
||||
53ABFDE5267974EF00886593 /* ViewModel.swift in Sources */,
|
||||
|
@ -776,6 +781,7 @@
|
|||
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */,
|
||||
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
||||
62EC352F267666A5000E9F2D /* SessionManager.swift in Sources */,
|
||||
62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||
535870AD2669D8DD00D05A09 /* Typings.swift in Sources */,
|
||||
62EC352C26766675000E9F2D /* ServerEnvironment.swift in Sources */,
|
||||
6267B3DA2671138200A7371D /* ImageExtensions.swift in Sources */,
|
||||
|
|
|
@ -39,7 +39,7 @@ struct ItemView: View {
|
|||
}
|
||||
VStack {
|
||||
if item.type == "Movie" {
|
||||
MovieItemView(item: item)
|
||||
MovieItemView(viewModel: .init(item: item))
|
||||
} else if item.type == "Season" {
|
||||
SeasonItemView(item: item)
|
||||
} else if item.type == "Series" {
|
||||
|
|
|
@ -11,7 +11,7 @@ import SwiftUI
|
|||
|
||||
struct MovieItemView: View {
|
||||
@StateObject
|
||||
var tempViewModel = ViewModel()
|
||||
var viewModel: MovieItemViewModel
|
||||
@State
|
||||
private var orientation = UIDeviceOrientation.unknown
|
||||
@Environment(\.horizontalSizeClass)
|
||||
|
@ -21,60 +21,9 @@ struct MovieItemView: View {
|
|||
@EnvironmentObject
|
||||
private var playbackInfo: VideoPlayerItem
|
||||
|
||||
var item: BaseItemDto
|
||||
|
||||
@State
|
||||
private var settingState: Bool = true
|
||||
@State
|
||||
private var watched: Bool = false {
|
||||
didSet {
|
||||
if !settingState {
|
||||
if watched == true {
|
||||
PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: item.id!)
|
||||
.sink(receiveCompletion: { completion in
|
||||
print(completion)
|
||||
}, receiveValue: { _ in
|
||||
})
|
||||
.store(in: &tempViewModel.cancellables)
|
||||
} else {
|
||||
PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: item.id!)
|
||||
.sink(receiveCompletion: { completion in
|
||||
print(completion)
|
||||
}, receiveValue: { _ in
|
||||
})
|
||||
.store(in: &tempViewModel.cancellables)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@State
|
||||
private var favorite: Bool = false {
|
||||
didSet {
|
||||
if !settingState {
|
||||
if favorite == true {
|
||||
UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: item.id!)
|
||||
.sink(receiveCompletion: { completion in
|
||||
print(completion)
|
||||
}, receiveValue: { _ in
|
||||
})
|
||||
.store(in: &tempViewModel.cancellables)
|
||||
} else {
|
||||
UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: item.id!)
|
||||
.sink(receiveCompletion: { completion in
|
||||
print(completion)
|
||||
}, receiveValue: { _ in
|
||||
})
|
||||
.store(in: &tempViewModel.cancellables)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var portraitHeaderView: some View {
|
||||
ImageView(src: item
|
||||
.getBackdropImage(maxWidth: UIDevice.current.userInterfaceIdiom == .pad ? 622 : Int(UIScreen.main.bounds.width)),
|
||||
bh: item.getBackdropImageBlurHash())
|
||||
ImageView(src: viewModel.item.getBackdropImage(maxWidth: UIDevice.current.userInterfaceIdiom == .pad ? 622 : Int(UIScreen.main.bounds.width)),
|
||||
bh: viewModel.item.getBackdropImageBlurHash())
|
||||
.opacity(0.4)
|
||||
.blur(radius: 2.0)
|
||||
}
|
||||
|
@ -82,29 +31,29 @@ struct MovieItemView: View {
|
|||
var portraitHeaderOverlayView: some View {
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .bottom, spacing: 12) {
|
||||
ImageView(src: item.getPrimaryImage(maxWidth: 120))
|
||||
ImageView(src: viewModel.item.getPrimaryImage(maxWidth: 120))
|
||||
.frame(width: 120, height: 180)
|
||||
.cornerRadius(10)
|
||||
VStack(alignment: .leading) {
|
||||
Spacer()
|
||||
Text(item.name ?? "").font(.headline)
|
||||
Text(viewModel.item.name ?? "").font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(1)
|
||||
.offset(y: 5)
|
||||
HStack {
|
||||
if item.productionYear != nil {
|
||||
Text(String(item.productionYear ?? 0)).font(.subheadline)
|
||||
if viewModel.item.productionYear != nil {
|
||||
Text(String(viewModel.item.productionYear ?? 0)).font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Text(item.getItemRuntime()).font(.subheadline)
|
||||
Text(viewModel.item.getItemRuntime()).font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
if item.officialRating != nil {
|
||||
Text(item.officialRating!).font(.subheadline)
|
||||
if viewModel.item.officialRating != nil {
|
||||
Text(viewModel.item.officialRating!).font(.subheadline)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
|
@ -119,11 +68,11 @@ struct MovieItemView: View {
|
|||
HStack {
|
||||
// Play button
|
||||
Button {
|
||||
self.playbackInfo.itemToPlay = item
|
||||
self.playbackInfo.itemToPlay = viewModel.item
|
||||
self.playbackInfo.shouldShowPlayer = true
|
||||
} label: {
|
||||
HStack {
|
||||
Text(item.getItemProgressString() == "" ? "Play" : "\(item.getItemProgressString()) left")
|
||||
Text(viewModel.item.getItemProgressString() == "" ? "Play" : "\(viewModel.item.getItemProgressString()) left")
|
||||
.foregroundColor(Color.white).font(.callout).fontWeight(.semibold)
|
||||
Image(systemName: "play.fill").foregroundColor(Color.white).font(.system(size: 20))
|
||||
}
|
||||
|
@ -135,19 +84,21 @@ struct MovieItemView: View {
|
|||
Spacer()
|
||||
HStack {
|
||||
Button {
|
||||
favorite.toggle()
|
||||
viewModel.updateFavoriteState()
|
||||
} label: {
|
||||
if !favorite {
|
||||
Image(systemName: "heart").foregroundColor(Color.primary).font(.system(size: 20))
|
||||
} else {
|
||||
if viewModel.isFavorited {
|
||||
Image(systemName: "heart.fill").foregroundColor(Color(UIColor.systemRed))
|
||||
.font(.system(size: 20))
|
||||
} else {
|
||||
Image(systemName: "heart").foregroundColor(Color.primary)
|
||||
.font(.system(size: 20))
|
||||
}
|
||||
}
|
||||
.disabled(viewModel.isLoading)
|
||||
Button {
|
||||
watched.toggle()
|
||||
viewModel.updateWatchState()
|
||||
} label: {
|
||||
if watched {
|
||||
if viewModel.isWatched {
|
||||
Image(systemName: "checkmark.rectangle.fill").foregroundColor(Color.primary)
|
||||
.font(.system(size: 20))
|
||||
} else {
|
||||
|
@ -155,6 +106,7 @@ struct MovieItemView: View {
|
|||
.font(.system(size: 20))
|
||||
}
|
||||
}
|
||||
.disabled(viewModel.isLoading)
|
||||
}
|
||||
}.padding(.top, 8)
|
||||
}
|
||||
|
@ -173,19 +125,19 @@ struct MovieItemView: View {
|
|||
Spacer()
|
||||
.frame(height: UIDevice.current.userInterfaceIdiom == .pad ? 135 : 40)
|
||||
.padding(.bottom, UIDevice.current.userInterfaceIdiom == .pad ? 54 : 24)
|
||||
if !(item.taglines ?? []).isEmpty {
|
||||
Text(item.taglines!.first!).font(.body).italic().padding(.top, 7)
|
||||
if !(viewModel.item.taglines ?? []).isEmpty {
|
||||
Text(viewModel.item.taglines!.first!).font(.body).italic().padding(.top, 7)
|
||||
.fixedSize(horizontal: false, vertical: true).padding(.leading, 16)
|
||||
.padding(.trailing, 16)
|
||||
}
|
||||
Text(item.overview ?? "").font(.footnote).padding(.top, 3)
|
||||
Text(viewModel.item.overview ?? "").font(.footnote).padding(.top, 3)
|
||||
.fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16)
|
||||
.padding(.trailing, 16)
|
||||
if !(item.genreItems ?? []).isEmpty {
|
||||
if !(viewModel.item.genreItems ?? []).isEmpty {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
Text("Genres:").font(.callout).fontWeight(.semibold)
|
||||
ForEach(item.genreItems!, id: \.id) { genre in
|
||||
ForEach(viewModel.item.genreItems!, id: \.id) { genre in
|
||||
NavigationLink(destination: LazyView {
|
||||
LibraryView(viewModel: .init(genre: genre), title: genre.name ?? "")
|
||||
}) {
|
||||
|
@ -195,13 +147,13 @@ struct MovieItemView: View {
|
|||
}.padding(.leading, 16).padding(.trailing, 16)
|
||||
}
|
||||
}
|
||||
if !(item.people ?? []).isEmpty {
|
||||
if !(viewModel.item.people ?? []).isEmpty {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
VStack {
|
||||
Spacer().frame(height: 8)
|
||||
HStack {
|
||||
Spacer().frame(width: 16)
|
||||
ForEach(item.people!, id: \.self) { person in
|
||||
ForEach(viewModel.item.people!, id: \.self) { person in
|
||||
if person.type! == "Actor" {
|
||||
NavigationLink(destination: LazyView {
|
||||
LibraryView(viewModel: .init(person: person), title: person.name ?? "")
|
||||
|
@ -228,11 +180,11 @@ struct MovieItemView: View {
|
|||
}
|
||||
}.padding(.top, -3)
|
||||
}
|
||||
if !(item.studios ?? []).isEmpty {
|
||||
if !(viewModel.item.studios ?? []).isEmpty {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
Text("Studios:").font(.callout).fontWeight(.semibold)
|
||||
ForEach(item.studios!, id: \.id) { studio in
|
||||
ForEach(viewModel.item.studios!, id: \.id) { studio in
|
||||
NavigationLink(destination: LazyView {
|
||||
|
||||
LibraryView(viewModel: .init(studio: studio), title: studio.name ?? "")
|
||||
|
@ -249,8 +201,8 @@ struct MovieItemView: View {
|
|||
} else {
|
||||
GeometryReader { geometry in
|
||||
ZStack {
|
||||
ImageView(src: item.getBackdropImage(maxWidth: 200),
|
||||
bh: item.getBackdropImageBlurHash())
|
||||
ImageView(src: viewModel.item.getBackdropImage(maxWidth: 200),
|
||||
bh: viewModel.item.getBackdropImageBlurHash())
|
||||
.opacity(0.3)
|
||||
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom)
|
||||
|
@ -258,17 +210,17 @@ struct MovieItemView: View {
|
|||
.blur(radius: 4)
|
||||
HStack {
|
||||
VStack {
|
||||
ImageView(src: item.getPrimaryImage(maxWidth: 120),
|
||||
bh: item.getPrimaryImageBlurHash())
|
||||
ImageView(src: viewModel.item.getPrimaryImage(maxWidth: 120),
|
||||
bh: viewModel.item.getPrimaryImageBlurHash())
|
||||
.frame(width: 120, height: 180)
|
||||
.cornerRadius(10)
|
||||
Spacer().frame(height: 15)
|
||||
Button {
|
||||
self.playbackInfo.itemToPlay = item
|
||||
self.playbackInfo.itemToPlay = viewModel.item
|
||||
self.playbackInfo.shouldShowPlayer = true
|
||||
} label: {
|
||||
HStack {
|
||||
Text(item.getItemProgressString() == "" ? "Play" : "\(item.getItemProgressString()) left")
|
||||
Text(viewModel.item.getItemProgressString() == "" ? "Play" : "\(viewModel.item.getItemProgressString()) left")
|
||||
.foregroundColor(Color.white).font(.callout).fontWeight(.semibold)
|
||||
Image(systemName: "play.fill").foregroundColor(Color.white).font(.system(size: 20))
|
||||
}
|
||||
|
@ -283,25 +235,25 @@ struct MovieItemView: View {
|
|||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text(item.name ?? "").font(.headline)
|
||||
Text(viewModel.item.name ?? "").font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(.primary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.offset(x: 14, y: 0)
|
||||
Spacer().frame(height: 1)
|
||||
HStack {
|
||||
if item.productionYear != nil {
|
||||
Text(String(item.productionYear ?? 0)).font(.subheadline)
|
||||
if viewModel.item.productionYear != nil {
|
||||
Text(String(viewModel.item.productionYear ?? 0)).font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Text(item.getItemRuntime()).font(.subheadline)
|
||||
Text(viewModel.item.getItemRuntime()).font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
if item.officialRating != nil {
|
||||
Text(item.officialRating!).font(.subheadline)
|
||||
if viewModel.item.officialRating != nil {
|
||||
Text(viewModel.item.officialRating!).font(.subheadline)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
|
@ -309,10 +261,10 @@ struct MovieItemView: View {
|
|||
.overlay(RoundedRectangle(cornerRadius: 2)
|
||||
.stroke(Color.secondary, lineWidth: 1))
|
||||
}
|
||||
if item.communityRating != nil {
|
||||
if viewModel.item.communityRating != nil {
|
||||
HStack {
|
||||
Image(systemName: "star").foregroundColor(.secondary)
|
||||
Text(String(item.communityRating!)).font(.subheadline)
|
||||
Text(String(viewModel.item.communityRating!)).font(.subheadline)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
|
@ -326,20 +278,21 @@ struct MovieItemView: View {
|
|||
Spacer()
|
||||
HStack {
|
||||
Button {
|
||||
favorite.toggle()
|
||||
viewModel.updateFavoriteState()
|
||||
} label: {
|
||||
if !favorite {
|
||||
Image(systemName: "heart").foregroundColor(Color.primary)
|
||||
if viewModel.isFavorited {
|
||||
Image(systemName: "heart.fill").foregroundColor(Color(UIColor.systemRed))
|
||||
.font(.system(size: 20))
|
||||
} else {
|
||||
Image(systemName: "heart.fill").foregroundColor(Color(UIColor.systemRed))
|
||||
Image(systemName: "heart").foregroundColor(Color.primary)
|
||||
.font(.system(size: 20))
|
||||
}
|
||||
}
|
||||
.disabled(viewModel.isLoading)
|
||||
Button {
|
||||
watched.toggle()
|
||||
viewModel.updateWatchState()
|
||||
} label: {
|
||||
if watched {
|
||||
if viewModel.isWatched {
|
||||
Image(systemName: "checkmark.rectangle.fill").foregroundColor(Color.primary)
|
||||
.font(.system(size: 20))
|
||||
} else {
|
||||
|
@ -347,21 +300,22 @@ struct MovieItemView: View {
|
|||
.font(.system(size: 20))
|
||||
}
|
||||
}
|
||||
.disabled(viewModel.isLoading)
|
||||
}
|
||||
}.padding(.trailing, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 55)
|
||||
if !(item.taglines ?? []).isEmpty {
|
||||
Text(item.taglines!.first!).font(.body).italic().padding(.top, 3)
|
||||
if !(viewModel.item.taglines ?? []).isEmpty {
|
||||
Text(viewModel.item.taglines!.first!).font(.body).italic().padding(.top, 3)
|
||||
.fixedSize(horizontal: false, vertical: true).padding(.leading, 16)
|
||||
.padding(.trailing, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 55)
|
||||
}
|
||||
Text(item.overview ?? "").font(.footnote).padding(.top, 3)
|
||||
Text(viewModel.item.overview ?? "").font(.footnote).padding(.top, 3)
|
||||
.fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16)
|
||||
.padding(.trailing, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 55)
|
||||
if !(item.genreItems ?? []).isEmpty {
|
||||
if !(viewModel.item.genreItems ?? []).isEmpty {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
Text("Genres:").font(.callout).fontWeight(.semibold)
|
||||
ForEach(item.genreItems!, id: \.id) { genre in
|
||||
ForEach(viewModel.item.genreItems!, id: \.id) { genre in
|
||||
NavigationLink(destination: LazyView {
|
||||
LibraryView(viewModel: .init(genre: genre), title: genre.name ?? "")
|
||||
}) {
|
||||
|
@ -373,13 +327,13 @@ struct MovieItemView: View {
|
|||
.padding(.trailing, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 55)
|
||||
}
|
||||
}
|
||||
if !(item.people ?? []).isEmpty {
|
||||
if !(viewModel.item.people ?? []).isEmpty {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
VStack {
|
||||
Spacer().frame(height: 8)
|
||||
HStack {
|
||||
Spacer().frame(width: 16)
|
||||
ForEach(item.people!, id: \.self) { person in
|
||||
ForEach(viewModel.item.people!, id: \.self) { person in
|
||||
if person.type! == "Actor" {
|
||||
NavigationLink(destination: LazyView {
|
||||
LibraryView(viewModel: .init(person: person), title: person.name ?? "")
|
||||
|
@ -408,11 +362,11 @@ struct MovieItemView: View {
|
|||
}
|
||||
}.padding(.top, -3)
|
||||
}
|
||||
if !(item.studios ?? []).isEmpty {
|
||||
if !(viewModel.item.studios ?? []).isEmpty {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
Text("Studios:").font(.callout).fontWeight(.semibold)
|
||||
ForEach(item.studios!, id: \.id) { studio in
|
||||
ForEach(viewModel.item.studios!, id: \.id) { studio in
|
||||
NavigationLink(destination: LazyView {
|
||||
LibraryView(viewModel: .init(studio: studio), title: studio.name ?? "")
|
||||
}) {
|
||||
|
@ -433,15 +387,10 @@ struct MovieItemView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onAppear(perform: {
|
||||
favorite = item.userData?.isFavorite ?? false
|
||||
watched = item.userData?.played ?? false
|
||||
settingState = false
|
||||
})
|
||||
.onRotate {
|
||||
orientation = $0
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationTitle(item.name ?? "")
|
||||
.navigationTitle(viewModel.item.name ?? "")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue