Use asyncImage for libraryIcons
This commit is contained in:
parent
885615d1dd
commit
a25acb1219
@ -27,7 +27,6 @@
|
|||||||
3D91FDC92B28C62800919017 /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDC82B28C62800919017 /* SignInView.swift */; };
|
3D91FDC92B28C62800919017 /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDC82B28C62800919017 /* SignInView.swift */; };
|
||||||
3D91FDCB2B28CA2500919017 /* SignInToServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDCA2B28CA2500919017 /* SignInToServerView.swift */; };
|
3D91FDCB2B28CA2500919017 /* SignInToServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDCA2B28CA2500919017 /* SignInToServerView.swift */; };
|
||||||
3D91FDCD2B2907E800919017 /* JellyfinDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDCC2B2907E800919017 /* JellyfinDateFormatter.swift */; };
|
3D91FDCD2B2907E800919017 /* JellyfinDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDCC2B2907E800919017 /* JellyfinDateFormatter.swift */; };
|
||||||
3DAA71C62B31E19200D5FB33 /* AsyncImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DAA71C52B31E19200D5FB33 /* AsyncImageView.swift */; };
|
|
||||||
3DC6BA2D2B2A422300416B9F /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DC6BA2C2B2A422300416B9F /* SettingsController.swift */; };
|
3DC6BA2D2B2A422300416B9F /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DC6BA2C2B2A422300416B9F /* SettingsController.swift */; };
|
||||||
3DDD67932B293BC40026781E /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDD67922B293BC40026781E /* DashboardView.swift */; };
|
3DDD67932B293BC40026781E /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDD67922B293BC40026781E /* DashboardView.swift */; };
|
||||||
3DDD67962B29E28B0026781E /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDD67952B29E28B0026781E /* SettingsView.swift */; };
|
3DDD67962B29E28B0026781E /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDD67952B29E28B0026781E /* SettingsView.swift */; };
|
||||||
@ -87,7 +86,6 @@
|
|||||||
3D91FDC82B28C62800919017 /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
|
3D91FDC82B28C62800919017 /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
|
||||||
3D91FDCA2B28CA2500919017 /* SignInToServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInToServerView.swift; sourceTree = "<group>"; };
|
3D91FDCA2B28CA2500919017 /* SignInToServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInToServerView.swift; sourceTree = "<group>"; };
|
||||||
3D91FDCC2B2907E800919017 /* JellyfinDateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinDateFormatter.swift; sourceTree = "<group>"; };
|
3D91FDCC2B2907E800919017 /* JellyfinDateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinDateFormatter.swift; sourceTree = "<group>"; };
|
||||||
3DAA71C52B31E19200D5FB33 /* AsyncImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncImageView.swift; sourceTree = "<group>"; };
|
|
||||||
3DC0E5802B2832B9001CCE96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
3DC0E5802B2832B9001CCE96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
3DC6BA2C2B2A422300416B9F /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
|
3DC6BA2C2B2A422300416B9F /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
|
||||||
3DDD67922B293BC40026781E /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = "<group>"; };
|
3DDD67922B293BC40026781E /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = "<group>"; };
|
||||||
@ -126,7 +124,6 @@
|
|||||||
3D1015D72B27F54A00F5C29A /* Views */ = {
|
3D1015D72B27F54A00F5C29A /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
3DAA71C42B31E11D00D5FB33 /* Utility */,
|
|
||||||
3D9063CC2B279A310063DD2A /* ContentView.swift */,
|
3D9063CC2B279A310063DD2A /* ContentView.swift */,
|
||||||
3DDD67902B293B780026781E /* Dashboard */,
|
3DDD67902B293B780026781E /* Dashboard */,
|
||||||
3D8AB2A62B366309005BD7D0 /* Library */,
|
3D8AB2A62B366309005BD7D0 /* Library */,
|
||||||
@ -235,14 +232,6 @@
|
|||||||
path = SignIn;
|
path = SignIn;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
3DAA71C42B31E11D00D5FB33 /* Utility */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
3DAA71C52B31E19200D5FB33 /* AsyncImageView.swift */,
|
|
||||||
);
|
|
||||||
path = Utility;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
3DDD67902B293B780026781E /* Dashboard */ = {
|
3DDD67902B293B780026781E /* Dashboard */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -413,7 +402,6 @@
|
|||||||
3DC6BA2D2B2A422300416B9F /* SettingsController.swift in Sources */,
|
3DC6BA2D2B2A422300416B9F /* SettingsController.swift in Sources */,
|
||||||
3D91FDCB2B28CA2500919017 /* SignInToServerView.swift in Sources */,
|
3D91FDCB2B28CA2500919017 /* SignInToServerView.swift in Sources */,
|
||||||
3D16FC3C2B2CDFB500E6D8B3 /* DashboardLibraryView.swift in Sources */,
|
3D16FC3C2B2CDFB500E6D8B3 /* DashboardLibraryView.swift in Sources */,
|
||||||
3DAA71C62B31E19200D5FB33 /* AsyncImageView.swift in Sources */,
|
|
||||||
3D1015E42B28000E00F5C29A /* AuthStateController.swift in Sources */,
|
3D1015E42B28000E00F5C29A /* AuthStateController.swift in Sources */,
|
||||||
3DDD67962B29E28B0026781E /* SettingsView.swift in Sources */,
|
3DDD67962B29E28B0026781E /* SettingsView.swift in Sources */,
|
||||||
3D41D1F52B2C962500E58234 /* AppearancePicker.swift in Sources */,
|
3D41D1F52B2C962500E58234 /* AppearancePicker.swift in Sources */,
|
||||||
|
@ -21,6 +21,7 @@ struct JelApp: App {
|
|||||||
ContentView()
|
ContentView()
|
||||||
.environmentObject(jellyfinClientController)
|
.environmentObject(jellyfinClientController)
|
||||||
.task {
|
.task {
|
||||||
|
URLCache.shared.diskCapacity = 1_000_000_000 // 1GB cache for images
|
||||||
AuthStateController.shared.load()
|
AuthStateController.shared.load()
|
||||||
SettingsController.shared.load()
|
SettingsController.shared.load()
|
||||||
jellyfinClientController.setUrl(url: AuthStateController.shared.serverUrl)
|
jellyfinClientController.setUrl(url: AuthStateController.shared.serverUrl)
|
||||||
|
@ -14,7 +14,12 @@ struct DashboardLibraryView: View {
|
|||||||
@StateObject var authState: AuthStateController = AuthStateController.shared
|
@StateObject var authState: AuthStateController = AuthStateController.shared
|
||||||
|
|
||||||
@State var libraries: [BaseItemDto] = []
|
@State var libraries: [BaseItemDto] = []
|
||||||
|
@State var loading: Bool = true
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
if loading {
|
||||||
|
ProgressView()
|
||||||
|
.progressViewStyle(.circular)
|
||||||
|
}
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
HStack {
|
HStack {
|
||||||
ForEach(libraries) {library in
|
ForEach(libraries) {library in
|
||||||
@ -22,9 +27,10 @@ struct DashboardLibraryView: View {
|
|||||||
NavigationLink {
|
NavigationLink {
|
||||||
LibraryDetailView(library: library)
|
LibraryDetailView(library: library)
|
||||||
} label: {
|
} label: {
|
||||||
LibraryIconView(library: library, height: 200)
|
LibraryIconView(library: library, height: 150)
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,11 +42,11 @@ struct DashboardLibraryView: View {
|
|||||||
if let results = try await jellyfinClient.send(request).value.items {
|
if let results = try await jellyfinClient.send(request).value.items {
|
||||||
libraries = results
|
libraries = results
|
||||||
}
|
}
|
||||||
|
loading = false
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#Preview {
|
//#Preview {
|
||||||
|
@ -15,11 +15,22 @@ struct LibraryDetailView: View {
|
|||||||
@State var library: BaseItemDto
|
@State var library: BaseItemDto
|
||||||
@State var items: [BaseItemDto]? = []
|
@State var items: [BaseItemDto]? = []
|
||||||
|
|
||||||
|
@State var loading: Bool = true
|
||||||
|
|
||||||
|
let columns = [
|
||||||
|
GridItem(.adaptive(minimum: 150))
|
||||||
|
]
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
if loading {
|
||||||
|
ProgressView()
|
||||||
|
.progressViewStyle(.circular)
|
||||||
|
}
|
||||||
ScrollView {
|
ScrollView {
|
||||||
ForEach(items ?? []) {item in
|
LazyVGrid(columns: columns) {
|
||||||
LibraryIconView(library: item, imageType: "Primary", width: 120)
|
ForEach(items ?? []) {item in
|
||||||
.padding()
|
LibraryIconView(library: item, imageType: "Primary", height: 150)
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(library.name ?? "Unknown")
|
.navigationTitle(library.name ?? "Unknown")
|
||||||
@ -31,6 +42,7 @@ struct LibraryDetailView: View {
|
|||||||
do {
|
do {
|
||||||
let res = try await jellyfinClient.send(request)
|
let res = try await jellyfinClient.send(request)
|
||||||
items = res.value.items
|
items = res.value.items
|
||||||
|
loading = false
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,6 +50,6 @@ struct LibraryDetailView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
//#Preview {
|
||||||
LibraryDetailView(library: BaseItemDto())
|
// LibraryDetailView(library: BaseItemDto())
|
||||||
}
|
//}
|
||||||
|
@ -18,20 +18,38 @@ struct LibraryIconView: View {
|
|||||||
var width: CGFloat?
|
var width: CGFloat?
|
||||||
var height: CGFloat?
|
var height: CGFloat?
|
||||||
|
|
||||||
@State var loadedImageBinaryData: Data?
|
@State var blurHashImage: UIImage = UIImage()
|
||||||
|
@State var imageUrl: URL?
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
AsyncImage(url: imageUrl) {image in
|
||||||
AsyncImageView(imageId: library.id ?? "",
|
VStack {
|
||||||
blurhash: library.imageBlurHashes?.primary?[library.imageTags?[imageType] ?? ""] ?? "",
|
image
|
||||||
imageType: imageType)
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fit)
|
||||||
.frame(width: width, height: height)
|
.frame(width: width, height: height)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 5))
|
.clipShape(RoundedRectangle(cornerRadius: 3))
|
||||||
|
Text(library.name ?? "Unknown")
|
||||||
|
.font(.subheadline)
|
||||||
|
}
|
||||||
|
} placeholder: {
|
||||||
|
VStack {
|
||||||
|
Image(uiImage: blurHashImage)
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(width: width, height: height)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 3))
|
||||||
|
Text(library.name ?? "Unknown")
|
||||||
|
.font(.subheadline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.onAppear {
|
||||||
|
let blurhash = library.imageBlurHashes?.primary?[library.imageTags?[imageType] ?? ""] ?? ""
|
||||||
|
blurHashImage = UIImage(blurHash: blurhash, size: CGSize(width: 32, height: 32)) ?? UIImage()
|
||||||
|
|
||||||
|
let imageId = library.id ?? ""
|
||||||
Text(library.name ?? "Unknown")
|
let request = Paths.getItemImage(itemID: imageId, imageType: imageType)
|
||||||
.font(.subheadline)
|
imageUrl = jellyfinClient.getUrl()?.appending(path: request.url?.absoluteString ?? "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
//
|
|
||||||
// AsyncImageView.swift
|
|
||||||
// Jel
|
|
||||||
//
|
|
||||||
// Created by zerocool on 12/19/23.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import JellyfinKit
|
|
||||||
|
|
||||||
struct AsyncImageView: View {
|
|
||||||
@EnvironmentObject var jellyfinClient: JellyfinClientController
|
|
||||||
|
|
||||||
@State var imageId: String
|
|
||||||
@State var blurhash: String
|
|
||||||
@State var imageType: String
|
|
||||||
|
|
||||||
@State var loading = true
|
|
||||||
@State var uiImage: UIImage = UIImage()
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack {
|
|
||||||
if loading {
|
|
||||||
Image(uiImage: uiImage)
|
|
||||||
.resizable()
|
|
||||||
} else {
|
|
||||||
Image(uiImage: uiImage)
|
|
||||||
.resizable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onAppear {
|
|
||||||
uiImage = UIImage(blurHash: blurhash, size: CGSize(width: 16, height: 16)) ?? UIImage()
|
|
||||||
|
|
||||||
Task {
|
|
||||||
let request = Paths.getItemImage(itemID: imageId, imageType: imageType)
|
|
||||||
do {
|
|
||||||
let res = try await jellyfinClient.send(request)
|
|
||||||
if let image = UIImage(data: res.value) {
|
|
||||||
uiImage = image
|
|
||||||
loading = false
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//#Preview {
|
|
||||||
// AsyncImageView(imageId: "", blurhash: "", imageType: "")
|
|
||||||
//}
|
|
Loading…
Reference in New Issue
Block a user