mirror of
https://github.com/jellyfin/Swiftfin.git
synced 2024-12-02 11:06:33 +00:00
add EpisodeItemViewModel
This commit is contained in:
parent
7267b37cb7
commit
4fb792ec24
@ -125,6 +125,8 @@
|
||||
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 */; };
|
||||
62E632E6267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.swift */; };
|
||||
62E632E7267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.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 */; };
|
||||
@ -277,6 +279,7 @@
|
||||
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>"; };
|
||||
62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EpisodeItemViewModel.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>"; };
|
||||
@ -342,6 +345,7 @@
|
||||
62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */,
|
||||
62E632DF267D30CA0063E547 /* LibraryViewModel.swift */,
|
||||
62E632E2267D3BA60063E547 /* MovieItemViewModel.swift */,
|
||||
62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.swift */,
|
||||
);
|
||||
path = ViewModels;
|
||||
sourceTree = "<group>";
|
||||
@ -718,6 +722,7 @@
|
||||
535870A82669D8AE00D05A09 /* StringExtensions.swift in Sources */,
|
||||
53ABFDE6267974EF00886593 /* SettingsViewModel.swift in Sources */,
|
||||
6267B3D826710B9800A7371D /* CollectionExtensions.swift in Sources */,
|
||||
62E632E7267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */,
|
||||
535870A52669D8AE00D05A09 /* ParallaxHeader.swift in Sources */,
|
||||
531690F0267ABF72005D8AB9 /* NextUpView.swift in Sources */,
|
||||
535870A72669D8AE00D05A09 /* MultiSelectorView.swift in Sources */,
|
||||
@ -768,6 +773,7 @@
|
||||
53892770263C25230035E14B /* NextUpView.swift in Sources */,
|
||||
625CB5682678B6FB00530A6E /* SplashView.swift in Sources */,
|
||||
535BAEA5264A151C005FA86D /* VideoPlayer.swift in Sources */,
|
||||
62E632E6267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */,
|
||||
5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */,
|
||||
532175402671EE4F005491E6 /* LibraryFilterView.swift in Sources */,
|
||||
5377CC01263B596B003A4E83 /* Model.xcdatamodeld in Sources */,
|
||||
|
@ -11,62 +11,14 @@ import Combine
|
||||
|
||||
struct EpisodeItemView: View {
|
||||
@StateObject
|
||||
var tempViewModel = ViewModel()
|
||||
var viewModel: EpisodeItemViewModel
|
||||
@State private var orientation = UIDeviceOrientation.unknown
|
||||
@Environment(\.horizontalSizeClass) var hSizeClass
|
||||
@Environment(\.verticalSizeClass) var vSizeClass
|
||||
@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)
|
||||
}
|
||||
@ -74,27 +26,27 @@ struct EpisodeItemView: View {
|
||||
var portraitHeaderOverlayView: some View {
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .bottom, spacing: 12) {
|
||||
ImageView(src: item.getSeriesPrimaryImage(maxWidth: 120), bh: item.getSeriesPrimaryImageBlurHash())
|
||||
ImageView(src: viewModel.item.getSeriesPrimaryImage(maxWidth: 120), bh: viewModel.item.getSeriesPrimaryImageBlurHash())
|
||||
.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)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.offset(y: 5)
|
||||
HStack {
|
||||
Text(String(item.productionYear ?? 0)).font(.subheadline)
|
||||
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)
|
||||
@ -109,11 +61,11 @@ struct EpisodeItemView: 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))
|
||||
}
|
||||
@ -125,19 +77,21 @@ struct EpisodeItemView: 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 {
|
||||
@ -145,6 +99,7 @@ struct EpisodeItemView: View {
|
||||
.font(.system(size: 20))
|
||||
}
|
||||
}
|
||||
.disabled(viewModel.isLoading)
|
||||
}
|
||||
}.padding(.top, 8)
|
||||
}
|
||||
@ -160,19 +115,19 @@ struct EpisodeItemView: 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 ?? "")
|
||||
}) {
|
||||
@ -182,13 +137,13 @@ struct EpisodeItemView: 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 ?? "")
|
||||
@ -213,11 +168,11 @@ struct EpisodeItemView: 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 ?? "")
|
||||
}) {
|
||||
@ -233,7 +188,7 @@ struct EpisodeItemView: 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)
|
||||
@ -241,16 +196,16 @@ struct EpisodeItemView: View {
|
||||
.blur(radius: 4)
|
||||
HStack {
|
||||
VStack {
|
||||
ImageView(src: item.getSeriesPrimaryImage(maxWidth: 120), bh: item.getSeriesPrimaryImageBlurHash())
|
||||
ImageView(src: viewModel.item.getSeriesPrimaryImage(maxWidth: 120), bh: viewModel.item.getSeriesPrimaryImageBlurHash())
|
||||
.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))
|
||||
}
|
||||
@ -265,23 +220,23 @@ struct EpisodeItemView: 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 {
|
||||
Text(String(item.productionYear ?? 0)).font(.subheadline)
|
||||
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)
|
||||
@ -289,10 +244,10 @@ struct EpisodeItemView: 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)
|
||||
@ -306,20 +261,21 @@ struct EpisodeItemView: 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 {
|
||||
@ -327,21 +283,22 @@ struct EpisodeItemView: 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 ?? "")
|
||||
}) {
|
||||
@ -353,13 +310,13 @@ struct EpisodeItemView: 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 ?? "")
|
||||
@ -384,11 +341,11 @@ struct EpisodeItemView: 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 ?? "")
|
||||
}) {
|
||||
@ -409,15 +366,10 @@ struct EpisodeItemView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear(perform: {
|
||||
favorite = item.userData?.isFavorite ?? false
|
||||
watched = item.userData?.played ?? false
|
||||
settingState = false
|
||||
})
|
||||
.onRotate(perform: { orientation in
|
||||
self.orientation = orientation
|
||||
})
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationTitle("\(item.seriesName ?? "") - S\(String(item.parentIndexNumber ?? 0)):E\(String(item.indexNumber ?? 0))")
|
||||
.navigationTitle("\(viewModel.item.seriesName ?? "") - S\(String(viewModel.item.parentIndexNumber ?? 0)):E\(String(viewModel.item.indexNumber ?? 0))")
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ struct ItemView: View {
|
||||
} else if item.type == "Series" {
|
||||
SeriesItemView(item: item)
|
||||
} else if item.type == "Episode" {
|
||||
EpisodeItemView(item: item)
|
||||
EpisodeItemView(viewModel: .init(item: item))
|
||||
} else {
|
||||
Text("Type: \(item.type ?? "") not implemented yet :(")
|
||||
}
|
||||
|
75
Shared/ViewModels/EpisodeItemViewModel.swift
Normal file
75
Shared/ViewModels/EpisodeItemViewModel.swift
Normal file
@ -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 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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user