Merge branch 'main' into multi-server-url
This commit is contained in:
commit
9ba5ab8417
|
@ -199,6 +199,9 @@
|
|||
62C29EA326D1030F00C1D2E7 /* ConnectToServerCoodinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C29EA226D1030F00C1D2E7 /* ConnectToServerCoodinator.swift */; };
|
||||
62C29EA626D1036A00C1D2E7 /* HomeCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C29EA526D1036A00C1D2E7 /* HomeCoordinator.swift */; };
|
||||
62C29EA826D103D500C1D2E7 /* LibraryListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C29EA726D103D500C1D2E7 /* LibraryListCoordinator.swift */; };
|
||||
62E1DCC3273CE19800C9AE76 /* URLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E1DCC2273CE19800C9AE76 /* URLExtensions.swift */; };
|
||||
62E1DCC4273CE19800C9AE76 /* URLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E1DCC2273CE19800C9AE76 /* URLExtensions.swift */; };
|
||||
62E1DCC5273CE19800C9AE76 /* URLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E1DCC2273CE19800C9AE76 /* URLExtensions.swift */; };
|
||||
62E632DA267D2BC40063E547 /* LatestMediaViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */; };
|
||||
62E632DC267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; };
|
||||
62E632DD267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; };
|
||||
|
@ -536,6 +539,7 @@
|
|||
62C29EA226D1030F00C1D2E7 /* ConnectToServerCoodinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectToServerCoodinator.swift; sourceTree = "<group>"; };
|
||||
62C29EA526D1036A00C1D2E7 /* HomeCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCoordinator.swift; sourceTree = "<group>"; };
|
||||
62C29EA726D103D500C1D2E7 /* LibraryListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListCoordinator.swift; sourceTree = "<group>"; };
|
||||
62E1DCC2273CE19800C9AE76 /* URLExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLExtensions.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
|
@ -1062,6 +1066,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
5389277B263CC3DB0035E14B /* BlurHashDecode.swift */,
|
||||
62E1DCC2273CE19800C9AE76 /* URLExtensions.swift */,
|
||||
6267B3D526710B8900A7371D /* CollectionExtensions.swift */,
|
||||
E173DA5126D04AAF00CC4EB7 /* ColorExtension.swift */,
|
||||
6267B3D92671138200A7371D /* ImageExtensions.swift */,
|
||||
|
@ -1823,6 +1828,7 @@
|
|||
E1AD104E26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */,
|
||||
62E632DD267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */,
|
||||
536D3D81267BDFC60004248C /* PortraitItemElement.swift in Sources */,
|
||||
62E1DCC4273CE19800C9AE76 /* URLExtensions.swift in Sources */,
|
||||
5310695B2684E7EE00CFFDBA /* AudioView.swift in Sources */,
|
||||
5398514726B64E4100101B49 /* SearchBarView.swift in Sources */,
|
||||
091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */,
|
||||
|
@ -1983,6 +1989,7 @@
|
|||
535870AD2669D8DD00D05A09 /* Typings.swift in Sources */,
|
||||
E1AD105F26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift in Sources */,
|
||||
E13DD3D5271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */,
|
||||
62E1DCC3273CE19800C9AE76 /* URLExtensions.swift in Sources */,
|
||||
C4BE0769271FC164003F4AD1 /* TVLibrariesView.swift in Sources */,
|
||||
E1267D3E271A1F46003C492E /* PreferenceUIHostingController.swift in Sources */,
|
||||
6220D0BA26D6092100B8E046 /* FilterCoordinator.swift in Sources */,
|
||||
|
@ -2031,6 +2038,7 @@
|
|||
E13DD3D7271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */,
|
||||
E131691926C583BC0074BFEE /* LogConstructor.swift in Sources */,
|
||||
E13DD3CA27164B80009D4DAF /* SwiftfinStore.swift in Sources */,
|
||||
62E1DCC5273CE19800C9AE76 /* URLExtensions.swift in Sources */,
|
||||
62EC353226766849000E9F2D /* SessionManager.swift in Sources */,
|
||||
536D3D79267BD5D00004248C /* ViewModel.swift in Sources */,
|
||||
E1D4BF8C2719F39F00A11E64 /* AppAppearance.swift in Sources */,
|
||||
|
|
|
@ -15,25 +15,25 @@ struct ItemLandscapeMainView: View {
|
|||
@Binding private var videoIsLoading: Bool
|
||||
@EnvironmentObject private var viewModel: ItemViewModel
|
||||
@EnvironmentObject private var videoPlayerItem: VideoPlayerItem
|
||||
|
||||
|
||||
init(videoIsLoading: Binding<Bool>) {
|
||||
self._videoIsLoading = videoIsLoading
|
||||
}
|
||||
|
||||
|
||||
// MARK: innerBody
|
||||
|
||||
|
||||
private var innerBody: some View {
|
||||
HStack {
|
||||
// MARK: Sidebar Image
|
||||
|
||||
|
||||
VStack {
|
||||
ImageView(src: viewModel.item.getPrimaryImage(maxWidth: 130),
|
||||
bh: viewModel.item.getPrimaryImageBlurHash())
|
||||
.frame(width: 130, height: 195)
|
||||
.cornerRadius(10)
|
||||
|
||||
|
||||
Spacer().frame(height: 15)
|
||||
|
||||
|
||||
Button {
|
||||
if let playButtonItem = viewModel.playButtonItem {
|
||||
self.videoPlayerItem.itemToPlay = playButtonItem
|
||||
|
@ -41,7 +41,7 @@ struct ItemLandscapeMainView: View {
|
|||
}
|
||||
} label: {
|
||||
// MARK: Play
|
||||
|
||||
|
||||
HStack {
|
||||
Image(systemName: "play.fill")
|
||||
.foregroundColor(viewModel.playButtonItem == nil ? Color(UIColor.secondaryLabel) : Color.white)
|
||||
|
@ -55,19 +55,19 @@ struct ItemLandscapeMainView: View {
|
|||
.background(viewModel.playButtonItem == nil ? Color(UIColor.secondarySystemFill) : Color.jellyfinPurple)
|
||||
.cornerRadius(10)
|
||||
}.disabled(viewModel.playButtonItem == nil)
|
||||
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
|
||||
ScrollView {
|
||||
VStack(alignment: .leading) {
|
||||
// MARK: ItemLandscapeTopBarView
|
||||
|
||||
|
||||
ItemLandscapeTopBarView()
|
||||
.environmentObject(viewModel)
|
||||
|
||||
|
||||
// MARK: ItemViewBody
|
||||
|
||||
|
||||
if let episodeViewModel = viewModel as? SeasonItemViewModel {
|
||||
EpisodeCardVStackView(items: episodeViewModel.episodes) { episode in
|
||||
itemRouter.route(to: \.item, episode)
|
||||
|
@ -80,9 +80,9 @@ struct ItemLandscapeMainView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: body
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
ZStack {
|
||||
|
@ -92,7 +92,8 @@ struct ItemLandscapeMainView: View {
|
|||
bh: viewModel.item.getBackdropImageBlurHash())
|
||||
.opacity(0.3)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.blur(radius: 4)
|
||||
.blur(radius: 8)
|
||||
.layoutPriority(-1)
|
||||
|
||||
// iPadOS is making the view go all the way to the edge.
|
||||
// We have to accomodate this here
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
//
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
/*
|
||||
* 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 Foundation
|
||||
import JellyfinAPI
|
||||
|
@ -14,35 +14,48 @@ import UIKit
|
|||
// 001fC^ = dark grey plain blurhash
|
||||
|
||||
public extension BaseItemDto {
|
||||
|
||||
// MARK: Images
|
||||
|
||||
func getSeriesBackdropImageBlurHash() -> String {
|
||||
let rawImgURL = getSeriesBackdropImage(maxWidth: 1).absoluteString
|
||||
let imgTag = rawImgURL.components(separatedBy: "&tag=")[1]
|
||||
let imgURL = getSeriesBackdropImage(maxWidth: 1)
|
||||
guard let imgTag = imgURL.queryParameters?["tag"],
|
||||
let hash = imageBlurHashes?.backdrop?[imgTag]
|
||||
else {
|
||||
return "001fC^"
|
||||
}
|
||||
|
||||
return imageBlurHashes?.backdrop?[imgTag] ?? "001fC^"
|
||||
return hash
|
||||
}
|
||||
|
||||
func getSeriesPrimaryImageBlurHash() -> String {
|
||||
let rawImgURL = getSeriesPrimaryImage(maxWidth: 1).absoluteString
|
||||
let imgTag = rawImgURL.components(separatedBy: "&tag=")[1]
|
||||
let imgURL = getSeriesPrimaryImage(maxWidth: 1)
|
||||
guard let imgTag = imgURL.queryParameters?["tag"],
|
||||
let hash = imageBlurHashes?.primary?[imgTag]
|
||||
else {
|
||||
return "001fC^"
|
||||
}
|
||||
|
||||
return imageBlurHashes?.primary?[imgTag] ?? "001fC^"
|
||||
return hash
|
||||
}
|
||||
|
||||
func getPrimaryImageBlurHash() -> String {
|
||||
let rawImgURL = getPrimaryImage(maxWidth: 1).absoluteString
|
||||
let imgTag = rawImgURL.components(separatedBy: "&tag=")[1]
|
||||
let imgURL = getPrimaryImage(maxWidth: 1)
|
||||
guard let imgTag = imgURL.queryParameters?["tag"],
|
||||
let hash = imageBlurHashes?.primary?[imgTag]
|
||||
else {
|
||||
return "001fC^"
|
||||
}
|
||||
|
||||
return imageBlurHashes?.primary?[imgTag] ?? "001fC^"
|
||||
return hash
|
||||
}
|
||||
|
||||
func getBackdropImageBlurHash() -> String {
|
||||
let rawImgURL = getBackdropImage(maxWidth: 1).absoluteString
|
||||
let imgTag = rawImgURL.components(separatedBy: "&tag=")[1]
|
||||
let imgURL = getBackdropImage(maxWidth: 1)
|
||||
guard let imgTag = imgURL.queryParameters?["tag"] else {
|
||||
return "001fC^"
|
||||
}
|
||||
|
||||
if rawImgURL.contains("Backdrop") {
|
||||
if imgURL.queryParameters?[ImageType.backdrop.rawValue] == nil {
|
||||
return imageBlurHashes?.backdrop?[imgTag] ?? "001fC^"
|
||||
} else {
|
||||
return imageBlurHashes?.primary?[imgTag] ?? "001fC^"
|
||||
|
@ -50,31 +63,29 @@ public extension BaseItemDto {
|
|||
}
|
||||
|
||||
func getBackdropImage(maxWidth: Int) -> URL {
|
||||
var imageType = ""
|
||||
var imageTag = ""
|
||||
var imageType = ImageType.backdrop
|
||||
var imageTag: String?
|
||||
var imageItemId = id ?? ""
|
||||
|
||||
if primaryImageAspectRatio ?? 0.0 < 1.0 {
|
||||
imageType = "Backdrop"
|
||||
if !(backdropImageTags?.isEmpty ?? true) {
|
||||
imageTag = (backdropImageTags ?? [""])[0]
|
||||
imageTag = backdropImageTags?.first
|
||||
}
|
||||
} else {
|
||||
imageType = "Primary"
|
||||
imageTag = imageTags?["Primary"] ?? ""
|
||||
imageType = .primary
|
||||
imageTag = imageTags?[ImageType.primary.rawValue] ?? ""
|
||||
}
|
||||
|
||||
if imageTag == "" || imageItemId == "" {
|
||||
imageType = "Backdrop"
|
||||
if imageTag == nil || imageItemId.isEmpty {
|
||||
if !(parentBackdropImageTags?.isEmpty ?? true) {
|
||||
imageTag = (parentBackdropImageTags ?? [""])[0]
|
||||
imageTag = parentBackdropImageTags?.first
|
||||
imageItemId = parentBackdropItemId ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
let x = UIScreen.main.nativeScale * CGFloat(maxWidth)
|
||||
let urlString =
|
||||
"\(SessionManager.main.currentLogin.server.currentURI)/Items/\(imageItemId)/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)"
|
||||
"\(SessionManager.main.currentLogin.server.currentURI)/Items/\(imageItemId)/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)"
|
||||
return URL(string: urlString)!
|
||||
}
|
||||
|
||||
|
@ -86,9 +97,6 @@ public extension BaseItemDto {
|
|||
}
|
||||
|
||||
func getSeriesBackdropImage(maxWidth: Int) -> URL {
|
||||
let imageType = "Backdrop"
|
||||
let imageTag = (parentBackdropImageTags ?? [""])[0]
|
||||
|
||||
let x = UIScreen.main.nativeScale * CGFloat(maxWidth)
|
||||
let urlString =
|
||||
"\(SessionManager.main.currentLogin.server.currentURI)/Items/\(parentBackdropItemId ?? "")/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)"
|
||||
|
@ -96,8 +104,6 @@ public extension BaseItemDto {
|
|||
}
|
||||
|
||||
func getSeriesPrimaryImage(maxWidth: Int) -> URL {
|
||||
let imageType = "Primary"
|
||||
let imageTag = seriesPrimaryImageTag ?? ""
|
||||
let x = UIScreen.main.nativeScale * CGFloat(maxWidth)
|
||||
let urlString =
|
||||
"\(SessionManager.main.currentLogin.server.currentURI)/Items/\(seriesId ?? "")/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)"
|
||||
|
@ -105,11 +111,11 @@ public extension BaseItemDto {
|
|||
}
|
||||
|
||||
func getPrimaryImage(maxWidth: Int) -> URL {
|
||||
let imageType = "Primary"
|
||||
var imageTag = imageTags?["Primary"] ?? ""
|
||||
let imageType = ImageType.primary
|
||||
var imageTag = imageTags?[ImageType.primary.rawValue] ?? ""
|
||||
var imageItemId = id ?? ""
|
||||
|
||||
if imageTag == "" || imageItemId == "" {
|
||||
if imageTag.isEmpty || imageItemId.isEmpty {
|
||||
imageTag = seriesPrimaryImageTag ?? ""
|
||||
imageItemId = seriesId ?? ""
|
||||
}
|
||||
|
@ -118,7 +124,6 @@ public extension BaseItemDto {
|
|||
|
||||
let urlString =
|
||||
"\(SessionManager.main.currentLogin.server.currentURI)/Items/\(imageItemId)/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)"
|
||||
// print(urlString)
|
||||
return URL(string: urlString)!
|
||||
}
|
||||
|
||||
|
@ -174,14 +179,14 @@ public extension BaseItemDto {
|
|||
}
|
||||
|
||||
var itemType: ItemType {
|
||||
guard let originalType = self.type, let knownType = ItemType(rawValue: originalType) else { return .unknown }
|
||||
guard let originalType = type, let knownType = ItemType(rawValue: originalType) else { return .unknown }
|
||||
return knownType
|
||||
}
|
||||
|
||||
// MARK: PortraitHeaderViewURL
|
||||
|
||||
func portraitHeaderViewURL(maxWidth: Int) -> URL {
|
||||
switch self.itemType {
|
||||
switch itemType {
|
||||
case .movie, .season, .series:
|
||||
return getPrimaryImage(maxWidth: maxWidth)
|
||||
case .episode:
|
||||
|
|
|
@ -10,23 +10,28 @@ import JellyfinAPI
|
|||
import UIKit
|
||||
|
||||
extension BaseItemPerson {
|
||||
|
||||
|
||||
// MARK: Get Image
|
||||
func getImage(baseURL: String, maxWidth: Int) -> URL {
|
||||
let imageType = "Primary"
|
||||
let imageTag = primaryImageTag ?? ""
|
||||
|
||||
let x = UIScreen.main.nativeScale * CGFloat(maxWidth)
|
||||
|
||||
let urlString = "\(baseURL)/Items/\(id ?? "")/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=85&tag=\(imageTag)"
|
||||
|
||||
let urlString = ImageAPI.getItemImageWithRequestBuilder(itemId: id ?? "",
|
||||
imageType: .primary,
|
||||
maxWidth: Int(x),
|
||||
quality: 96,
|
||||
tag: primaryImageTag).URLString
|
||||
return URL(string: urlString)!
|
||||
}
|
||||
|
||||
|
||||
func getBlurHash() -> String {
|
||||
let rawImgURL = getImage(baseURL: "", maxWidth: 1).absoluteString
|
||||
let imgTag = rawImgURL.components(separatedBy: "&tag=")[1]
|
||||
let imgURL = getImage(baseURL: "", maxWidth: 1)
|
||||
guard let imgTag = imgURL.queryParameters?["tag"],
|
||||
let hash = imageBlurHashes?.primary?[imgTag]
|
||||
else {
|
||||
return "001fC^"
|
||||
}
|
||||
|
||||
return imageBlurHashes?.primary?[imgTag] ?? "001fC^"
|
||||
return hash
|
||||
}
|
||||
|
||||
// MARK: First Role
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
/*
|
||||
* 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 Foundation
|
||||
|
||||
public extension URL {
|
||||
/// Dictionary of the URL's query parameters
|
||||
var queryParameters: [String: String]? {
|
||||
guard let components = URLComponents(url: self, resolvingAgainstBaseURL: false),
|
||||
let queryItems = components.queryItems else { return nil }
|
||||
|
||||
var items: [String: String] = [:]
|
||||
|
||||
for queryItem in queryItems {
|
||||
items[queryItem.name] = queryItem.value
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue