Merge pull request #29 from PangMo5/PangMo5/Improve-image-performance
Improved image performance
This commit is contained in:
commit
296bd8fcc9
|
@ -28,7 +28,6 @@
|
||||||
53892777263CBB000035E14B /* JellyApiTypings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53892776263CBB000035E14B /* JellyApiTypings.swift */; };
|
53892777263CBB000035E14B /* JellyApiTypings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53892776263CBB000035E14B /* JellyApiTypings.swift */; };
|
||||||
5389277A263CBFE70035E14B /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 53892779263CBFE70035E14B /* SwiftyJSON */; };
|
5389277A263CBFE70035E14B /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 53892779263CBFE70035E14B /* SwiftyJSON */; };
|
||||||
5389277C263CC3DB0035E14B /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5389277B263CC3DB0035E14B /* BlurHashDecode.swift */; };
|
5389277C263CC3DB0035E14B /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5389277B263CC3DB0035E14B /* BlurHashDecode.swift */; };
|
||||||
538CD954263E3DC100BB5AF0 /* SDWebImageSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 538CD953263E3DC100BB5AF0 /* SDWebImageSwiftUI */; };
|
|
||||||
53987CA426572C1300E7EA70 /* SeasonItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53987CA326572C1300E7EA70 /* SeasonItemView.swift */; };
|
53987CA426572C1300E7EA70 /* SeasonItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53987CA326572C1300E7EA70 /* SeasonItemView.swift */; };
|
||||||
53987CA626572F0700E7EA70 /* SeriesItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53987CA526572F0700E7EA70 /* SeriesItemView.swift */; };
|
53987CA626572F0700E7EA70 /* SeriesItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53987CA526572F0700E7EA70 /* SeriesItemView.swift */; };
|
||||||
53987CA82657424A00E7EA70 /* EpisodeItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53987CA72657424A00E7EA70 /* EpisodeItemView.swift */; };
|
53987CA82657424A00E7EA70 /* EpisodeItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53987CA72657424A00E7EA70 /* EpisodeItemView.swift */; };
|
||||||
|
@ -47,6 +46,8 @@
|
||||||
621338932660107500A81A2A /* String++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* String++.swift */; };
|
621338932660107500A81A2A /* String++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* String++.swift */; };
|
||||||
62133895266096EF00A81A2A /* LibraryListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62133894266096EF00A81A2A /* LibraryListViewModel.swift */; };
|
62133895266096EF00A81A2A /* LibraryListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62133894266096EF00A81A2A /* LibraryListViewModel.swift */; };
|
||||||
621338B32660A07800A81A2A /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338B22660A07800A81A2A /* LazyView.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 */; };
|
6225FCCB2663841E00E067F6 /* ParallaxHeaderScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */; };
|
||||||
6273DD43265F4195009C1D0B /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD42265F4195009C1D0B /* Moya */; };
|
6273DD43265F4195009C1D0B /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD42265F4195009C1D0B /* Moya */; };
|
||||||
6273DD45265F4195009C1D0B /* CombineMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD44265F4195009C1D0B /* CombineMoya */; };
|
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 = "<group>"; };
|
621338922660107500A81A2A /* String++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String++.swift"; sourceTree = "<group>"; };
|
||||||
62133894266096EF00A81A2A /* LibraryListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListViewModel.swift; sourceTree = "<group>"; };
|
62133894266096EF00A81A2A /* LibraryListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListViewModel.swift; sourceTree = "<group>"; };
|
||||||
621338B22660A07800A81A2A /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
621338B22660A07800A81A2A /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
||||||
|
621C638126676728004216EA /* LazyImage++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LazyImage++.swift"; sourceTree = "<group>"; };
|
||||||
6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallaxHeaderScrollView.swift; sourceTree = "<group>"; };
|
6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallaxHeaderScrollView.swift; sourceTree = "<group>"; };
|
||||||
6273DD47265F41B3009C1D0B /* JellyfinAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinAPI.swift; sourceTree = "<group>"; };
|
6273DD47265F41B3009C1D0B /* JellyfinAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinAPI.swift; sourceTree = "<group>"; };
|
||||||
6273DD4D265F47B2009C1D0B /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = "<group>"; };
|
6273DD4D265F47B2009C1D0B /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -130,13 +132,13 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
538CD954263E3DC100BB5AF0 /* SDWebImageSwiftUI in Frameworks */,
|
|
||||||
5338F757263B7E2E0014BF09 /* KeychainSwift in Frameworks */,
|
5338F757263B7E2E0014BF09 /* KeychainSwift in Frameworks */,
|
||||||
6273DD45265F4195009C1D0B /* CombineMoya in Frameworks */,
|
6273DD45265F4195009C1D0B /* CombineMoya in Frameworks */,
|
||||||
6273DD43265F4195009C1D0B /* Moya in Frameworks */,
|
6273DD43265F4195009C1D0B /* Moya in Frameworks */,
|
||||||
53D5E3DD264B47EE00BADDC8 /* MobileVLCKit.xcframework in Frameworks */,
|
53D5E3DD264B47EE00BADDC8 /* MobileVLCKit.xcframework in Frameworks */,
|
||||||
5338F754263B65E10014BF09 /* SwiftyRequest in Frameworks */,
|
5338F754263B65E10014BF09 /* SwiftyRequest in Frameworks */,
|
||||||
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
||||||
|
621C638026672A30004216EA /* NukeUI in Frameworks */,
|
||||||
5302F82A2658791C00647A2E /* Sentry in Frameworks */,
|
5302F82A2658791C00647A2E /* Sentry in Frameworks */,
|
||||||
5389277A263CBFE70035E14B /* SwiftyJSON in Frameworks */,
|
5389277A263CBFE70035E14B /* SwiftyJSON in Frameworks */,
|
||||||
);
|
);
|
||||||
|
@ -221,6 +223,7 @@
|
||||||
621338B22660A07800A81A2A /* LazyView.swift */,
|
621338B22660A07800A81A2A /* LazyView.swift */,
|
||||||
621338922660107500A81A2A /* String++.swift */,
|
621338922660107500A81A2A /* String++.swift */,
|
||||||
6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */,
|
6225FCCA2663841E00E067F6 /* ParallaxHeaderScrollView.swift */,
|
||||||
|
621C638126676728004216EA /* LazyImage++.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -295,11 +298,11 @@
|
||||||
5338F753263B65E10014BF09 /* SwiftyRequest */,
|
5338F753263B65E10014BF09 /* SwiftyRequest */,
|
||||||
5338F756263B7E2E0014BF09 /* KeychainSwift */,
|
5338F756263B7E2E0014BF09 /* KeychainSwift */,
|
||||||
53892779263CBFE70035E14B /* SwiftyJSON */,
|
53892779263CBFE70035E14B /* SwiftyJSON */,
|
||||||
538CD953263E3DC100BB5AF0 /* SDWebImageSwiftUI */,
|
|
||||||
5302F8292658791C00647A2E /* Sentry */,
|
5302F8292658791C00647A2E /* Sentry */,
|
||||||
53352570265EA0A0006CCA86 /* Introspect */,
|
53352570265EA0A0006CCA86 /* Introspect */,
|
||||||
6273DD42265F4195009C1D0B /* Moya */,
|
6273DD42265F4195009C1D0B /* Moya */,
|
||||||
6273DD44265F4195009C1D0B /* CombineMoya */,
|
6273DD44265F4195009C1D0B /* CombineMoya */,
|
||||||
|
621C637F26672A30004216EA /* NukeUI */,
|
||||||
);
|
);
|
||||||
productName = JellyfinPlayer;
|
productName = JellyfinPlayer;
|
||||||
productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer.app */;
|
productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer.app */;
|
||||||
|
@ -335,10 +338,10 @@
|
||||||
5338F752263B65E10014BF09 /* XCRemoteSwiftPackageReference "SwiftyRequest" */,
|
5338F752263B65E10014BF09 /* XCRemoteSwiftPackageReference "SwiftyRequest" */,
|
||||||
5338F755263B7E2E0014BF09 /* XCRemoteSwiftPackageReference "keychain-swift" */,
|
5338F755263B7E2E0014BF09 /* XCRemoteSwiftPackageReference "keychain-swift" */,
|
||||||
53892778263CBFE70035E14B /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
53892778263CBFE70035E14B /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
||||||
538CD952263E3DC100BB5AF0 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */,
|
|
||||||
5302F8282658791C00647A2E /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
|
5302F8282658791C00647A2E /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
|
||||||
5335256F265EA0A0006CCA86 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
|
5335256F265EA0A0006CCA86 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
|
||||||
6273DD41265F4195009C1D0B /* XCRemoteSwiftPackageReference "Moya" */,
|
6273DD41265F4195009C1D0B /* XCRemoteSwiftPackageReference "Moya" */,
|
||||||
|
621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
|
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
@ -369,6 +372,7 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
621338932660107500A81A2A /* String++.swift in Sources */,
|
621338932660107500A81A2A /* String++.swift in Sources */,
|
||||||
|
621C638226676728004216EA /* LazyImage++.swift in Sources */,
|
||||||
53FF7F2A263CF3F500585C35 /* LatestMediaView.swift in Sources */,
|
53FF7F2A263CF3F500585C35 /* LatestMediaView.swift in Sources */,
|
||||||
5377CBFE263B596B003A4E83 /* PersistenceController.swift in Sources */,
|
5377CBFE263B596B003A4E83 /* PersistenceController.swift in Sources */,
|
||||||
5389276E263C25100035E14B /* ContinueWatchingView.swift in Sources */,
|
5389276E263C25100035E14B /* ContinueWatchingView.swift in Sources */,
|
||||||
|
@ -644,12 +648,12 @@
|
||||||
minimumVersion = 5.0.1;
|
minimumVersion = 5.0.1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
538CD952263E3DC100BB5AF0 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */ = {
|
621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/SDWebImage/SDWebImageSwiftUI";
|
repositoryURL = "https://github.com/kean/NukeUI";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMajorVersion;
|
branch = main;
|
||||||
minimumVersion = 2.0.2;
|
kind = branch;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
6273DD41265F4195009C1D0B /* XCRemoteSwiftPackageReference "Moya" */ = {
|
6273DD41265F4195009C1D0B /* XCRemoteSwiftPackageReference "Moya" */ = {
|
||||||
|
@ -688,10 +692,10 @@
|
||||||
package = 53892778263CBFE70035E14B /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
|
package = 53892778263CBFE70035E14B /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
|
||||||
productName = SwiftyJSON;
|
productName = SwiftyJSON;
|
||||||
};
|
};
|
||||||
538CD953263E3DC100BB5AF0 /* SDWebImageSwiftUI */ = {
|
621C637F26672A30004216EA /* NukeUI */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 538CD952263E3DC100BB5AF0 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */;
|
package = 621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */;
|
||||||
productName = SDWebImageSwiftUI;
|
productName = NukeUI;
|
||||||
};
|
};
|
||||||
6273DD42265F4195009C1D0B /* Moya */ = {
|
6273DD42265F4195009C1D0B /* Moya */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
|
|
@ -28,6 +28,15 @@
|
||||||
"version": "5.0.200"
|
"version": "5.0.200"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"package": "Gifu",
|
||||||
|
"repositoryURL": "https://github.com/kaishin/Gifu",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "0ffe24744cc3d82ab9edece53670d0352c6d5507",
|
||||||
|
"version": "3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "KeychainSwift",
|
"package": "KeychainSwift",
|
||||||
"repositoryURL": "https://github.com/evgenyneu/keychain-swift",
|
"repositoryURL": "https://github.com/evgenyneu/keychain-swift",
|
||||||
|
@ -55,6 +64,24 @@
|
||||||
"version": "15.0.0-alpha.1"
|
"version": "15.0.0-alpha.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"package": "Nuke",
|
||||||
|
"repositoryURL": "https://github.com/kean/Nuke.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "2775239e10e23c0b70c5544b98c2af7f65c2bbd9",
|
||||||
|
"version": "10.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package": "NukeUI",
|
||||||
|
"repositoryURL": "https://github.com/kean/NukeUI",
|
||||||
|
"state": {
|
||||||
|
"branch": "main",
|
||||||
|
"revision": "27dcb9065a18450ba47ecd46a913a74646d95144",
|
||||||
|
"version": null
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "ReactiveSwift",
|
"package": "ReactiveSwift",
|
||||||
"repositoryURL": "https://github.com/Moya/ReactiveSwift.git",
|
"repositoryURL": "https://github.com/Moya/ReactiveSwift.git",
|
||||||
|
@ -73,24 +100,6 @@
|
||||||
"version": "5.1.2"
|
"version": "5.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"package": "SDWebImage",
|
|
||||||
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "76dd4b49110b8624317fc128e7fa0d8a252018bc",
|
|
||||||
"version": "5.11.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "SDWebImageSwiftUI",
|
|
||||||
"repositoryURL": "https://github.com/SDWebImage/SDWebImageSwiftUI",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "cd8625b7cf11a97698e180d28bb7d5d357196678",
|
|
||||||
"version": "2.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"package": "Sentry",
|
"package": "Sentry",
|
||||||
"repositoryURL": "https://github.com/getsentry/sentry-cocoa",
|
"repositoryURL": "https://github.com/getsentry/sentry-cocoa",
|
||||||
|
|
|
@ -12,7 +12,7 @@ import SwiftyJSON
|
||||||
import CoreData
|
import CoreData
|
||||||
import KeychainSwift
|
import KeychainSwift
|
||||||
import Sentry
|
import Sentry
|
||||||
import SDWebImageSwiftUI
|
import NukeUI
|
||||||
|
|
||||||
class publicUser: ObservableObject {
|
class publicUser: ObservableObject {
|
||||||
@Published var username: String = "";
|
@Published var username: String = "";
|
||||||
|
@ -320,9 +320,8 @@ struct ConnectToServerView: View {
|
||||||
Text(pubuser.username).font(.subheadline).fontWeight(.semibold)
|
Text(pubuser.username).font(.subheadline).fontWeight(.semibold)
|
||||||
Spacer()
|
Spacer()
|
||||||
if(pubuser.primaryImageTag != "") {
|
if(pubuser.primaryImageTag != "") {
|
||||||
WebImage(url: URL(string: "\(uri)/Users/\(pubuser.id)/Images/Primary?width=200&quality=80&tag=\(pubuser.primaryImageTag)")!)
|
LazyImage(source: URL(string: "\(uri)/Users/\(pubuser.id)/Images/Primary?width=200&quality=80&tag=\(pubuser.primaryImageTag)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.contentMode(.aspectFill)
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: 60, height: 60)
|
.frame(width: 60, height: 60)
|
||||||
.cornerRadius(30.0)
|
.cornerRadius(30.0)
|
||||||
.shadow(radius: 6)
|
.shadow(radius: 6)
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
import KeychainSwift
|
import KeychainSwift
|
||||||
import SDWebImageSwiftUI
|
|
||||||
import Sentry
|
import Sentry
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
|
import Nuke
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@Environment(\.managedObjectContext)
|
@Environment(\.managedObjectContext)
|
||||||
|
@ -75,12 +75,9 @@ struct ContentView: View {
|
||||||
options.releaseName = "ios-" + (Bundle.main.infoDictionary?["CFBundleVersion"] as! String)
|
options.releaseName = "ios-" + (Bundle.main.infoDictionary?["CFBundleVersion"] as! String)
|
||||||
options.enableOutOfMemoryTracking = true
|
options.enableOutOfMemoryTracking = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let cache = SDImageCache(namespace: "tiny")
|
ImageCache.shared.costLimit = 125 * 1024 * 1024 // 125MB memory
|
||||||
cache.config.maxMemoryCost = 125 * 1024 * 1024 // 125MB memory
|
DataLoader.sharedUrlCache.diskCapacity = 1000 * 1024 * 1024 // 1000MB disk
|
||||||
cache.config.maxDiskSize = 1000 * 1024 * 1024 // 1000MB disk
|
|
||||||
SDImageCachesManager.shared.addCache(cache)
|
|
||||||
SDWebImageManager.defaultImageCache = SDImageCachesManager.shared
|
|
||||||
|
|
||||||
_libraries.wrappedValue = []
|
_libraries.wrappedValue = []
|
||||||
_library_names.wrappedValue = [:]
|
_library_names.wrappedValue = [:]
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SDWebImageSwiftUI
|
import NukeUI
|
||||||
|
|
||||||
struct CustomShape: Shape {
|
struct CustomShape: Shape {
|
||||||
let radius: CGFloat
|
let radius: CGFloat
|
||||||
|
@ -115,9 +115,8 @@ struct ContinueWatchingView: View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Spacer().frame(height: 10)
|
Spacer().frame(height: 10)
|
||||||
if(item.Type == "Episode") {
|
if(item.Type == "Episode") {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=550&quality=80&tag=\(item.Image)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=550&quality=80&tag=\(item.Image)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 48, height: 32))!)
|
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()
|
.resizable()
|
||||||
.frame(width: 320, height: 180)
|
.frame(width: 320, height: 180)
|
||||||
|
@ -144,9 +143,8 @@ struct ContinueWatchingView: View {
|
||||||
.padding(0), alignment: .bottomLeading
|
.padding(0), alignment: .bottomLeading
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=550&quality=80&tag=\(item.Image)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=550&quality=80&tag=\(item.Image)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 48, height: 32))!)
|
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()
|
.resizable()
|
||||||
.frame(width: 320, height: 180)
|
.frame(width: 320, height: 180)
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
// Created by Aiden Vigue on 5/13/21.
|
// Created by Aiden Vigue on 5/13/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SDWebImageSwiftUI
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
|
import NukeUI
|
||||||
|
|
||||||
struct EpisodeItemView: View {
|
struct EpisodeItemView: View {
|
||||||
@EnvironmentObject
|
@EnvironmentObject
|
||||||
|
@ -203,29 +203,24 @@ struct EpisodeItemView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var portraitHeaderView: some 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)"))
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.ParentBackdropItemId)/Images/Backdrop?maxWidth=550&quality=90&tag=\(fullItem.Backdrop)")!)
|
.placeholderAndFailure {
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
||||||
.BackdropBlurHash,
|
.BackdropBlurHash,
|
||||||
size: CGSize(width: 32, height: 32))!)
|
size: CGSize(width: 32, height: 32))!)
|
||||||
.resizable()
|
.resizable()
|
||||||
}
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
.opacity(0.3)
|
.opacity(0.3)
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.shadow(radius: 5)
|
.shadow(radius: 5)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var portraitHeaderOverlayView: some View {
|
var portraitHeaderOverlayView: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack(alignment: .bottom, spacing: 12) {
|
HStack(alignment: .bottom, spacing: 12) {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
fullItem.PosterBlurHash,
|
fullItem.PosterBlurHash,
|
||||||
|
@ -233,7 +228,8 @@ struct EpisodeItemView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}.aspectRatio(contentMode: .fill)
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
@ -365,9 +361,8 @@ struct EpisodeItemView: View {
|
||||||
])), title: cast.Name)
|
])), title: cast.Name)
|
||||||
}) {
|
}) {
|
||||||
VStack {
|
VStack {
|
||||||
WebImage(url: cast.Image)
|
LazyImage(source: cast.Image)
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: cast
|
Image(uiImage: UIImage(blurHash: cast
|
||||||
.ImageBlurHash == "" ?
|
.ImageBlurHash == "" ?
|
||||||
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
|
@ -379,7 +374,8 @@ struct EpisodeItemView: View {
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}
|
}
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
|
.contentMode(.aspectFill)
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
||||||
|
@ -424,9 +420,8 @@ struct EpisodeItemView: View {
|
||||||
} else {
|
} else {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
ZStack {
|
ZStack {
|
||||||
WebImage(url: 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)")!)
|
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)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
||||||
.BackdropBlurHash,
|
.BackdropBlurHash,
|
||||||
|
@ -437,18 +432,17 @@ struct EpisodeItemView: View {
|
||||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets
|
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets
|
||||||
.bottom)
|
.bottom)
|
||||||
}
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
|
|
||||||
.opacity(0.3)
|
.opacity(0.3)
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
||||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom)
|
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom)
|
||||||
.edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
.blur(radius: 2)
|
.blur(radius: 2)
|
||||||
HStack {
|
HStack {
|
||||||
VStack {
|
VStack {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
fullItem.PosterBlurHash,
|
fullItem.PosterBlurHash,
|
||||||
|
@ -456,7 +450,7 @@ struct EpisodeItemView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
}
|
}
|
||||||
.aspectRatio(contentMode: .fill)
|
.contentMode(.fill)
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
.shadow(radius: 5)
|
.shadow(radius: 5)
|
||||||
|
@ -585,9 +579,8 @@ struct EpisodeItemView: View {
|
||||||
])), title: cast.Name)
|
])), title: cast.Name)
|
||||||
}) {
|
}) {
|
||||||
VStack {
|
VStack {
|
||||||
WebImage(url: cast.Image)
|
LazyImage(source: cast.Image)
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: cast
|
Image(uiImage: UIImage(blurHash: cast
|
||||||
.ImageBlurHash == "" ?
|
.ImageBlurHash == "" ?
|
||||||
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
|
@ -599,7 +592,7 @@ struct EpisodeItemView: View {
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}
|
}
|
||||||
.aspectRatio(contentMode: .fill)
|
.contentMode(.aspectFill)
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// LazyImage++.swift
|
||||||
|
// JellyfinPlayer
|
||||||
|
//
|
||||||
|
// Created by PangMo5 on 2021/06/02.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
import NukeUI
|
||||||
|
|
||||||
|
extension LazyImage {
|
||||||
|
func placeholderAndFailure<Content: View>(@ViewBuilder _ content: () -> Content?) -> LazyImage {
|
||||||
|
placeholder {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
.failure {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SDWebImageSwiftUI
|
import NukeUI
|
||||||
|
|
||||||
struct LatestMediaView: View {
|
struct LatestMediaView: View {
|
||||||
@Environment(\.managedObjectContext) private var viewContext
|
@Environment(\.managedObjectContext) private var viewContext
|
||||||
|
@ -91,9 +91,8 @@ struct LatestMediaView: View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
if(item.Type == "Series") {
|
if(item.Type == "Series") {
|
||||||
Spacer().frame(height:10)
|
Spacer().frame(height:10)
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 16, height: 16))!)
|
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()
|
.resizable()
|
||||||
.frame(width: 100, height: 150)
|
.frame(width: 100, height: 150)
|
||||||
|
@ -122,9 +121,8 @@ struct LatestMediaView: View {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Spacer().frame(height:10)
|
Spacer().frame(height:10)
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 16, height: 16))!)
|
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()
|
.resizable()
|
||||||
.frame(width: 100, height: 150)
|
.frame(width: 100, height: 150)
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
// Created by Aiden Vigue on 5/2/21.
|
// Created by Aiden Vigue on 5/2/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SDWebImageSwiftUI
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
|
import NukeUI
|
||||||
|
|
||||||
struct LibrarySearchView: View {
|
struct LibrarySearchView: View {
|
||||||
@Environment(\.managedObjectContext)
|
@Environment(\.managedObjectContext)
|
||||||
|
@ -68,7 +68,7 @@ struct LibrarySearchView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if viewModel.isLoading {
|
if viewModel.isLoading {
|
||||||
ActivityIndicator($viewModel.isLoading)
|
ProgressView()
|
||||||
} else if viewModel.items.isEmpty {
|
} else if viewModel.items.isEmpty {
|
||||||
Text("Empty Response")
|
Text("Empty Response")
|
||||||
}
|
}
|
||||||
|
@ -87,9 +87,8 @@ struct ResumeItemGridCell: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
if item.Type == "Movie" {
|
if item.Type == "Movie" {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)"))
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)"))
|
||||||
.resizable()
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: item
|
Image(uiImage: UIImage(blurHash: item
|
||||||
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
||||||
.BlurHash,
|
.BlurHash,
|
||||||
|
@ -101,9 +100,8 @@ struct ResumeItemGridCell: View {
|
||||||
.frame(width: 100, height: 150)
|
.frame(width: 100, height: 150)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
} else {
|
} else {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)"))
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)"))
|
||||||
.resizable()
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: item
|
Image(uiImage: UIImage(blurHash: item
|
||||||
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
||||||
.BlurHash,
|
.BlurHash,
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
// Created by Aiden Vigue on 5/1/21.
|
// Created by Aiden Vigue on 5/1/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SDWebImageSwiftUI
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import NukeUI
|
||||||
|
|
||||||
struct LibraryView: View {
|
struct LibraryView: View {
|
||||||
@Environment(\.managedObjectContext)
|
@Environment(\.managedObjectContext)
|
||||||
|
@ -87,7 +87,7 @@ struct LibraryView: View {
|
||||||
recalcTracks()
|
recalcTracks()
|
||||||
}
|
}
|
||||||
if viewModel.isLoading {
|
if viewModel.isLoading {
|
||||||
ActivityIndicator($viewModel.isLoading)
|
ProgressView()
|
||||||
} else if viewModel.items.isEmpty {
|
} else if viewModel.items.isEmpty {
|
||||||
Text("Empty Response")
|
Text("Empty Response")
|
||||||
}
|
}
|
||||||
|
@ -136,9 +136,8 @@ extension LibraryView {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
if item.Type == "Movie" {
|
if item.Type == "Movie" {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)"))
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)"))
|
||||||
.resizable()
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: item
|
Image(uiImage: UIImage(blurHash: item
|
||||||
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
||||||
.BlurHash,
|
.BlurHash,
|
||||||
|
@ -150,9 +149,8 @@ extension LibraryView {
|
||||||
.frame(width: 100, height: 150)
|
.frame(width: 100, height: 150)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
} else {
|
} else {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)"))
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)"))
|
||||||
.resizable()
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: item
|
Image(uiImage: UIImage(blurHash: item
|
||||||
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
||||||
.BlurHash,
|
.BlurHash,
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
// Created by Aiden Vigue on 5/13/21.
|
// Created by Aiden Vigue on 5/13/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SDWebImageSwiftUI
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
|
import NukeUI
|
||||||
|
|
||||||
class DetailItem: ObservableObject {
|
class DetailItem: ObservableObject {
|
||||||
@Published
|
@Published
|
||||||
|
@ -293,27 +293,24 @@ struct MovieItemView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var portraitHeaderView: some View {
|
var portraitHeaderView: some View {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Backdrop?maxWidth=550&quality=90&tag=\(fullItem.Backdrop)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Backdrop?maxWidth=550&quality=90&tag=\(fullItem.Backdrop)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
||||||
.BackdropBlurHash,
|
.BackdropBlurHash,
|
||||||
size: CGSize(width: 32, height: 32))!)
|
size: CGSize(width: 32, height: 32))!)
|
||||||
.resizable()
|
.resizable()
|
||||||
}
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
.opacity(0.3)
|
.opacity(0.3)
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.shadow(radius: 5)
|
.shadow(radius: 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
var portraitHeaderOverlayView: some View {
|
var portraitHeaderOverlayView: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack(alignment: .bottom, spacing: 12) {
|
HStack(alignment: .bottom, spacing: 12) {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
fullItem.PosterBlurHash,
|
fullItem.PosterBlurHash,
|
||||||
|
@ -321,7 +318,8 @@ struct MovieItemView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}.aspectRatio(contentMode: .fill)
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
@ -454,9 +452,8 @@ struct MovieItemView: View {
|
||||||
])), title: cast.Name)
|
])), title: cast.Name)
|
||||||
}) {
|
}) {
|
||||||
VStack {
|
VStack {
|
||||||
WebImage(url: cast.Image)
|
LazyImage(source: cast.Image)
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: cast
|
Image(uiImage: UIImage(blurHash: cast
|
||||||
.ImageBlurHash == "" ?
|
.ImageBlurHash == "" ?
|
||||||
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
|
@ -468,7 +465,7 @@ struct MovieItemView: View {
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}
|
}
|
||||||
.aspectRatio(contentMode: .fill)
|
.contentMode(.aspectFill)
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
||||||
|
@ -513,9 +510,8 @@ struct MovieItemView: View {
|
||||||
} else {
|
} else {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
ZStack {
|
ZStack {
|
||||||
WebImage(url: 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)")!)
|
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)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
||||||
.BackdropBlurHash,
|
.BackdropBlurHash,
|
||||||
|
@ -526,18 +522,17 @@ struct MovieItemView: View {
|
||||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets
|
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets
|
||||||
.bottom)
|
.bottom)
|
||||||
}
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
|
|
||||||
.opacity(0.3)
|
.opacity(0.3)
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
||||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom)
|
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom)
|
||||||
.edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
.blur(radius: 2)
|
.blur(radius: 2)
|
||||||
HStack {
|
HStack {
|
||||||
VStack {
|
VStack {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
fullItem.PosterBlurHash,
|
fullItem.PosterBlurHash,
|
||||||
|
@ -674,9 +669,8 @@ struct MovieItemView: View {
|
||||||
])), title: cast.Name)
|
])), title: cast.Name)
|
||||||
}) {
|
}) {
|
||||||
VStack {
|
VStack {
|
||||||
WebImage(url: cast.Image)
|
LazyImage(source: cast.Image)
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: cast
|
Image(uiImage: UIImage(blurHash: cast
|
||||||
.ImageBlurHash == "" ?
|
.ImageBlurHash == "" ?
|
||||||
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
|
@ -688,7 +682,7 @@ struct MovieItemView: View {
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}
|
}
|
||||||
.aspectRatio(contentMode: .fill)
|
.contentMode(.aspectFill)
|
||||||
.frame(width: 100, height: 100)
|
.frame(width: 100, height: 100)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SDWebImageSwiftUI
|
import NukeUI
|
||||||
|
|
||||||
struct NextUpView: View {
|
struct NextUpView: View {
|
||||||
@Environment(\.managedObjectContext) private var viewContext
|
@Environment(\.managedObjectContext) private var viewContext
|
||||||
|
@ -79,9 +79,8 @@ struct NextUpView: View {
|
||||||
NavigationLink(destination: ItemView(item: item)) {
|
NavigationLink(destination: ItemView(item: item)) {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Spacer().frame(height:10)
|
Spacer().frame(height:10)
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.SeriesId ?? "")/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.SeriesId ?? "")/Images/\(item.ImageType)?maxWidth=250&quality=80&tag=\(item.Image)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 16, height: 16))!)
|
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()
|
.resizable()
|
||||||
.frame(width: 100, height: 150)
|
.frame(width: 100, height: 150)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// Created by Aiden Vigue on 5/13/21.
|
// Created by Aiden Vigue on 5/13/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SDWebImageSwiftUI
|
import NukeUI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
|
@ -18,7 +18,8 @@ struct SeasonItemView: View {
|
||||||
@State
|
@State
|
||||||
private var isLoading: Bool = true
|
private var isLoading: Bool = true
|
||||||
var item: ResumeItem
|
var item: ResumeItem
|
||||||
var fullItem: DetailItem
|
@State
|
||||||
|
var fullItem = DetailItem()
|
||||||
@State
|
@State
|
||||||
var episodes: [DetailItem] = []
|
var episodes: [DetailItem] = []
|
||||||
@State
|
@State
|
||||||
|
@ -28,7 +29,6 @@ struct SeasonItemView: View {
|
||||||
|
|
||||||
init(item: ResumeItem) {
|
init(item: ResumeItem) {
|
||||||
self.item = item
|
self.item = item
|
||||||
self.fullItem = DetailItem()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadData() {
|
func loadData() {
|
||||||
|
@ -48,32 +48,33 @@ struct SeasonItemView: View {
|
||||||
let body = response.body
|
let body = response.body
|
||||||
do {
|
do {
|
||||||
let json = try JSON(data: body)
|
let json = try JSON(data: body)
|
||||||
fullItem.ProductionYear = json["ProductionYear"].int ?? 0
|
let responseItem = DetailItem()
|
||||||
fullItem.Poster = json["ImageTags"]["Primary"].string ?? ""
|
responseItem.ProductionYear = json["ProductionYear"].int ?? 0
|
||||||
fullItem.PosterBlurHash = json["ImageBlurHashes"]["Primary"][fullItem.Poster].string ?? ""
|
responseItem.Poster = json["ImageTags"]["Primary"].string ?? ""
|
||||||
fullItem.Backdrop = json["BackdropImageTags"][0].string ?? ""
|
responseItem.PosterBlurHash = json["ImageBlurHashes"]["Primary"][responseItem.Poster].string ?? ""
|
||||||
fullItem.BackdropBlurHash = json["ImageBlurHashes"]["Backdrop"][fullItem.Backdrop].string ?? ""
|
responseItem.Backdrop = json["BackdropImageTags"][0].string ?? ""
|
||||||
fullItem.Name = json["Name"].string ?? ""
|
responseItem.BackdropBlurHash = json["ImageBlurHashes"]["Backdrop"][responseItem.Backdrop].string ?? ""
|
||||||
fullItem.Type = json["Type"].string ?? ""
|
responseItem.Name = json["Name"].string ?? ""
|
||||||
fullItem.IndexNumber = json["IndexNumber"].int ?? nil
|
responseItem.Type = json["Type"].string ?? ""
|
||||||
fullItem.SeriesId = json["ParentId"].string ?? nil
|
responseItem.IndexNumber = json["IndexNumber"].int ?? nil
|
||||||
fullItem.Id = item.Id
|
responseItem.SeriesId = json["ParentId"].string ?? nil
|
||||||
fullItem.Overview = json["Overview"].string ?? ""
|
responseItem.Id = item.Id
|
||||||
fullItem.Tagline = json["Taglines"][0].string ?? ""
|
responseItem.Overview = json["Overview"].string ?? ""
|
||||||
fullItem.SeriesName = json["SeriesName"].string ?? nil
|
responseItem.Tagline = json["Taglines"][0].string ?? ""
|
||||||
fullItem.ParentId = json["ParentId"].string ?? ""
|
responseItem.SeriesName = json["SeriesName"].string ?? nil
|
||||||
|
responseItem.ParentId = json["ParentId"].string ?? ""
|
||||||
// People
|
// People
|
||||||
fullItem.Directors = []
|
responseItem.Directors = []
|
||||||
fullItem.Studios = []
|
responseItem.Studios = []
|
||||||
fullItem.Writers = []
|
responseItem.Writers = []
|
||||||
fullItem.Cast = []
|
responseItem.Cast = []
|
||||||
fullItem.Genres = []
|
responseItem.Genres = []
|
||||||
|
|
||||||
for (_, person): (String, JSON) in json["People"] {
|
for (_, person): (String, JSON) in json["People"] {
|
||||||
if person["Type"].stringValue == "Director" {
|
if person["Type"].stringValue == "Director" {
|
||||||
fullItem.Directors.append(person["Name"].string ?? "")
|
responseItem.Directors.append(person["Name"].string ?? "")
|
||||||
} else if person["Type"].stringValue == "Writer" {
|
} else if person["Type"].stringValue == "Writer" {
|
||||||
fullItem.Writers.append(person["Name"].string ?? "")
|
responseItem.Writers.append(person["Name"].string ?? "")
|
||||||
} else if person["Type"].stringValue == "Actor" {
|
} else if person["Type"].stringValue == "Actor" {
|
||||||
let cast = CastMember()
|
let cast = CastMember()
|
||||||
cast.Name = person["Name"].string ?? ""
|
cast.Name = person["Name"].string ?? ""
|
||||||
|
@ -84,10 +85,12 @@ struct SeasonItemView: View {
|
||||||
cast
|
cast
|
||||||
.Image =
|
.Image =
|
||||||
URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(cast.Id)/Images/Primary?maxWidth=2000&quality=90&tag=\(imageTag)")!
|
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
|
||||||
|
|
||||||
let url2 =
|
let url2 =
|
||||||
"/Shows/\(fullItem.SeriesId ?? "")/Episodes?SeasonId=\(item.Id)&UserId=\(globalData.user?.user_id ?? "")&Fields=ItemCounts%2CPrimaryImageAspectRatio%2CBasicSyncInfo%2CCanDelete%2CMediaSourceCount%2COverview"
|
"/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)
|
let request2 = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + url2)
|
||||||
|
@ -185,26 +188,29 @@ struct SeasonItemView: View {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
var portraitHeaderView: some View {
|
var portraitHeaderView: some View {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Backdrop?maxWidth=750&quality=80&tag=\(item.SeasonImage ?? "")")!)
|
if isLoading {
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
EmptyView()
|
||||||
.placeholder {
|
} else {
|
||||||
Image(uiImage: UIImage(blurHash: item
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.SeriesId ?? "")/Images/Backdrop?maxWidth=550&quality=90&tag=\(item.SeasonImage ?? "")"))
|
||||||
.SeasonImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
.placeholderAndFailure {
|
||||||
.SeasonImageBlurHash ?? "",
|
Image(uiImage: UIImage(blurHash: item
|
||||||
size: CGSize(width: 32, height: 32))!)
|
.SeasonImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item
|
||||||
.resizable()
|
.SeasonImageBlurHash ?? "",
|
||||||
}
|
size: CGSize(width: 32, height: 32))!)
|
||||||
.opacity(0.4)
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
}
|
||||||
.shadow(radius: 5)
|
.contentMode(.aspectFill)
|
||||||
|
.opacity(0.4)
|
||||||
|
.shadow(radius: 5)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var portraitHeaderOverlayView: some View {
|
var portraitHeaderOverlayView: some View {
|
||||||
HStack(alignment: .bottom, spacing: 12) {
|
HStack(alignment: .bottom, spacing: 12) {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
||||||
.PosterBlurHash,
|
.PosterBlurHash,
|
||||||
|
@ -212,7 +218,8 @@ struct SeasonItemView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}.aspectRatio(contentMode: .fill)
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
@ -237,32 +244,156 @@ struct SeasonItemView: View {
|
||||||
.padding(.bottom, -22)
|
.padding(.bottom, -22)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
@ViewBuilder
|
||||||
VStack(alignment: .leading) {
|
var innerBody: some View {
|
||||||
LoadingView(isShowing: $isLoading) {
|
if orientationInfo.orientation == .portrait {
|
||||||
VStack(alignment: .leading) {
|
ParallaxHeaderScrollView(header: portraitHeaderView,
|
||||||
if orientationInfo.orientation == .portrait {
|
staticOverlayView: portraitHeaderOverlayView,
|
||||||
ParallaxHeaderScrollView(header: portraitHeaderView,
|
overlayAlignment: .bottomLeading,
|
||||||
staticOverlayView: portraitHeaderOverlayView,
|
headerHeight: UIScreen.main.bounds.width * 0.5625) {
|
||||||
overlayAlignment: .bottomLeading,
|
LazyVStack(alignment: .leading) {
|
||||||
headerHeight: UIScreen.main.bounds.width * 0.5625) {
|
Spacer()
|
||||||
VStack(alignment: .leading) {
|
.frame(height: 22)
|
||||||
Spacer()
|
if fullItem.Tagline != "" {
|
||||||
.frame(height: 22)
|
Text(fullItem.Tagline).font(.body).italic().padding(.top, 7)
|
||||||
|
.fixedSize(horizontal: false, vertical: true).padding(.leading, 16)
|
||||||
|
.padding(.trailing, 16)
|
||||||
|
}
|
||||||
|
Text(fullItem.Overview).font(.footnote).padding(.top, 3)
|
||||||
|
.fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16)
|
||||||
|
.padding(.trailing, 16)
|
||||||
|
ForEach(episodes, id: \.Id) { episode in
|
||||||
|
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)"))
|
||||||
|
.placeholderAndFailure {
|
||||||
|
Image(uiImage: UIImage(blurHash: episode
|
||||||
|
.PosterBlurHash == "" ?
|
||||||
|
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
||||||
|
.PosterBlurHash,
|
||||||
|
size: CGSize(width: 32, height: 32))!)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 150, height: 90)
|
||||||
|
.cornerRadius(10)
|
||||||
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
|
.shadow(radius: 5)
|
||||||
|
.frame(width: 150, height: 90)
|
||||||
|
.cornerRadius(10)
|
||||||
|
.overlay(RoundedRectangle(cornerRadius: 10, style: .circular)
|
||||||
|
.fill(Color(red: 172 / 255, green: 92 / 255, blue: 195 / 255)
|
||||||
|
.opacity(0.4))
|
||||||
|
.frame(width: CGFloat((episode.Progress / Double(episode.RuntimeTicks)) *
|
||||||
|
150),
|
||||||
|
height: 90)
|
||||||
|
.padding(0), alignment: .bottomLeading)
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
HStack {
|
||||||
|
Text(episode.Name).font(.subheadline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
.lineLimit(1)
|
||||||
|
Spacer()
|
||||||
|
Text(episode.Runtime).font(.subheadline)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
Text(episode.Overview).font(.footnote).foregroundColor(.secondary)
|
||||||
|
.fixedSize(horizontal: false, vertical: true).lineLimit(4)
|
||||||
|
Spacer()
|
||||||
|
}.padding(.trailing, 20).offset(y: 2)
|
||||||
|
}.offset(x: 12, y: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !fullItem.Directors.isEmpty {
|
||||||
|
HStack {
|
||||||
|
Text("Directors:").font(.callout).fontWeight(.semibold)
|
||||||
|
Text(fullItem.Directors.joined(separator: ", ")).font(.footnote).lineLimit(1)
|
||||||
|
.foregroundColor(Color.secondary)
|
||||||
|
}.padding(.leading, 16).padding(.trailing, 16)
|
||||||
|
}
|
||||||
|
if !fullItem.Writers.isEmpty {
|
||||||
|
HStack {
|
||||||
|
Text("Writers:").font(.callout).fontWeight(.semibold)
|
||||||
|
Text(fullItem.Writers.joined(separator: ", ")).font(.footnote).lineLimit(1)
|
||||||
|
.foregroundColor(Color.secondary)
|
||||||
|
}.padding(.leading, 16).padding(.trailing, 16)
|
||||||
|
}
|
||||||
|
if !fullItem.Studios.isEmpty {
|
||||||
|
HStack {
|
||||||
|
Text("Studios:").font(.callout).fontWeight(.semibold)
|
||||||
|
Text(fullItem.Studios.joined(separator: ", ")).font(.footnote).lineLimit(1)
|
||||||
|
.foregroundColor(Color.secondary)
|
||||||
|
}.padding(.leading, 16).padding(.trailing, 16)
|
||||||
|
}
|
||||||
|
Spacer().frame(height: 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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 ?? "")"))
|
||||||
|
.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()
|
||||||
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets
|
||||||
|
.trailing,
|
||||||
|
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets
|
||||||
|
.bottom)
|
||||||
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
|
|
||||||
|
.opacity(0.4)
|
||||||
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
||||||
|
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom)
|
||||||
|
.edgesIgnoringSafeArea(.all)
|
||||||
|
.blur(radius: 2)
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)"))
|
||||||
|
.placeholderAndFailure {
|
||||||
|
Image(uiImage: UIImage(blurHash: fullItem
|
||||||
|
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
||||||
|
fullItem.PosterBlurHash,
|
||||||
|
size: CGSize(width: 32, height: 32))!)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 120, height: 180)
|
||||||
|
.cornerRadius(10)
|
||||||
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
|
.frame(width: 120, height: 180)
|
||||||
|
.cornerRadius(10)
|
||||||
|
Spacer().frame(height: 4)
|
||||||
|
if fullItem.ProductionYear != 0 {
|
||||||
|
Text(String(fullItem.ProductionYear)).font(.subheadline)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
ScrollView {
|
||||||
|
LazyVStack(alignment: .leading) {
|
||||||
if fullItem.Tagline != "" {
|
if fullItem.Tagline != "" {
|
||||||
Text(fullItem.Tagline).font(.body).italic().padding(.top, 7)
|
Text(fullItem.Tagline).font(.body).italic().padding(.top, 3)
|
||||||
.fixedSize(horizontal: false, vertical: true).padding(.leading, 16)
|
.fixedSize(horizontal: false, vertical: true).padding(.leading, 16)
|
||||||
.padding(.trailing, 16)
|
.padding(.trailing, 16)
|
||||||
}
|
}
|
||||||
Text(fullItem.Overview).font(.footnote).padding(.top, 3)
|
if fullItem.Overview != "" {
|
||||||
.fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16)
|
Text(fullItem.Overview).font(.footnote).padding(.top, 3)
|
||||||
.padding(.trailing, 16)
|
.fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16)
|
||||||
|
.padding(.trailing, 16)
|
||||||
|
}
|
||||||
ForEach(episodes, id: \.Id) { episode in
|
ForEach(episodes, id: \.Id) { episode in
|
||||||
NavigationLink(destination: ItemView(item: episode.ResumeItem ?? ResumeItem())) {
|
NavigationLink(destination: ItemView(item: episode.ResumeItem ?? ResumeItem())) {
|
||||||
HStack {
|
HStack {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(episode.Id)/Images/Primary?maxWidth=300&quality=90&tag=\(episode.Poster)")!)
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(episode.Id)/Images/Primary?maxWidth=300&quality=90&tag=\(episode.Poster)"))
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: episode
|
Image(uiImage: UIImage(blurHash: episode
|
||||||
.PosterBlurHash == "" ?
|
.PosterBlurHash == "" ?
|
||||||
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
||||||
|
@ -271,7 +402,8 @@ struct SeasonItemView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 150, height: 90)
|
.frame(width: 150, height: 90)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}.aspectRatio(contentMode: .fill)
|
}
|
||||||
|
.contentMode(.aspectFill)
|
||||||
.shadow(radius: 5)
|
.shadow(radius: 5)
|
||||||
.frame(width: 150, height: 90)
|
.frame(width: 150, height: 90)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
|
@ -289,11 +421,30 @@ struct SeasonItemView: View {
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
Spacer()
|
|
||||||
Text(episode.Runtime).font(.subheadline)
|
Text(episode.Runtime).font(.subheadline)
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
|
if episode.OfficialRating != "" {
|
||||||
|
Text(episode.OfficialRating).font(.subheadline)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
.padding(EdgeInsets(top: 1, leading: 4, bottom: 1, trailing: 4))
|
||||||
|
.overlay(RoundedRectangle(cornerRadius: 2)
|
||||||
|
.stroke(Color.secondary, lineWidth: 1))
|
||||||
|
}
|
||||||
|
if episode.CommunityRating != "" {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "star").foregroundColor(.secondary)
|
||||||
|
Text(episode.CommunityRating).font(.subheadline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
.offset(x: -6, y: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
Text(episode.Overview).font(.footnote).foregroundColor(.secondary)
|
Text(episode.Overview).font(.footnote).foregroundColor(.secondary)
|
||||||
|
@ -324,163 +475,19 @@ struct SeasonItemView: View {
|
||||||
.foregroundColor(Color.secondary)
|
.foregroundColor(Color.secondary)
|
||||||
}.padding(.leading, 16).padding(.trailing, 16)
|
}.padding(.leading, 16).padding(.trailing, 16)
|
||||||
}
|
}
|
||||||
Spacer().frame(height: 3)
|
Spacer().frame(height: 125)
|
||||||
}
|
}.frame(maxHeight: .infinity)
|
||||||
}
|
}.padding(.trailing, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 55)
|
||||||
} else {
|
}.padding(.top, 16).padding(.leading, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 0)
|
||||||
GeometryReader { geometry in
|
|
||||||
ZStack {
|
|
||||||
WebImage(url: 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 ?? "")")!)
|
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
|
||||||
.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()
|
|
||||||
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets
|
|
||||||
.trailing,
|
|
||||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets
|
|
||||||
.bottom)
|
|
||||||
}
|
|
||||||
|
|
||||||
.opacity(0.4)
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
|
||||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom)
|
|
||||||
.edgesIgnoringSafeArea(.all)
|
|
||||||
.blur(radius: 2)
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=250&quality=90&tag=\(fullItem.Poster)")!)
|
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: fullItem
|
|
||||||
.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" :
|
|
||||||
fullItem.PosterBlurHash,
|
|
||||||
size: CGSize(width: 32, height: 32))!)
|
|
||||||
.resizable()
|
|
||||||
.frame(width: 120, height: 180)
|
|
||||||
.cornerRadius(10)
|
|
||||||
}.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: 120, height: 180)
|
|
||||||
.cornerRadius(10)
|
|
||||||
Spacer().frame(height: 4)
|
|
||||||
if fullItem.ProductionYear != 0 {
|
|
||||||
Text(String(fullItem.ProductionYear)).font(.subheadline)
|
|
||||||
.fontWeight(.medium)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
ScrollView {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
if fullItem.Tagline != "" {
|
|
||||||
Text(fullItem.Tagline).font(.body).italic().padding(.top, 3)
|
|
||||||
.fixedSize(horizontal: false, vertical: true).padding(.leading, 16)
|
|
||||||
.padding(.trailing, 16)
|
|
||||||
}
|
|
||||||
if fullItem.Overview != "" {
|
|
||||||
Text(fullItem.Overview).font(.footnote).padding(.top, 3)
|
|
||||||
.fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16)
|
|
||||||
.padding(.trailing, 16)
|
|
||||||
}
|
|
||||||
ForEach(episodes, id: \.Id) { episode in
|
|
||||||
NavigationLink(destination: ItemView(item: episode.ResumeItem ?? ResumeItem())) {
|
|
||||||
HStack {
|
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(episode.Id)/Images/Primary?maxWidth=300&quality=90&tag=\(episode.Poster)")!)
|
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: episode
|
|
||||||
.PosterBlurHash == "" ?
|
|
||||||
"W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem
|
|
||||||
.PosterBlurHash,
|
|
||||||
size: CGSize(width: 32, height: 32))!)
|
|
||||||
.resizable()
|
|
||||||
.frame(width: 150, height: 90)
|
|
||||||
.cornerRadius(10)
|
|
||||||
}.aspectRatio(contentMode: .fill)
|
|
||||||
.shadow(radius: 5)
|
|
||||||
.frame(width: 150, height: 90)
|
|
||||||
.cornerRadius(10)
|
|
||||||
.overlay(RoundedRectangle(cornerRadius: 10, style: .circular)
|
|
||||||
.fill(Color(red: 172 / 255, green: 92 / 255, blue: 195 / 255)
|
|
||||||
.opacity(0.4))
|
|
||||||
.frame(width: CGFloat((episode.Progress / Double(episode.RuntimeTicks)) *
|
|
||||||
150),
|
|
||||||
height: 90)
|
|
||||||
.padding(0), alignment: .bottomLeading)
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
HStack {
|
|
||||||
Text(episode.Name).font(.subheadline)
|
|
||||||
.fontWeight(.semibold)
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
.lineLimit(1)
|
|
||||||
Text(episode.Runtime).font(.subheadline)
|
|
||||||
.fontWeight(.medium)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.lineLimit(1)
|
|
||||||
if episode.OfficialRating != "" {
|
|
||||||
Text(episode.OfficialRating).font(.subheadline)
|
|
||||||
.fontWeight(.medium)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.lineLimit(1)
|
|
||||||
.padding(EdgeInsets(top: 1, leading: 4, bottom: 1, trailing: 4))
|
|
||||||
.overlay(RoundedRectangle(cornerRadius: 2)
|
|
||||||
.stroke(Color.secondary, lineWidth: 1))
|
|
||||||
}
|
|
||||||
if episode.CommunityRating != "" {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "star").foregroundColor(.secondary)
|
|
||||||
Text(episode.CommunityRating).font(.subheadline)
|
|
||||||
.fontWeight(.semibold)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.lineLimit(1)
|
|
||||||
.offset(x: -6, y: 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
Text(episode.Overview).font(.footnote).foregroundColor(.secondary)
|
|
||||||
.fixedSize(horizontal: false, vertical: true).lineLimit(4)
|
|
||||||
Spacer()
|
|
||||||
}.padding(.trailing, 20).offset(y: 2)
|
|
||||||
}.offset(x: 12, y: 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !fullItem.Directors.isEmpty {
|
|
||||||
HStack {
|
|
||||||
Text("Directors:").font(.callout).fontWeight(.semibold)
|
|
||||||
Text(fullItem.Directors.joined(separator: ", ")).font(.footnote).lineLimit(1)
|
|
||||||
.foregroundColor(Color.secondary)
|
|
||||||
}.padding(.leading, 16).padding(.trailing, 16)
|
|
||||||
}
|
|
||||||
if !fullItem.Writers.isEmpty {
|
|
||||||
HStack {
|
|
||||||
Text("Writers:").font(.callout).fontWeight(.semibold)
|
|
||||||
Text(fullItem.Writers.joined(separator: ", ")).font(.footnote).lineLimit(1)
|
|
||||||
.foregroundColor(Color.secondary)
|
|
||||||
}.padding(.leading, 16).padding(.trailing, 16)
|
|
||||||
}
|
|
||||||
if !fullItem.Studios.isEmpty {
|
|
||||||
HStack {
|
|
||||||
Text("Studios:").font(.callout).fontWeight(.semibold)
|
|
||||||
Text(fullItem.Studios.joined(separator: ", ")).font(.footnote).lineLimit(1)
|
|
||||||
.foregroundColor(Color.secondary)
|
|
||||||
}.padding(.leading, 16).padding(.trailing, 16)
|
|
||||||
}
|
|
||||||
Spacer().frame(height: 125)
|
|
||||||
}.frame(maxHeight: .infinity)
|
|
||||||
}.padding(.trailing, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 55)
|
|
||||||
}.padding(.top, 16).padding(.leading, UIDevice.current.userInterfaceIdiom == .pad ? 16 : 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
LoadingView(isShowing: $isLoading) {
|
||||||
|
innerBody
|
||||||
|
}
|
||||||
.onAppear(perform: loadData)
|
.onAppear(perform: loadData)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationTitle("\(item.Name) - \(item.SeriesName ?? "")")
|
.navigationTitle("\(item.Name) - \(item.SeriesName ?? "")")
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import SDWebImageSwiftUI
|
import NukeUI
|
||||||
|
|
||||||
struct SeriesItemView: View {
|
struct SeriesItemView: View {
|
||||||
@EnvironmentObject var globalData: GlobalData
|
@EnvironmentObject var globalData: GlobalData
|
||||||
|
@ -96,9 +96,8 @@ struct SeriesItemView: View {
|
||||||
ForEach(items, id: \.Id) { item in
|
ForEach(items, id: \.Id) { item in
|
||||||
NavigationLink(destination: ItemView(item: item )) {
|
NavigationLink(destination: ItemView(item: item )) {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=90&tag=\(item.Image)"))
|
LazyImage(source: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?maxWidth=250&quality=90&tag=\(item.Image)"))
|
||||||
.resizable()
|
.placeholderAndFailure {
|
||||||
.placeholder {
|
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!)
|
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()
|
.resizable()
|
||||||
.frame(width: 100, height: 150)
|
.frame(width: 100, height: 150)
|
||||||
|
|
Loading…
Reference in New Issue