From df0014592d91f5739a104d37af9026b67df1f724 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Wed, 2 Jun 2021 16:18:38 +0900 Subject: [PATCH] add LazyImage.placeholderAndFailure apply placeholderAndFailure too all LazyImage --- JellyfinPlayer.xcodeproj/project.pbxproj | 4 + JellyfinPlayer/ContinueWatchingView.swift | 4 +- JellyfinPlayer/EpisodeItemView.swift | 14 ++- JellyfinPlayer/Extensions/LazyImage++.swift | 22 ++++ JellyfinPlayer/LatestMediaView.swift | 4 +- JellyfinPlayer/LibrarySearchView.swift | 4 +- JellyfinPlayer/LibraryView.swift | 4 +- JellyfinPlayer/MovieItemView.swift | 12 +-- JellyfinPlayer/NextUpView.swift | 2 +- JellyfinPlayer/SeasonItemView.swift | 108 +++++++++----------- JellyfinPlayer/SeriesItemView.swift | 2 +- 11 files changed, 99 insertions(+), 81 deletions(-) create mode 100644 JellyfinPlayer/Extensions/LazyImage++.swift diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index e97ae5d5..89943dca 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ 62133895266096EF00A81A2A /* LibraryListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62133894266096EF00A81A2A /* LibraryListViewModel.swift */; }; 621338B32660A07800A81A2A /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338B22660A07800A81A2A /* LazyView.swift */; }; 621C638026672A30004216EA /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 621C637F26672A30004216EA /* NukeUI */; }; + 621C638226676728004216EA /* LazyImage++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621C638126676728004216EA /* LazyImage++.swift */; }; 6225FCCB2663841E00E067F6 /* ParallaxHeaderScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */; }; 6273DD43265F4195009C1D0B /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD42265F4195009C1D0B /* Moya */; }; 6273DD45265F4195009C1D0B /* CombineMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD44265F4195009C1D0B /* CombineMoya */; }; @@ -117,6 +118,7 @@ 621338922660107500A81A2A /* String++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String++.swift"; sourceTree = ""; }; 62133894266096EF00A81A2A /* LibraryListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListViewModel.swift; sourceTree = ""; }; 621338B22660A07800A81A2A /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = ""; }; + 621C638126676728004216EA /* LazyImage++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LazyImage++.swift"; sourceTree = ""; }; 6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallaxHeaderScrollView.swift; sourceTree = ""; }; 6273DD47265F41B3009C1D0B /* JellyfinAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinAPI.swift; sourceTree = ""; }; 6273DD4D265F47B2009C1D0B /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = ""; }; @@ -221,6 +223,7 @@ 621338B22660A07800A81A2A /* LazyView.swift */, 621338922660107500A81A2A /* String++.swift */, 6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */, + 621C638126676728004216EA /* LazyImage++.swift */, ); path = Extensions; sourceTree = ""; @@ -369,6 +372,7 @@ buildActionMask = 2147483647; files = ( 621338932660107500A81A2A /* String++.swift in Sources */, + 621C638226676728004216EA /* LazyImage++.swift in Sources */, 53FF7F2A263CF3F500585C35 /* LatestMediaView.swift in Sources */, 5377CBFE263B596B003A4E83 /* PersistenceController.swift in Sources */, 5389276E263C25100035E14B /* ContinueWatchingView.swift in Sources */, diff --git a/JellyfinPlayer/ContinueWatchingView.swift b/JellyfinPlayer/ContinueWatchingView.swift index 9c78236c..8b6be46c 100644 --- a/JellyfinPlayer/ContinueWatchingView.swift +++ b/JellyfinPlayer/ContinueWatchingView.swift @@ -116,7 +116,7 @@ struct ContinueWatchingView: View { Spacer().frame(height: 10) if(item.Type == "Episode") { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=550&quality=80&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 48, height: 32))!) .resizable() .frame(width: 320, height: 180) @@ -144,7 +144,7 @@ struct ContinueWatchingView: View { ) } else { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=550&quality=80&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 48, height: 32))!) .resizable() .frame(width: 320, height: 180) diff --git a/JellyfinPlayer/EpisodeItemView.swift b/JellyfinPlayer/EpisodeItemView.swift index 2f504fe4..5fb2a308 100644 --- a/JellyfinPlayer/EpisodeItemView.swift +++ b/JellyfinPlayer/EpisodeItemView.swift @@ -203,9 +203,8 @@ struct EpisodeItemView: View { } var portraitHeaderView: some View { - VStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.ParentBackdropItemId)/Images/Backdrop?maxWidth=550&quality=90&tag=\(fullItem.Backdrop)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem .BackdropBlurHash, @@ -215,14 +214,13 @@ struct EpisodeItemView: View { .contentMode(.aspectFill) .opacity(0.3) .shadow(radius: 5) - } } var portraitHeaderOverlayView: some View { VStack(alignment: .leading) { HStack(alignment: .bottom, spacing: 12) { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash, @@ -364,7 +362,7 @@ struct EpisodeItemView: View { }) { VStack { LazyImage(source: cast.Image) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: cast .ImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : @@ -423,7 +421,7 @@ struct EpisodeItemView: View { GeometryReader { geometry in ZStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.ParentBackdropItemId)/Images/Backdrop?maxWidth=\(String(Int(geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing)))&quality=80&tag=\(fullItem.Backdrop)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem .BackdropBlurHash, @@ -444,7 +442,7 @@ struct EpisodeItemView: View { HStack { VStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash, @@ -582,7 +580,7 @@ struct EpisodeItemView: View { }) { VStack { LazyImage(source: cast.Image) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: cast .ImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : diff --git a/JellyfinPlayer/Extensions/LazyImage++.swift b/JellyfinPlayer/Extensions/LazyImage++.swift new file mode 100644 index 00000000..d124f6a7 --- /dev/null +++ b/JellyfinPlayer/Extensions/LazyImage++.swift @@ -0,0 +1,22 @@ +// +// LazyImage++.swift +// JellyfinPlayer +// +// Created by PangMo5 on 2021/06/02. +// + +import Foundation +import SwiftUI +import NukeUI + +extension LazyImage { + func placeholderAndFailure(@ViewBuilder _ content: () -> Content?) -> LazyImage { + placeholder { + content() + } + .failure { + content() + } + } + +} diff --git a/JellyfinPlayer/LatestMediaView.swift b/JellyfinPlayer/LatestMediaView.swift index 7846d2be..88004fdc 100644 --- a/JellyfinPlayer/LatestMediaView.swift +++ b/JellyfinPlayer/LatestMediaView.swift @@ -92,7 +92,7 @@ struct LatestMediaView: View { if(item.Type == "Series") { Spacer().frame(height:10) LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 16, height: 16))!) .resizable() .frame(width: 100, height: 150) @@ -122,7 +122,7 @@ struct LatestMediaView: View { } else { Spacer().frame(height:10) LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 16, height: 16))!) .resizable() .frame(width: 100, height: 150) diff --git a/JellyfinPlayer/LibrarySearchView.swift b/JellyfinPlayer/LibrarySearchView.swift index 5b1291b7..0fb7ae20 100644 --- a/JellyfinPlayer/LibrarySearchView.swift +++ b/JellyfinPlayer/LibrarySearchView.swift @@ -88,7 +88,7 @@ struct ResumeItemGridCell: View { VStack(alignment: .leading) { if item.Type == "Movie" { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: item .BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item .BlurHash, @@ -101,7 +101,7 @@ struct ResumeItemGridCell: View { .cornerRadius(10) } else { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: item .BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item .BlurHash, diff --git a/JellyfinPlayer/LibraryView.swift b/JellyfinPlayer/LibraryView.swift index eaea439e..9823aeb0 100644 --- a/JellyfinPlayer/LibraryView.swift +++ b/JellyfinPlayer/LibraryView.swift @@ -137,7 +137,7 @@ extension LibraryView { VStack(alignment: .leading) { if item.Type == "Movie" { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: item .BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item .BlurHash, @@ -150,7 +150,7 @@ extension LibraryView { .cornerRadius(10) } else { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: item .BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item .BlurHash, diff --git a/JellyfinPlayer/MovieItemView.swift b/JellyfinPlayer/MovieItemView.swift index 528451bb..452edfca 100644 --- a/JellyfinPlayer/MovieItemView.swift +++ b/JellyfinPlayer/MovieItemView.swift @@ -294,7 +294,7 @@ struct MovieItemView: View { var portraitHeaderView: some View { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Backdrop?maxWidth=550&quality=90&tag=\(fullItem.Backdrop)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem .BackdropBlurHash, @@ -310,7 +310,7 @@ struct MovieItemView: View { VStack(alignment: .leading) { HStack(alignment: .bottom, spacing: 12) { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash, @@ -453,7 +453,7 @@ struct MovieItemView: View { }) { VStack { LazyImage(source: cast.Image) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: cast .ImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : @@ -511,7 +511,7 @@ struct MovieItemView: View { GeometryReader { geometry in ZStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Backdrop?maxWidth=\(String(Int(geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing)))&quality=80&tag=\(fullItem.Backdrop)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem .BackdropBlurHash, @@ -532,7 +532,7 @@ struct MovieItemView: View { HStack { VStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash, @@ -670,7 +670,7 @@ struct MovieItemView: View { }) { VStack { LazyImage(source: cast.Image) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: cast .ImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : diff --git a/JellyfinPlayer/NextUpView.swift b/JellyfinPlayer/NextUpView.swift index 4128d1c7..23e08323 100644 --- a/JellyfinPlayer/NextUpView.swift +++ b/JellyfinPlayer/NextUpView.swift @@ -80,7 +80,7 @@ struct NextUpView: View { VStack(alignment: .leading) { Spacer().frame(height:10) LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.SeriesId ?? "")/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 16, height: 16))!) .resizable() .frame(width: 100, height: 150) diff --git a/JellyfinPlayer/SeasonItemView.swift b/JellyfinPlayer/SeasonItemView.swift index dd6afd46..97a8ccfc 100644 --- a/JellyfinPlayer/SeasonItemView.swift +++ b/JellyfinPlayer/SeasonItemView.swift @@ -18,7 +18,8 @@ struct SeasonItemView: View { @State private var isLoading: Bool = true var item: ResumeItem - var fullItem: DetailItem + @State + var fullItem = DetailItem() @State var episodes: [DetailItem] = [] @State @@ -28,7 +29,6 @@ struct SeasonItemView: View { init(item: ResumeItem) { self.item = item - self.fullItem = DetailItem() } func loadData() { @@ -48,32 +48,33 @@ struct SeasonItemView: View { let body = response.body do { let json = try JSON(data: body) - fullItem.ProductionYear = json["ProductionYear"].int ?? 0 - fullItem.Poster = json["ImageTags"]["Primary"].string ?? "" - fullItem.PosterBlurHash = json["ImageBlurHashes"]["Primary"][fullItem.Poster].string ?? "" - fullItem.Backdrop = json["BackdropImageTags"][0].string ?? "" - fullItem.BackdropBlurHash = json["ImageBlurHashes"]["Backdrop"][fullItem.Backdrop].string ?? "" - fullItem.Name = json["Name"].string ?? "" - fullItem.Type = json["Type"].string ?? "" - fullItem.IndexNumber = json["IndexNumber"].int ?? nil - fullItem.SeriesId = json["ParentId"].string ?? nil - fullItem.Id = item.Id - fullItem.Overview = json["Overview"].string ?? "" - fullItem.Tagline = json["Taglines"][0].string ?? "" - fullItem.SeriesName = json["SeriesName"].string ?? nil - fullItem.ParentId = json["ParentId"].string ?? "" + let responseItem = DetailItem() + responseItem.ProductionYear = json["ProductionYear"].int ?? 0 + responseItem.Poster = json["ImageTags"]["Primary"].string ?? "" + responseItem.PosterBlurHash = json["ImageBlurHashes"]["Primary"][responseItem.Poster].string ?? "" + responseItem.Backdrop = json["BackdropImageTags"][0].string ?? "" + responseItem.BackdropBlurHash = json["ImageBlurHashes"]["Backdrop"][responseItem.Backdrop].string ?? "" + responseItem.Name = json["Name"].string ?? "" + responseItem.Type = json["Type"].string ?? "" + responseItem.IndexNumber = json["IndexNumber"].int ?? nil + responseItem.SeriesId = json["ParentId"].string ?? nil + responseItem.Id = item.Id + responseItem.Overview = json["Overview"].string ?? "" + responseItem.Tagline = json["Taglines"][0].string ?? "" + responseItem.SeriesName = json["SeriesName"].string ?? nil + responseItem.ParentId = json["ParentId"].string ?? "" // People - fullItem.Directors = [] - fullItem.Studios = [] - fullItem.Writers = [] - fullItem.Cast = [] - fullItem.Genres = [] + responseItem.Directors = [] + responseItem.Studios = [] + responseItem.Writers = [] + responseItem.Cast = [] + responseItem.Genres = [] for (_, person): (String, JSON) in json["People"] { if person["Type"].stringValue == "Director" { - fullItem.Directors.append(person["Name"].string ?? "") + responseItem.Directors.append(person["Name"].string ?? "") } else if person["Type"].stringValue == "Writer" { - fullItem.Writers.append(person["Name"].string ?? "") + responseItem.Writers.append(person["Name"].string ?? "") } else if person["Type"].stringValue == "Actor" { let cast = CastMember() cast.Name = person["Name"].string ?? "" @@ -84,10 +85,15 @@ struct SeasonItemView: View { cast .Image = URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(cast.Id)/Images/Primary?maxWidth=2000&quality=90&tag=\(imageTag)")! - fullItem.Cast.append(cast) + responseItem.Cast.append(cast) } } + _fullItem.wrappedValue = responseItem + + print("!@#!@#@#!@#") + print(fullItem.SeriesId) + let url2 = "/Shows/\(fullItem.SeriesId ?? "")/Episodes?SeasonId=\(item.Id)&UserId=\(globalData.user?.user_id ?? "")&Fields=ItemCounts%2CPrimaryImageAspectRatio%2CBasicSyncInfo%2CCanDelete%2CMediaSourceCount%2COverview" let request2 = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + url2) @@ -185,41 +191,29 @@ struct SeasonItemView: View { return result } + @ViewBuilder var portraitHeaderView: some View { - LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Backdrop?maxWidth=750&quality=90&tag=\(item.SeasonImage ?? "")")) - .placeholder { - Image(uiImage: UIImage(blurHash: item - .SeasonImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item - .SeasonImageBlurHash ?? "", - size: CGSize(width: 32, height: 32))!) - .resizable() - } - .failure{ - Image(uiImage: UIImage(blurHash: item - .SeasonImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item - .SeasonImageBlurHash ?? "", - size: CGSize(width: 32, height: 32))!) - .resizable() - } - .contentMode(.aspectFill) - .onStart { print("onStart \($0.request.url)") } - .onProgress { _,_,_ in print("onProgress") } - .onSuccess { _ in print("onSuccess") } - .onFailure { error in - print(error.dataLoadingError?.localizedDescription) - print(error.description) - print(error.localizedDescription) - } - .onCompletion { _ in print("onCompletion") } - .frame(minWidth: 0, maxWidth: .infinity) - .opacity(0.4) - .shadow(radius: 5) + if isLoading { + EmptyView() + } else { + LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Backdrop?maxWidth=550&quality=90&tag=\(item.SeasonImage ?? "")")) + .placeholderAndFailure { + Image(uiImage: UIImage(blurHash: item + .SeasonImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item + .SeasonImageBlurHash ?? "", + size: CGSize(width: 32, height: 32))!) + .resizable() + } + .contentMode(.aspectFill) + .opacity(0.4) + .shadow(radius: 5) + } } var portraitHeaderOverlayView: some View { HStack(alignment: .bottom, spacing: 12) { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem .PosterBlurHash, @@ -275,7 +269,7 @@ struct SeasonItemView: View { NavigationLink(destination: ItemView(item: episode.ResumeItem ?? ResumeItem())) { HStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(episode.Id)/Images/Primary?maxWidth=300&quality=90&tag=\(episode.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: episode .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem @@ -345,7 +339,7 @@ struct SeasonItemView: View { GeometryReader { geometry in ZStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Backdrop?maxWidth=\(String(Int(geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing)))&quality=80&tag=\(item.SeasonImage ?? "")")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: item .SeasonImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item .SeasonImageBlurHash ?? "", @@ -366,7 +360,7 @@ struct SeasonItemView: View { HStack { VStack(alignment: .leading) { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: fullItem .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash, @@ -402,7 +396,7 @@ struct SeasonItemView: View { NavigationLink(destination: ItemView(item: episode.ResumeItem ?? ResumeItem())) { HStack { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(episode.Id)/Images/Primary?maxWidth=300&quality=90&tag=\(episode.Poster)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: episode .PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem diff --git a/JellyfinPlayer/SeriesItemView.swift b/JellyfinPlayer/SeriesItemView.swift index f6294b73..9689cf32 100644 --- a/JellyfinPlayer/SeriesItemView.swift +++ b/JellyfinPlayer/SeriesItemView.swift @@ -97,7 +97,7 @@ struct SeriesItemView: View { NavigationLink(destination: ItemView(item: item )) { VStack(alignment: .leading) { LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=90&tag=\(item.Image)")) - .placeholder { + .placeholderAndFailure { Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!) .resizable() .frame(width: 100, height: 150)