Merge pull request #93 from jellyfin/create-pull-request/patch
[ci] SwiftLint
This commit is contained in:
commit
a2d57dd326
|
@ -91,7 +91,7 @@ struct LandscapeItemElement: View {
|
|||
.shadow(radius: focused ? 10.0 : 0, y: focused ? 10.0 : 0)
|
||||
.shadow(radius: focused ? 10.0 : 0, y: focused ? 10.0 : 0)
|
||||
if focused {
|
||||
if(inSeasonView ?? false) {
|
||||
if inSeasonView ?? false {
|
||||
Text("\(item.getEpisodeLocator()) • \(item.name ?? "")")
|
||||
.font(.callout)
|
||||
.fontWeight(.semibold)
|
||||
|
|
|
@ -15,18 +15,18 @@ struct MediaViewActionButton: View {
|
|||
var icon: String
|
||||
var scrollView: Binding<UIScrollView?>?
|
||||
var iconColor: Color?
|
||||
|
||||
|
||||
var body: some View {
|
||||
Image(systemName: icon)
|
||||
.foregroundColor(focused ? .black : iconColor ?? .white)
|
||||
.onChange(of: envFocused) { envFocus in
|
||||
if(envFocus == true) {
|
||||
if envFocus == true {
|
||||
scrollView?.wrappedValue?.scrollToTop()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
|
||||
scrollView?.wrappedValue?.scrollToTop()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
withAnimation(.linear(duration: 0.15)) {
|
||||
self.focused = envFocus
|
||||
}
|
||||
|
|
|
@ -36,8 +36,7 @@ struct PortraitItemElement: View {
|
|||
}
|
||||
}
|
||||
.padding(2)
|
||||
.opacity(1)
|
||||
, alignment: .bottomLeading)
|
||||
.opacity(1), alignment: .bottomLeading)
|
||||
.overlay(
|
||||
ZStack {
|
||||
if item.userData?.played ?? false {
|
||||
|
@ -46,7 +45,7 @@ struct PortraitItemElement: View {
|
|||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(Color(.systemBlue))
|
||||
} else {
|
||||
if(item.userData?.unplayedItemCount != nil) {
|
||||
if item.userData?.unplayedItemCount != nil {
|
||||
Image(systemName: "circle.fill")
|
||||
.foregroundColor(Color(.systemBlue))
|
||||
Text(String(item.userData!.unplayedItemCount ?? 0))
|
||||
|
|
|
@ -13,30 +13,30 @@ import JellyfinAPI
|
|||
struct EpisodeItemView: View {
|
||||
@ObservedObject var viewModel: EpisodeItemViewModel
|
||||
|
||||
@State var actors: [BaseItemPerson] = [];
|
||||
@State var studio: String? = nil;
|
||||
@State var director: String? = nil;
|
||||
|
||||
@State var actors: [BaseItemPerson] = []
|
||||
@State var studio: String?
|
||||
@State var director: String?
|
||||
|
||||
func onAppear() {
|
||||
actors = []
|
||||
director = nil
|
||||
studio = nil
|
||||
var actor_index = 0;
|
||||
var actor_index = 0
|
||||
viewModel.item.people?.forEach { person in
|
||||
if(person.type == "Actor") {
|
||||
if(actor_index < 4) {
|
||||
if person.type == "Actor" {
|
||||
if actor_index < 4 {
|
||||
actors.append(person)
|
||||
}
|
||||
actor_index = actor_index + 1;
|
||||
actor_index = actor_index + 1
|
||||
}
|
||||
if(person.type == "Director") {
|
||||
if person.type == "Director" {
|
||||
director = person.name ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
studio = viewModel.item.studios?.first?.name ?? nil
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ImageView(src: viewModel.item.getBackdropImage(maxWidth: 1920), bh: viewModel.item.getBackdropImageBlurHash())
|
||||
|
@ -71,10 +71,10 @@ struct EpisodeItemView: View {
|
|||
}
|
||||
Spacer()
|
||||
}.padding(.top, -15)
|
||||
|
||||
|
||||
HStack(alignment: .top) {
|
||||
VStack(alignment: .trailing) {
|
||||
if(studio != nil) {
|
||||
if studio != nil {
|
||||
Text("STUDIO")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -85,8 +85,8 @@ struct EpisodeItemView: View {
|
|||
.foregroundColor(.secondary)
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
|
||||
if(director != nil) {
|
||||
|
||||
if director != nil {
|
||||
Text("DIRECTOR")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -97,8 +97,8 @@ struct EpisodeItemView: View {
|
|||
.foregroundColor(.secondary)
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
|
||||
if(!actors.isEmpty) {
|
||||
|
||||
if !actors.isEmpty {
|
||||
Text("CAST")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -117,7 +117,7 @@ struct EpisodeItemView: View {
|
|||
.font(.body)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
|
||||
HStack {
|
||||
VStack {
|
||||
Button {
|
||||
|
@ -150,7 +150,7 @@ struct EpisodeItemView: View {
|
|||
}
|
||||
}.padding(.top, 50)
|
||||
|
||||
if(!viewModel.similarItems.isEmpty) {
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
Text("More Like This")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
|
|
|
@ -28,11 +28,11 @@ struct LibraryView: View {
|
|||
ScrollView(.vertical) {
|
||||
LazyVGrid(columns: tracks) {
|
||||
ForEach(viewModel.items, id: \.id) { item in
|
||||
if(item.type != "Folder") {
|
||||
if item.type != "Folder" {
|
||||
NavigationLink(destination: LazyView { ItemView(item: item) }) {
|
||||
PortraitItemElement(item: item)
|
||||
}.buttonStyle(PlainNavigationLinkButtonStyle())
|
||||
.onAppear() {
|
||||
.onAppear {
|
||||
if item == viewModel.items.last && viewModel.hasNextPage {
|
||||
print("Last item visible, load more items.")
|
||||
viewModel.requestNextPageAsync()
|
||||
|
|
|
@ -14,36 +14,36 @@ import SwiftUIFocusGuide
|
|||
struct MovieItemView: View {
|
||||
@ObservedObject var viewModel: MovieItemViewModel
|
||||
|
||||
@State var actors: [BaseItemPerson] = [];
|
||||
@State var studio: String? = nil;
|
||||
@State var director: String? = nil;
|
||||
|
||||
@State var wrappedScrollView: UIScrollView?;
|
||||
|
||||
@State var actors: [BaseItemPerson] = []
|
||||
@State var studio: String?
|
||||
@State var director: String?
|
||||
|
||||
@State var wrappedScrollView: UIScrollView?
|
||||
|
||||
@StateObject var focusBag = SwiftUIFocusBag()
|
||||
|
||||
|
||||
@Namespace private var namespace
|
||||
|
||||
|
||||
func onAppear() {
|
||||
actors = []
|
||||
director = nil
|
||||
studio = nil
|
||||
var actor_index = 0;
|
||||
var actor_index = 0
|
||||
viewModel.item.people?.forEach { person in
|
||||
if(person.type == "Actor") {
|
||||
if(actor_index < 4) {
|
||||
if person.type == "Actor" {
|
||||
if actor_index < 4 {
|
||||
actors.append(person)
|
||||
}
|
||||
actor_index = actor_index + 1;
|
||||
actor_index = actor_index + 1
|
||||
}
|
||||
if(person.type == "Director") {
|
||||
if person.type == "Director" {
|
||||
director = person.name ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
studio = viewModel.item.studios?.first?.name ?? nil
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ImageView(src: viewModel.item.getBackdropImage(maxWidth: 1920), bh: viewModel.item.getBackdropImageBlurHash())
|
||||
|
@ -75,10 +75,10 @@ struct MovieItemView: View {
|
|||
.stroke(Color.secondary, lineWidth: 1))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HStack {
|
||||
VStack(alignment: .trailing) {
|
||||
if(studio != nil) {
|
||||
if studio != nil {
|
||||
Text("STUDIO")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -89,8 +89,8 @@ struct MovieItemView: View {
|
|||
.foregroundColor(.secondary)
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
|
||||
if(director != nil) {
|
||||
|
||||
if director != nil {
|
||||
Text("DIRECTOR")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -101,8 +101,8 @@ struct MovieItemView: View {
|
|||
.foregroundColor(.secondary)
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
|
||||
if(!actors.isEmpty) {
|
||||
|
||||
if !actors.isEmpty {
|
||||
Text("CAST")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -117,7 +117,7 @@ struct MovieItemView: View {
|
|||
Spacer()
|
||||
}
|
||||
VStack(alignment: .leading) {
|
||||
if(!(viewModel.item.taglines ?? []).isEmpty) {
|
||||
if !(viewModel.item.taglines ?? []).isEmpty {
|
||||
Text(viewModel.item.taglines?.first ?? "")
|
||||
.font(.body)
|
||||
.italic()
|
||||
|
@ -128,7 +128,7 @@ struct MovieItemView: View {
|
|||
.font(.body)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
|
||||
HStack {
|
||||
VStack {
|
||||
Button {
|
||||
|
@ -162,7 +162,7 @@ struct MovieItemView: View {
|
|||
}
|
||||
}.padding(.top, 50)
|
||||
|
||||
if(!viewModel.similarItems.isEmpty) {
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
Text("More Like This")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
|
|
|
@ -13,13 +13,13 @@ import SwiftUIFocusGuide
|
|||
|
||||
struct SeasonItemView: View {
|
||||
@ObservedObject var viewModel: SeasonItemViewModel
|
||||
@State var wrappedScrollView: UIScrollView?;
|
||||
|
||||
@State var wrappedScrollView: UIScrollView?
|
||||
|
||||
@StateObject var focusBag = SwiftUIFocusBag()
|
||||
|
||||
|
||||
@Environment(\.resetFocus) var resetFocus
|
||||
@Namespace private var namespace
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ImageView(src: viewModel.item.getSeriesBackdropImage(maxWidth: 1920), bh: viewModel.item.getSeriesBackdropImageBlurHash())
|
||||
|
@ -31,7 +31,7 @@ struct SeasonItemView: View {
|
|||
.fontWeight(.bold)
|
||||
.foregroundColor(.primary)
|
||||
HStack {
|
||||
if(viewModel.item.productionYear != nil) {
|
||||
if viewModel.item.productionYear != nil {
|
||||
Text(String(viewModel.item.productionYear!)).font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.secondary)
|
||||
|
@ -58,9 +58,9 @@ struct SeasonItemView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
if(!(viewModel.item.taglines ?? []).isEmpty) {
|
||||
if !(viewModel.item.taglines ?? []).isEmpty {
|
||||
Text(viewModel.item.taglines?.first ?? "")
|
||||
.font(.body)
|
||||
.italic()
|
||||
|
@ -71,7 +71,7 @@ struct SeasonItemView: View {
|
|||
.font(.body)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
|
||||
HStack {
|
||||
VStack {
|
||||
Button {
|
||||
|
@ -96,7 +96,7 @@ struct SeasonItemView: View {
|
|||
Spacer()
|
||||
}.padding(.top, 50)
|
||||
|
||||
if(!viewModel.episodes.isEmpty) {
|
||||
if !viewModel.episodes.isEmpty {
|
||||
Text("Episodes")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
|
|
|
@ -14,14 +14,14 @@ import SwiftUIFocusGuide
|
|||
struct SeriesItemView: View {
|
||||
@ObservedObject var viewModel: SeriesItemViewModel
|
||||
|
||||
@State var actors: [BaseItemPerson] = [];
|
||||
@State var studio: String? = nil;
|
||||
@State var director: String? = nil;
|
||||
|
||||
@State var wrappedScrollView: UIScrollView?;
|
||||
|
||||
@State var actors: [BaseItemPerson] = []
|
||||
@State var studio: String?
|
||||
@State var director: String?
|
||||
|
||||
@State var wrappedScrollView: UIScrollView?
|
||||
|
||||
@StateObject var focusBag = SwiftUIFocusBag()
|
||||
|
||||
|
||||
@Environment(\.resetFocus) var resetFocus
|
||||
@Namespace private var namespace
|
||||
|
||||
|
@ -29,22 +29,22 @@ struct SeriesItemView: View {
|
|||
actors = []
|
||||
director = nil
|
||||
studio = nil
|
||||
var actor_index = 0;
|
||||
var actor_index = 0
|
||||
viewModel.item.people?.forEach { person in
|
||||
if(person.type == "Actor") {
|
||||
if(actor_index < 4) {
|
||||
if person.type == "Actor" {
|
||||
if actor_index < 4 {
|
||||
actors.append(person)
|
||||
}
|
||||
actor_index = actor_index + 1;
|
||||
actor_index = actor_index + 1
|
||||
}
|
||||
if(person.type == "Director") {
|
||||
if person.type == "Director" {
|
||||
director = person.name ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
studio = viewModel.item.studios?.first?.name ?? nil
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ImageView(src: viewModel.item.getBackdropImage(maxWidth: 1920), bh: viewModel.item.getBackdropImageBlurHash())
|
||||
|
@ -81,10 +81,10 @@ struct SeriesItemView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HStack {
|
||||
VStack(alignment: .trailing) {
|
||||
if(studio != nil) {
|
||||
if studio != nil {
|
||||
Text("STUDIO")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -95,8 +95,8 @@ struct SeriesItemView: View {
|
|||
.foregroundColor(.secondary)
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
|
||||
if(director != nil) {
|
||||
|
||||
if director != nil {
|
||||
Text("DIRECTOR")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -107,8 +107,8 @@ struct SeriesItemView: View {
|
|||
.foregroundColor(.secondary)
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
|
||||
if(!actors.isEmpty) {
|
||||
|
||||
if !actors.isEmpty {
|
||||
Text("CAST")
|
||||
.font(.body)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -123,7 +123,7 @@ struct SeriesItemView: View {
|
|||
Spacer()
|
||||
}
|
||||
VStack(alignment: .leading) {
|
||||
if(!(viewModel.item.taglines ?? []).isEmpty) {
|
||||
if !(viewModel.item.taglines ?? []).isEmpty {
|
||||
Text(viewModel.item.taglines?.first ?? "")
|
||||
.font(.body)
|
||||
.italic()
|
||||
|
@ -134,7 +134,7 @@ struct SeriesItemView: View {
|
|||
.font(.body)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
|
||||
HStack {
|
||||
VStack {
|
||||
Button {
|
||||
|
@ -145,7 +145,7 @@ struct SeriesItemView: View {
|
|||
Text(viewModel.isFavorited ? "Unfavorite" : "Favorite")
|
||||
.font(.caption)
|
||||
}
|
||||
if(viewModel.nextUpItem != nil) {
|
||||
if viewModel.nextUpItem != nil {
|
||||
VStack {
|
||||
NavigationLink(destination: VideoPlayerView(item: viewModel.nextUpItem!)) {
|
||||
MediaViewActionButton(icon: "play.fill", scrollView: $wrappedScrollView)
|
||||
|
@ -167,8 +167,8 @@ struct SeriesItemView: View {
|
|||
Spacer()
|
||||
}
|
||||
}.padding(.top, 50)
|
||||
|
||||
if(viewModel.nextUpItem != nil) {
|
||||
|
||||
if viewModel.nextUpItem != nil {
|
||||
Text("Next Up")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -176,8 +176,8 @@ struct SeriesItemView: View {
|
|||
LandscapeItemElement(item: viewModel.nextUpItem!)
|
||||
}.buttonStyle(PlainNavigationLinkButtonStyle()).padding(.bottom, 1)
|
||||
}
|
||||
|
||||
if(!viewModel.seasons.isEmpty) {
|
||||
|
||||
if !viewModel.seasons.isEmpty {
|
||||
Text("Seasons")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -194,8 +194,8 @@ struct SeriesItemView: View {
|
|||
}.padding(EdgeInsets(top: -30, leading: -90, bottom: 0, trailing: -90))
|
||||
.frame(height: 360)
|
||||
}
|
||||
|
||||
if(!viewModel.similarItems.isEmpty) {
|
||||
|
||||
if !viewModel.similarItems.isEmpty {
|
||||
Text("More Like This")
|
||||
.font(.headline)
|
||||
.fontWeight(.semibold)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
import SwiftUI
|
||||
|
||||
class AudioViewController: InfoTabViewController {
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
|
|
@ -11,10 +11,9 @@ import TVUIKit
|
|||
import JellyfinAPI
|
||||
|
||||
class InfoTabViewController: UIViewController {
|
||||
var height : CGFloat = 420
|
||||
var height: CGFloat = 420
|
||||
}
|
||||
|
||||
|
||||
class InfoTabBarViewController: UITabBarController, UIGestureRecognizerDelegate {
|
||||
|
||||
var videoPlayer: VideoPlayerViewController?
|
||||
|
@ -39,11 +38,11 @@ class InfoTabBarViewController: UITabBarController, UIGestureRecognizerDelegate
|
|||
audioViewController?.prepareAudioView(audioTracks: audioTracks, selectedTrack: selectedAudioTrack, delegate: delegate)
|
||||
|
||||
subtitleViewController?.prepareSubtitleView(subtitleTracks: subtitleTracks, selectedTrack: selectedSubtitleTrack, delegate: delegate)
|
||||
|
||||
|
||||
}
|
||||
|
||||
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
|
||||
|
||||
|
||||
if let index = tabBar.items?.firstIndex(of: item),
|
||||
let tabViewController = viewControllers?[index] as? InfoTabViewController,
|
||||
let width = videoPlayer?.infoPanelContainerView.frame.width {
|
||||
|
|
|
@ -50,11 +50,11 @@ struct MediaInfoView: View {
|
|||
if item.type == "Episode" {
|
||||
Text(item.seriesName ?? "Series")
|
||||
.fontWeight(.bold)
|
||||
|
||||
|
||||
HStack {
|
||||
Text(item.name ?? "Episode")
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
|
||||
Text(item.getEpisodeLocator())
|
||||
|
||||
if let date = item.premiereDate {
|
||||
|
@ -67,7 +67,7 @@ struct MediaInfoView: View {
|
|||
}
|
||||
|
||||
HStack(spacing: 10) {
|
||||
if(item.type != "Episode") {
|
||||
if item.type != "Episode" {
|
||||
if let year = item.productionYear {
|
||||
Text(String(year))
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
if let rawStartTicks = manifest.userData?.playbackPositionTicks {
|
||||
mediaPlayer.jumpForward(Int32(rawStartTicks / 10_000_000))
|
||||
}
|
||||
|
||||
|
||||
subtitleTrackArray.forEach { sub in
|
||||
if sub.id != -1 && sub.delivery == .external {
|
||||
mediaPlayer.addPlaybackSlave(sub.url!, type: .subtitle, enforce: false)
|
||||
|
@ -247,13 +247,13 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
let commandCenter = MPRemoteCommandCenter.shared()
|
||||
commandCenter.playCommand.isEnabled = true
|
||||
commandCenter.pauseCommand.isEnabled = true
|
||||
|
||||
|
||||
commandCenter.skipBackwardCommand.isEnabled = true
|
||||
commandCenter.skipBackwardCommand.preferredIntervals = [15]
|
||||
|
||||
|
||||
commandCenter.skipForwardCommand.isEnabled = true
|
||||
commandCenter.skipForwardCommand.preferredIntervals = [30]
|
||||
|
||||
|
||||
commandCenter.changePlaybackPositionCommand.isEnabled = true
|
||||
commandCenter.enableLanguageOptionCommand.isEnabled = true
|
||||
|
||||
|
@ -275,14 +275,14 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
}
|
||||
|
||||
// Add handler for FF command
|
||||
commandCenter.skipForwardCommand.addTarget { skipEvent in
|
||||
commandCenter.skipForwardCommand.addTarget { _ in
|
||||
self.mediaPlayer.jumpForward(30)
|
||||
self.sendProgressReport(eventName: "timeupdate")
|
||||
return .success
|
||||
}
|
||||
|
||||
// Add handler for RW command
|
||||
commandCenter.skipBackwardCommand.addTarget { skipEvent in
|
||||
commandCenter.skipBackwardCommand.addTarget { _ in
|
||||
self.mediaPlayer.jumpBackward(15)
|
||||
self.sendProgressReport(eventName: "timeupdate")
|
||||
return .success
|
||||
|
@ -324,7 +324,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
var nowPlayingInfo = [String: Any]()
|
||||
|
||||
nowPlayingInfo[MPMediaItemPropertyTitle] = manifest.name ?? "Jellyfin Video"
|
||||
if(manifest.type == "Episode") {
|
||||
if manifest.type == "Episode" {
|
||||
nowPlayingInfo[MPMediaItemPropertyArtist] = "\(manifest.seriesName ?? manifest.name ?? "") • \(manifest.getEpisodeLocator())"
|
||||
}
|
||||
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 0.0
|
||||
|
@ -421,26 +421,26 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
|
||||
UIView.animate(withDuration: 0.4, delay: 0, options: .curveEaseOut) { [self] in
|
||||
let size = infoPanelContainerView.frame.size
|
||||
let y : CGFloat = showingInfoPanel ? 87 : -size.height
|
||||
|
||||
let y: CGFloat = showingInfoPanel ? 87 : -size.height
|
||||
|
||||
infoPanelContainerView.frame = CGRect(x: 88, y: y, width: size.width, height: size.height)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: Gestures
|
||||
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
|
||||
for item in presses {
|
||||
if(item.type == .select) {
|
||||
if item.type == .select {
|
||||
selectButtonTapped()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func setupGestures() {
|
||||
self.becomeFirstResponder()
|
||||
|
||||
//vlc crap
|
||||
|
||||
// vlc crap
|
||||
videoContentView.gestureRecognizers?.forEach { gr in
|
||||
videoContentView.removeGestureRecognizer(gr)
|
||||
}
|
||||
|
@ -449,17 +449,17 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
sv.removeGestureRecognizer(gr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let playPauseGesture = UITapGestureRecognizer(target: self, action: #selector(self.selectButtonTapped))
|
||||
let playPauseType = UIPress.PressType.playPause
|
||||
playPauseGesture.allowedPressTypes = [NSNumber(value: playPauseType.rawValue)]
|
||||
view.addGestureRecognizer(playPauseGesture)
|
||||
|
||||
|
||||
let backTapGesture = UITapGestureRecognizer(target: self, action: #selector(self.backButtonPressed(tap:)))
|
||||
let backPress = UIPress.PressType.menu
|
||||
backTapGesture.allowedPressTypes = [NSNumber(value: backPress.rawValue)]
|
||||
view.addGestureRecognizer(backTapGesture)
|
||||
|
||||
|
||||
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.userPanned(panGestureRecognizer:)))
|
||||
view.addGestureRecognizer(panGestureRecognizer)
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
|
||||
let translation = panGestureRecognizer.translation(in: view)
|
||||
let velocity = panGestureRecognizer.velocity(in: view)
|
||||
|
||||
|
||||
// Swiped up - Handle dismissing info panel
|
||||
if translation.y < -200 && (focusedOnTabBar && showingInfoPanel) {
|
||||
toggleInfoContainer()
|
||||
|
@ -580,7 +580,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
|||
// MARK: Jellyfin Playstate updates
|
||||
func sendProgressReport(eventName: String) {
|
||||
updateNowPlayingCenter(time: nil, playing: mediaPlayer.state == .playing)
|
||||
|
||||
|
||||
if (eventName == "timeupdate" && mediaPlayer.state == .playing) || eventName != "timeupdate" {
|
||||
let progressInfo = PlaybackProgressInfo(canSeek: true, item: manifest, itemId: manifest.id, sessionId: playSessionId, mediaSourceId: manifest.id, audioStreamIndex: Int(selectedAudioTrack), subtitleStreamIndex: Int(selectedCaptionTrack), isPaused: (!playing), isMuted: false, positionTicks: Int64(mediaPlayer.position * Float(manifest.runTimeTicks!)), playbackStartTimeTicks: Int64(startTime), volumeLevel: 100, brightness: 100, aspectRatio: nil, playMethod: playbackItem.videoType, liveStreamId: nil, playSessionId: playSessionId, repeatMode: .repeatNone, nowPlayingQueue: [], playlistItemId: "playlistItem0")
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import SwiftUI
|
|||
import JellyfinAPI
|
||||
struct PortraitItemView: View {
|
||||
var item: BaseItemDto
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationLink(destination: LazyView { ItemView(item: item) }) {
|
||||
VStack(alignment: .leading) {
|
||||
|
@ -39,8 +39,7 @@ struct PortraitItemView: View {
|
|||
}
|
||||
.padding(.leading, 2)
|
||||
.padding(.bottom, item.userData?.playedPercentage == nil ? 2 : 9)
|
||||
.opacity(1)
|
||||
, alignment: .bottomLeading)
|
||||
.opacity(1), alignment: .bottomLeading)
|
||||
.overlay(
|
||||
ZStack {
|
||||
if item.userData?.played ?? false {
|
||||
|
@ -49,7 +48,7 @@ struct PortraitItemView: View {
|
|||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(Color(.systemBlue))
|
||||
} else {
|
||||
if(item.userData?.unplayedItemCount != nil) {
|
||||
if item.userData?.unplayedItemCount != nil {
|
||||
Image(systemName: "circle.fill")
|
||||
.foregroundColor(Color(.systemBlue))
|
||||
Text(String(item.userData!.unplayedItemCount ?? 0))
|
||||
|
@ -64,12 +63,12 @@ struct PortraitItemView: View {
|
|||
.fontWeight(.semibold)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(1)
|
||||
if(item.type == "Movie" || item.type == "Series") {
|
||||
if item.type == "Movie" || item.type == "Series" {
|
||||
Text("\(String(item.productionYear ?? 0)) • \(item.officialRating ?? "N/A")")
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
} else if(item.type == "Season") {
|
||||
} else if item.type == "Season" {
|
||||
Text("\(item.name ?? "") • \(String(item.productionYear ?? 0))")
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
|
|
|
@ -56,7 +56,7 @@ struct LibraryListView: View {
|
|||
.shadow(radius: 5)
|
||||
.padding(.bottom, 15)
|
||||
|
||||
if(!viewModel.isLoading) {
|
||||
if !viewModel.isLoading {
|
||||
ForEach(viewModel.libraries, id: \.id) { library in
|
||||
if library.collectionType ?? "" == "movies" || library.collectionType ?? "" == "tvshows" {
|
||||
NavigationLink(destination: LazyView {
|
||||
|
@ -67,7 +67,7 @@ struct LibraryListView: View {
|
|||
.opacity(0.4)
|
||||
HStack {
|
||||
Spacer()
|
||||
VStack() {
|
||||
VStack {
|
||||
Text(library.name ?? "")
|
||||
.foregroundColor(.white)
|
||||
.font(.title2)
|
||||
|
|
|
@ -34,7 +34,7 @@ struct LibraryView: View {
|
|||
Spacer().frame(height: 16)
|
||||
LazyVGrid(columns: tracks) {
|
||||
ForEach(viewModel.items, id: \.id) { item in
|
||||
if(item.type != "Folder") {
|
||||
if item.type != "Folder" {
|
||||
PortraitItemView(item: item)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,8 +89,7 @@ struct SeasonItemView: View {
|
|||
}
|
||||
.padding(.leading, 2)
|
||||
.padding(.bottom, episode.userData?.playedPercentage == nil ? 2 : 9)
|
||||
.opacity(1)
|
||||
, alignment: .bottomLeading)
|
||||
.opacity(1), alignment: .bottomLeading)
|
||||
.overlay(
|
||||
ZStack {
|
||||
if episode.userData?.played ?? false {
|
||||
|
|
|
@ -68,21 +68,21 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
}
|
||||
var hasSentRemoteSeek: Bool = false
|
||||
|
||||
var selectedPlaybackSpeedIndex : Int = 3
|
||||
var selectedPlaybackSpeedIndex: Int = 3
|
||||
var selectedAudioTrack: Int32 = -1
|
||||
var selectedCaptionTrack: Int32 = -1
|
||||
var playSessionId: String = ""
|
||||
var lastProgressReportTime: Double = 0
|
||||
var subtitleTrackArray: [Subtitle] = []
|
||||
var audioTrackArray: [AudioTrack] = []
|
||||
let playbackSpeeds : [Float] = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0]
|
||||
let playbackSpeeds: [Float] = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0]
|
||||
|
||||
var manifest: BaseItemDto = BaseItemDto()
|
||||
var playbackItem = PlaybackItem()
|
||||
var remoteTimeUpdateTimer: Timer?
|
||||
var upNextViewModel: UpNextViewModel = UpNextViewModel()
|
||||
var lastOri: UIDeviceOrientation!
|
||||
|
||||
|
||||
// MARK: IBActions
|
||||
@IBAction func seekSliderStart(_ sender: Any) {
|
||||
if playerDestination == .local {
|
||||
|
@ -348,34 +348,34 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
}
|
||||
}
|
||||
|
||||
var nowPlayingInfo = [String : Any]()
|
||||
|
||||
var nowPlayingInfo = [String: Any]()
|
||||
|
||||
var runTicks = 0
|
||||
var playbackTicks = 0
|
||||
|
||||
|
||||
if let ticks = manifest.runTimeTicks {
|
||||
runTicks = Int(ticks / 10_000_000)
|
||||
}
|
||||
|
||||
|
||||
if let ticks = manifest.userData?.playbackPositionTicks {
|
||||
playbackTicks = Int(ticks / 10_000_000)
|
||||
}
|
||||
|
||||
|
||||
nowPlayingInfo[MPMediaItemPropertyTitle] = manifest.name ?? "Jellyfin Video"
|
||||
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
|
||||
nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = AVMediaType.video
|
||||
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = runTicks
|
||||
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playbackTicks
|
||||
|
||||
|
||||
if let imageData = NSData(contentsOf: manifest.getPrimaryImage(maxWidth: 200)) {
|
||||
if let artworkImage = UIImage(data: imageData as Data) {
|
||||
let artwork = MPMediaItemArtwork.init(boundsSize: artworkImage.size, requestHandler: { (size) -> UIImage in
|
||||
let artwork = MPMediaItemArtwork.init(boundsSize: artworkImage.size, requestHandler: { (_) -> UIImage in
|
||||
return artworkImage
|
||||
})
|
||||
nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
|
||||
|
||||
UIApplication.shared.beginReceivingRemoteControlEvents()
|
||||
|
@ -387,11 +387,11 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
titleLabel.text = manifest.name ?? ""
|
||||
} else {
|
||||
titleLabel.text = "S\(String(manifest.parentIndexNumber ?? 0)):E\(String(manifest.indexNumber ?? 0)) “\(manifest.name ?? "")”"
|
||||
|
||||
|
||||
setupNextUpView()
|
||||
upNextViewModel.delegate = self
|
||||
}
|
||||
|
||||
|
||||
lastOri = UIDevice.current.orientation
|
||||
|
||||
if !UIDevice.current.orientation.isLandscape || UIDevice.current.orientation.isFlat {
|
||||
|
@ -454,12 +454,12 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
|
||||
mediaPlayer.delegate = self
|
||||
mediaPlayer.drawable = videoContentView
|
||||
|
||||
|
||||
setupMediaPlayer()
|
||||
}
|
||||
|
||||
|
||||
func setupMediaPlayer() {
|
||||
|
||||
|
||||
// Fetch max bitrate from UserDefaults depending on current connection mode
|
||||
let maxBitrate = Defaults[.inNetworkBandwidth]
|
||||
print(maxBitrate)
|
||||
|
@ -580,8 +580,8 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
|
||||
self.sendPlayReport()
|
||||
playbackItem = item
|
||||
|
||||
//self.setupNowPlayingCC()
|
||||
|
||||
// self.setupNowPlayingCC()
|
||||
}
|
||||
|
||||
startLocalPlaybackEngine(true)
|
||||
|
@ -678,21 +678,21 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
selectedAudioTrack = newTrackID
|
||||
mediaPlayer.currentAudioTrackIndex = newTrackID
|
||||
}
|
||||
|
||||
|
||||
func playbackSpeedChanged(index: Int) {
|
||||
selectedPlaybackSpeedIndex = index
|
||||
mediaPlayer.rate = playbackSpeeds[index]
|
||||
}
|
||||
|
||||
|
||||
func smallNextUpView() {
|
||||
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseIn) { [self] in
|
||||
upNextViewModel.largeView = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func setupNextUpView() {
|
||||
getNextEpisode()
|
||||
|
||||
|
||||
// Create the swiftUI view
|
||||
let contentView = UIHostingController(rootView: VideoUpNextView(viewModel: upNextViewModel))
|
||||
self.upNextView.addSubview(contentView.view)
|
||||
|
@ -703,7 +703,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
contentView.view.leftAnchor.constraint(equalTo: upNextView.leftAnchor).isActive = true
|
||||
contentView.view.rightAnchor.constraint(equalTo: upNextView.rightAnchor).isActive = true
|
||||
}
|
||||
|
||||
|
||||
func getNextEpisode() {
|
||||
TvShowsAPI.getEpisodes(seriesId: manifest.seriesId!, userId: SessionManager.current.user.user_id!, startItemId: manifest.id, limit: 2)
|
||||
.sink(receiveCompletion: { completion in
|
||||
|
@ -717,22 +717,21 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
||||
func setPlayerToNextUp() {
|
||||
mediaPlayer.stop()
|
||||
|
||||
|
||||
ssTargetValueOffset = 0
|
||||
ssStartValue = 0
|
||||
|
||||
|
||||
paused = true
|
||||
lastTime = 0.0
|
||||
startTime = 0
|
||||
controlsAppearTime = 0
|
||||
isSeeking = false
|
||||
|
||||
|
||||
remotePositionTicks = 0
|
||||
|
||||
|
||||
selectedPlaybackSpeedIndex = 3
|
||||
selectedAudioTrack = -1
|
||||
selectedCaptionTrack = -1
|
||||
|
@ -740,22 +739,22 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
|||
lastProgressReportTime = 0
|
||||
subtitleTrackArray = []
|
||||
audioTrackArray = []
|
||||
|
||||
|
||||
manifest = upNextViewModel.item!
|
||||
playbackItem = PlaybackItem()
|
||||
|
||||
|
||||
upNextViewModel.item = nil
|
||||
|
||||
|
||||
upNextView.isHidden = true
|
||||
shouldShowLoadingScreen = true
|
||||
videoControlsView.isHidden = true
|
||||
|
||||
titleLabel.text = "S\(String(manifest.parentIndexNumber ?? 0)):E\(String(manifest.indexNumber ?? 0)) “\(manifest.name ?? "")”"
|
||||
|
||||
|
||||
setupMediaPlayer()
|
||||
getNextEpisode()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - GCKGenericChannelDelegate
|
||||
|
@ -951,8 +950,8 @@ extension PlayerViewController: VLCMediaPlayerDelegate {
|
|||
mainActionButton.setImage(UIImage(systemName: "pause"), for: .normal)
|
||||
seekSlider.setValue(mediaPlayer.position, animated: true)
|
||||
delegate?.hideLoadingView(self)
|
||||
|
||||
if manifest.type == "Episode" && upNextViewModel.item != nil{
|
||||
|
||||
if manifest.type == "Episode" && upNextViewModel.item != nil {
|
||||
if time > 0.96 {
|
||||
upNextView.isHidden = false
|
||||
self.jumpForwardButton.isHidden = true
|
||||
|
@ -961,7 +960,7 @@ extension PlayerViewController: VLCMediaPlayerDelegate {
|
|||
self.jumpForwardButton.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
timeText.text = String(mediaPlayer.remainingTime.stringValue.dropFirst())
|
||||
|
||||
if CACurrentMediaTime() - controlsAppearTime > 5 {
|
||||
|
|
|
@ -37,8 +37,8 @@ struct VideoPlayerSettings: View {
|
|||
weak var delegate: PlayerViewController!
|
||||
@State var captionTrack: Int32 = -99
|
||||
@State var audioTrack: Int32 = -99
|
||||
@State var playbackSpeedSelection : Int = 3
|
||||
|
||||
@State var playbackSpeedSelection: Int = 3
|
||||
|
||||
init(delegate: PlayerViewController) {
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
@ -66,8 +66,7 @@ struct VideoPlayerSettings: View {
|
|||
let speed = delegate.playbackSpeeds[speedIndex]
|
||||
if floor(speed) == speed {
|
||||
Text(String(format: "%.0fx", speed)).tag(speedIndex)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text(String(format: "%.2fx", speed)).tag(speedIndex)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ import JellyfinAPI
|
|||
|
||||
class UpNextViewModel: ObservableObject {
|
||||
@Published var largeView: Bool = false
|
||||
@Published var item: BaseItemDto? = nil
|
||||
var delegate: PlayerViewController?
|
||||
|
||||
@Published var item: BaseItemDto?
|
||||
weak var delegate: PlayerViewController?
|
||||
|
||||
func nextUp() {
|
||||
if delegate != nil {
|
||||
delegate?.setPlayerToNextUp()
|
||||
|
@ -23,9 +23,9 @@ class UpNextViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
struct VideoUpNextView: View {
|
||||
|
||||
|
||||
@ObservedObject var viewModel: UpNextViewModel
|
||||
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
viewModel.nextUp()
|
||||
|
|
|
@ -73,7 +73,7 @@ extension BaseItemDto {
|
|||
let urlString = "\(ServerEnvironment.current.server.baseURI!)/Items/\(imageItemId)/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)"
|
||||
return URL(string: urlString)!
|
||||
}
|
||||
|
||||
|
||||
func getEpisodeLocator() -> String {
|
||||
if let seasonNo = self.parentIndexNumber, let episodeNo = self.indexNumber {
|
||||
return "S\(seasonNo):E\(episodeNo)"
|
||||
|
@ -111,7 +111,7 @@ extension BaseItemDto {
|
|||
let x = UIScreen.main.nativeScale * CGFloat(maxWidth)
|
||||
|
||||
let urlString = "\(ServerEnvironment.current.server.baseURI!)/Items/\(imageItemId)/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)"
|
||||
//print(urlString)
|
||||
// print(urlString)
|
||||
return URL(string: urlString)!
|
||||
}
|
||||
|
||||
|
|
|
@ -54,17 +54,17 @@ final class SessionManager {
|
|||
var deviceName = UIDevice.current.name
|
||||
deviceName = deviceName.folding(options: .diacriticInsensitive, locale: .current)
|
||||
deviceName = String(deviceName.unicodeScalars.filter {CharacterSet.urlQueryAllowed.contains($0) })
|
||||
|
||||
|
||||
var header = "MediaBrowser "
|
||||
#if os(tvOS)
|
||||
header.append("Client=\"Jellyfin tvOS\", ")
|
||||
#else
|
||||
header.append("Client=\"SwiftFin iOS\", ")
|
||||
#endif
|
||||
|
||||
|
||||
header.append("Device=\"\(deviceName)\", ")
|
||||
|
||||
if(devID == nil) {
|
||||
|
||||
if devID == nil {
|
||||
#if os(tvOS)
|
||||
header.append("DeviceId=\"tvOS_\(UIDevice.current.identifierForVendor!.uuidString)_\(String(Date().timeIntervalSince1970))\", ")
|
||||
deviceID = "tvOS_\(UIDevice.current.identifierForVendor!.uuidString)_\(String(Date().timeIntervalSince1970))"
|
||||
|
@ -78,7 +78,7 @@ final class SessionManager {
|
|||
header.append("DeviceId=\"\(devID!)\", ")
|
||||
deviceID = devID!
|
||||
}
|
||||
|
||||
|
||||
header.append("Version=\"\(appVersion ?? "0.0.1")\", ")
|
||||
|
||||
if authToken != nil {
|
||||
|
@ -116,8 +116,8 @@ final class SessionManager {
|
|||
|
||||
func loginWithSavedSession(user: SignedInUser) {
|
||||
let accessToken = getAuthToken(userID: user.user_id!)
|
||||
print("logging in with saved session");
|
||||
|
||||
print("logging in with saved session")
|
||||
|
||||
self.user = user
|
||||
generateAuthHeader(with: accessToken, deviceID: user.device_uuid)
|
||||
print(JellyfinAPI.customHeaders)
|
||||
|
@ -134,7 +134,7 @@ final class SessionManager {
|
|||
user.username = response.user?.name
|
||||
user.user_id = response.user?.id
|
||||
user.device_uuid = self.deviceID
|
||||
|
||||
|
||||
#if os(tvOS)
|
||||
// user.appletv_id = tvUserManager.currentUserIdentifier ?? ""
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,7 @@ import JellyfinAPI
|
|||
class DetailItemViewModel: ViewModel {
|
||||
@Published var item: BaseItemDto
|
||||
@Published var similarItems: [BaseItemDto] = []
|
||||
|
||||
|
||||
@Published var isWatched = false
|
||||
@Published var isFavorited = false
|
||||
|
||||
|
@ -23,10 +23,10 @@ class DetailItemViewModel: ViewModel {
|
|||
isFavorited = item.userData?.isFavorite ?? false
|
||||
isWatched = item.userData?.played ?? false
|
||||
super.init()
|
||||
|
||||
|
||||
getRelatedItems()
|
||||
}
|
||||
|
||||
|
||||
func getRelatedItems() {
|
||||
LibraryAPI.getSimilarItems(itemId: item.id!, userId: SessionManager.current.user.user_id!, limit: 20, fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
||||
.trackActivity(loading)
|
||||
|
|
|
@ -39,7 +39,7 @@ final class LibraryFilterViewModel: ViewModel {
|
|||
var selectedSortOrder: APISortOrder = .descending
|
||||
@Published
|
||||
var selectedSortBy: SortBy = .name
|
||||
|
||||
|
||||
var parentId: String = ""
|
||||
|
||||
func updateModifiedFilter() {
|
||||
|
|
|
@ -87,7 +87,7 @@ final class LibraryViewModel: ViewModel {
|
|||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
||||
func requestItemsAsync(with filters: LibraryFilters) {
|
||||
let personIDs: [String] = [person].compactMap(\.?.id)
|
||||
let studioIDs: [String] = [studio].compactMap(\.?.id)
|
||||
|
@ -121,7 +121,7 @@ final class LibraryViewModel: ViewModel {
|
|||
currentPage += 1
|
||||
requestItems(with: filters)
|
||||
}
|
||||
|
||||
|
||||
func requestNextPageAsync() {
|
||||
currentPage += 1
|
||||
requestItemsAsync(with: filters)
|
||||
|
|
|
@ -13,11 +13,11 @@ import JellyfinAPI
|
|||
|
||||
final class SeasonItemViewModel: DetailItemViewModel {
|
||||
@Published var episodes = [BaseItemDto]()
|
||||
|
||||
|
||||
override init(item: BaseItemDto) {
|
||||
super.init(item: item)
|
||||
self.item = item
|
||||
|
||||
|
||||
requestEpisodes()
|
||||
}
|
||||
|
||||
|
|
|
@ -14,15 +14,15 @@ import JellyfinAPI
|
|||
final class SeriesItemViewModel: DetailItemViewModel {
|
||||
@Published var seasons = [BaseItemDto]()
|
||||
@Published var nextUpItem: BaseItemDto?
|
||||
|
||||
|
||||
override init(item: BaseItemDto) {
|
||||
super.init(item: item)
|
||||
self.item = item
|
||||
|
||||
|
||||
requestSeasons()
|
||||
getNextUp()
|
||||
}
|
||||
|
||||
|
||||
func getNextUp() {
|
||||
TvShowsAPI.getNextUp(userId: SessionManager.current.user.user_id!, fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people], seriesId: self.item.id!, enableUserData: true)
|
||||
.trackActivity(loading)
|
||||
|
@ -33,22 +33,22 @@ final class SeriesItemViewModel: DetailItemViewModel {
|
|||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
||||
func getRunYears() -> String {
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "yyyy"
|
||||
|
||||
var startYear: String? = nil
|
||||
var endYear: String? = nil
|
||||
|
||||
if(item.premiereDate != nil) {
|
||||
|
||||
var startYear: String?
|
||||
var endYear: String?
|
||||
|
||||
if item.premiereDate != nil {
|
||||
startYear = dateFormatter.string(from: item.premiereDate!)
|
||||
}
|
||||
|
||||
if(item.endDate != nil) {
|
||||
|
||||
if item.endDate != nil {
|
||||
endYear = dateFormatter.string(from: item.endDate!)
|
||||
}
|
||||
|
||||
|
||||
return "\(startYear ?? "Unknown") - \(endYear ?? "Present")"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue