update item after playback close
This commit is contained in:
parent
0df99b9899
commit
53048d7d14
|
@ -13,6 +13,9 @@ import UIKit
|
|||
|
||||
extension BaseItemDto {
|
||||
func createVideoPlayerViewModel() -> AnyPublisher<VideoPlayerViewModel, Error> {
|
||||
|
||||
LogManager.shared.log.debug("Creating video player view model for item: \(id ?? "")")
|
||||
|
||||
let builder = DeviceProfileBuilder()
|
||||
// TODO: fix bitrate settings
|
||||
builder.setMaxBitrate(bitrate: 60_000_000)
|
||||
|
|
|
@ -20,5 +20,8 @@ enum SwiftfinNotificationCenter {
|
|||
static let processDeepLink = Notification.Name("processDeepLink")
|
||||
static let didPurge = Notification.Name("didPurge")
|
||||
static let didChangeServerCurrentURI = Notification.Name("didChangeCurrentLoginURI")
|
||||
|
||||
// Send with an item id to check if current item for item views
|
||||
static let didSendStopReport = Notification.Name("didSendStopReport")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,6 @@ final class EpisodeItemViewModel: ItemViewModel {
|
|||
return "\(episodeLocator)\n\(item.name ?? "")"
|
||||
}
|
||||
|
||||
override func shouldDisplayRuntime() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
func getEpisodeSeries() {
|
||||
guard let id = item.seriesId else { return }
|
||||
UserLibraryAPI.getItem(userId: SessionManager.main.currentLogin.user.id, itemId: id)
|
||||
|
@ -44,4 +40,29 @@ final class EpisodeItemViewModel: ItemViewModel {
|
|||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
override func updateItem() {
|
||||
ItemsAPI.getItems(userId: SessionManager.main.currentLogin.user.id,
|
||||
limit: 1,
|
||||
fields: [
|
||||
.primaryImageAspectRatio,
|
||||
.seriesPrimaryImage,
|
||||
.seasonUserData,
|
||||
.overview,
|
||||
.genres,
|
||||
.people,
|
||||
.chapters,
|
||||
],
|
||||
enableUserData: true,
|
||||
ids: [item.id ?? ""])
|
||||
.sink { completion in
|
||||
self.handleAPIRequestError(completion: completion)
|
||||
} receiveValue: { response in
|
||||
if let item = response.items?.first {
|
||||
self.item = item
|
||||
self.playButtonItem = item
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,9 +54,27 @@ class ItemViewModel: ViewModel {
|
|||
|
||||
getSimilarItems()
|
||||
|
||||
SwiftfinNotificationCenter.main.addObserver(self,
|
||||
selector: #selector(receivedStopReport(_:)),
|
||||
name: SwiftfinNotificationCenter.Keys.didSendStopReport,
|
||||
object: nil)
|
||||
|
||||
refreshItemVideoPlayerViewModel(for: item)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func receivedStopReport(_ notification: NSNotification) {
|
||||
guard let itemID = notification.object as? String else { return }
|
||||
|
||||
if itemID == item.id {
|
||||
updateItem()
|
||||
} else {
|
||||
// Remove if necessary. Note that this cannot be in deinit as
|
||||
// holding as an observer won't allow the object to be deinit-ed
|
||||
SwiftfinNotificationCenter.main.removeObserver(self)
|
||||
}
|
||||
}
|
||||
|
||||
func refreshItemVideoPlayerViewModel(for item: BaseItemDto) {
|
||||
item.createVideoPlayerViewModel()
|
||||
.sink { completion in
|
||||
|
@ -139,4 +157,7 @@ class ItemViewModel: ViewModel {
|
|||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
||||
// Overridden by subclasses
|
||||
func updateItem() {}
|
||||
}
|
||||
|
|
|
@ -10,4 +10,30 @@ import Combine
|
|||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
final class MovieItemViewModel: ItemViewModel {}
|
||||
final class MovieItemViewModel: ItemViewModel {
|
||||
|
||||
override func updateItem() {
|
||||
ItemsAPI.getItems(userId: SessionManager.main.currentLogin.user.id,
|
||||
limit: 1,
|
||||
fields: [
|
||||
.primaryImageAspectRatio,
|
||||
.seriesPrimaryImage,
|
||||
.seasonUserData,
|
||||
.overview,
|
||||
.genres,
|
||||
.people,
|
||||
.chapters,
|
||||
],
|
||||
enableUserData: true,
|
||||
ids: [item.id ?? ""])
|
||||
.sink { completion in
|
||||
self.handleAPIRequestError(completion: completion)
|
||||
} receiveValue: { response in
|
||||
if let item = response.items?.first {
|
||||
self.item = item
|
||||
self.playButtonItem = item
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ extension VideoPlayerViewModel {
|
|||
adjacentTo: item.id,
|
||||
limit: 3)
|
||||
.sink(receiveCompletion: { completion in
|
||||
print(completion)
|
||||
self.handleAPIRequestError(completion: completion)
|
||||
}, receiveValue: { response in
|
||||
|
||||
// 4 possible states:
|
||||
|
@ -510,6 +510,8 @@ extension VideoPlayerViewModel {
|
|||
self.handleAPIRequestError(completion: completion)
|
||||
} receiveValue: { _ in
|
||||
LogManager.shared.log.debug("Stop report sent for item: \(self.item.id ?? "No ID")")
|
||||
SwiftfinNotificationCenter.main.post(name: SwiftfinNotificationCenter.Keys.didSendStopReport,
|
||||
object: self.item.id)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
@ -536,3 +538,13 @@ extension VideoPlayerViewModel {
|
|||
return newURL.url!
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Equatable
|
||||
|
||||
extension VideoPlayerViewModel: Equatable {
|
||||
|
||||
static func == (lhs: VideoPlayerViewModel, rhs: VideoPlayerViewModel) -> Bool {
|
||||
lhs.item.id == rhs.item.id &&
|
||||
lhs.item.userData?.playbackPositionTicks == rhs.item.userData?.playbackPositionTicks
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2773,7 +2773,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
EXCLUDED_ARCHS = "";
|
||||
|
@ -2810,7 +2810,7 @@
|
|||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
EXCLUDED_ARCHS = "";
|
||||
|
@ -2841,7 +2841,7 @@
|
|||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -2868,7 +2868,7 @@
|
|||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = TY84JMYEFE;
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
|
|
@ -54,8 +54,7 @@ struct ItemViewBody: View {
|
|||
topBarView: {
|
||||
L10n.seasons.text
|
||||
.fontWeight(.semibold)
|
||||
.padding(.bottom)
|
||||
.padding(.horizontal)
|
||||
.padding()
|
||||
}, selectedAction: { season in
|
||||
itemRouter.route(to: \.item, season)
|
||||
})
|
||||
|
@ -63,14 +62,14 @@ struct ItemViewBody: View {
|
|||
|
||||
// MARK: Genres
|
||||
|
||||
if let genres = viewModel.item.genreItems {
|
||||
PillHStackView(title: L10n.genres,
|
||||
items: genres,
|
||||
selectedAction: { genre in
|
||||
itemRouter.route(to: \.library, (viewModel: .init(genre: genre), title: genre.title))
|
||||
})
|
||||
.padding(.bottom)
|
||||
}
|
||||
if let genres = viewModel.item.genreItems {
|
||||
PillHStackView(title: L10n.genres,
|
||||
items: genres,
|
||||
selectedAction: { genre in
|
||||
itemRouter.route(to: \.library, (viewModel: .init(genre: genre), title: genre.title))
|
||||
})
|
||||
.padding(.bottom)
|
||||
}
|
||||
|
||||
// MARK: Studios
|
||||
|
||||
|
@ -120,7 +119,7 @@ struct ItemViewBody: View {
|
|||
// MARK: Cast & Crew
|
||||
|
||||
if showCastAndCrew {
|
||||
if let castAndCrew = viewModel.item.people, castAndCrew.count > 0 {
|
||||
if let castAndCrew = viewModel.item.people, !castAndCrew.isEmpty {
|
||||
PortraitImageHStackView(items: castAndCrew.filter { BaseItemPerson.DisplayedType.allCasesRaw.contains($0.type ?? "") },
|
||||
topBarView: {
|
||||
L10n.castAndCrew.text
|
||||
|
|
|
@ -14,6 +14,8 @@ struct ItemLandscapeMainView: View {
|
|||
var itemRouter: ItemCoordinator.Router
|
||||
@EnvironmentObject
|
||||
private var viewModel: ItemViewModel
|
||||
@State
|
||||
private var playButtonText: String = ""
|
||||
|
||||
// MARK: innerBody
|
||||
|
||||
|
@ -72,6 +74,9 @@ struct ItemLandscapeMainView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
playButtonText = viewModel.playButtonText()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: body
|
||||
|
|
|
@ -15,6 +15,8 @@ struct PortraitHeaderOverlayView: View {
|
|||
var itemRouter: ItemCoordinator.Router
|
||||
@EnvironmentObject
|
||||
private var viewModel: ItemViewModel
|
||||
@State
|
||||
private var playButtonText: String = ""
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
|
@ -37,9 +39,9 @@ struct PortraitHeaderOverlayView: View {
|
|||
.fixedSize(horizontal: false, vertical: true)
|
||||
.padding(.bottom, 10)
|
||||
|
||||
if viewModel.item.itemType.showDetails {
|
||||
// MARK: Runtime
|
||||
// MARK: Details
|
||||
|
||||
HStack {
|
||||
if viewModel.shouldDisplayRuntime() {
|
||||
if let runtime = viewModel.item.getItemRuntime() {
|
||||
Text(runtime)
|
||||
|
@ -49,11 +51,7 @@ struct PortraitHeaderOverlayView: View {
|
|||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Details
|
||||
|
||||
HStack {
|
||||
if let productionYear = viewModel.item.productionYear {
|
||||
Text(String(productionYear))
|
||||
.font(.subheadline)
|
||||
|
@ -88,7 +86,7 @@ struct PortraitHeaderOverlayView: View {
|
|||
Image(systemName: "play.fill")
|
||||
.foregroundColor(viewModel.playButtonItem == nil ? Color(UIColor.secondaryLabel) : Color.white)
|
||||
.font(.system(size: 20))
|
||||
Text(viewModel.playButtonText())
|
||||
Text(playButtonText)
|
||||
.foregroundColor(viewModel.playButtonItem == nil ? Color(UIColor.secondaryLabel) : Color.white)
|
||||
.font(.callout)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -137,7 +135,10 @@ struct PortraitHeaderOverlayView: View {
|
|||
}
|
||||
}.padding(.top, 8)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.onAppear {
|
||||
playButtonText = viewModel.playButtonText()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, UIDevice.current.userInterfaceIdiom == .pad ? -189 : -64)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue