From a25acb1219d506351717edef8ad728abcdaf50f9 Mon Sep 17 00:00:00 2001 From: Shav Kinderlehrer Date: Sat, 23 Dec 2023 11:14:53 -0500 Subject: [PATCH] Use asyncImage for libraryIcons --- Jel.xcodeproj/project.pbxproj | 12 ----- Jel/JelApp.swift | 1 + .../Dashboard/DashboardLibraryView.swift | 12 +++-- Jel/Views/Library/LibraryDetailView.swift | 24 ++++++--- Jel/Views/Library/LibraryIconView.swift | 42 ++++++++++----- Jel/Views/Utility/AsyncImageView.swift | 53 ------------------- 6 files changed, 58 insertions(+), 86 deletions(-) delete mode 100644 Jel/Views/Utility/AsyncImageView.swift diff --git a/Jel.xcodeproj/project.pbxproj b/Jel.xcodeproj/project.pbxproj index 695650b..020a200 100644 --- a/Jel.xcodeproj/project.pbxproj +++ b/Jel.xcodeproj/project.pbxproj @@ -27,7 +27,6 @@ 3D91FDC92B28C62800919017 /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDC82B28C62800919017 /* SignInView.swift */; }; 3D91FDCB2B28CA2500919017 /* SignInToServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D91FDCA2B28CA2500919017 /* SignInToServerView.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 */; }; 3DDD67932B293BC40026781E /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDD67922B293BC40026781E /* DashboardView.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 = ""; }; 3D91FDCA2B28CA2500919017 /* SignInToServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInToServerView.swift; sourceTree = ""; }; 3D91FDCC2B2907E800919017 /* JellyfinDateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinDateFormatter.swift; sourceTree = ""; }; - 3DAA71C52B31E19200D5FB33 /* AsyncImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncImageView.swift; sourceTree = ""; }; 3DC0E5802B2832B9001CCE96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3DC6BA2C2B2A422300416B9F /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = ""; }; 3DDD67922B293BC40026781E /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = ""; }; @@ -126,7 +124,6 @@ 3D1015D72B27F54A00F5C29A /* Views */ = { isa = PBXGroup; children = ( - 3DAA71C42B31E11D00D5FB33 /* Utility */, 3D9063CC2B279A310063DD2A /* ContentView.swift */, 3DDD67902B293B780026781E /* Dashboard */, 3D8AB2A62B366309005BD7D0 /* Library */, @@ -235,14 +232,6 @@ path = SignIn; sourceTree = ""; }; - 3DAA71C42B31E11D00D5FB33 /* Utility */ = { - isa = PBXGroup; - children = ( - 3DAA71C52B31E19200D5FB33 /* AsyncImageView.swift */, - ); - path = Utility; - sourceTree = ""; - }; 3DDD67902B293B780026781E /* Dashboard */ = { isa = PBXGroup; children = ( @@ -413,7 +402,6 @@ 3DC6BA2D2B2A422300416B9F /* SettingsController.swift in Sources */, 3D91FDCB2B28CA2500919017 /* SignInToServerView.swift in Sources */, 3D16FC3C2B2CDFB500E6D8B3 /* DashboardLibraryView.swift in Sources */, - 3DAA71C62B31E19200D5FB33 /* AsyncImageView.swift in Sources */, 3D1015E42B28000E00F5C29A /* AuthStateController.swift in Sources */, 3DDD67962B29E28B0026781E /* SettingsView.swift in Sources */, 3D41D1F52B2C962500E58234 /* AppearancePicker.swift in Sources */, diff --git a/Jel/JelApp.swift b/Jel/JelApp.swift index 5dce28d..bb3fe1e 100644 --- a/Jel/JelApp.swift +++ b/Jel/JelApp.swift @@ -21,6 +21,7 @@ struct JelApp: App { ContentView() .environmentObject(jellyfinClientController) .task { + URLCache.shared.diskCapacity = 1_000_000_000 // 1GB cache for images AuthStateController.shared.load() SettingsController.shared.load() jellyfinClientController.setUrl(url: AuthStateController.shared.serverUrl) diff --git a/Jel/Views/Dashboard/DashboardLibraryView.swift b/Jel/Views/Dashboard/DashboardLibraryView.swift index 98c92c0..00f0e68 100644 --- a/Jel/Views/Dashboard/DashboardLibraryView.swift +++ b/Jel/Views/Dashboard/DashboardLibraryView.swift @@ -14,7 +14,12 @@ struct DashboardLibraryView: View { @StateObject var authState: AuthStateController = AuthStateController.shared @State var libraries: [BaseItemDto] = [] + @State var loading: Bool = true var body: some View { + if loading { + ProgressView() + .progressViewStyle(.circular) + } ScrollView(.horizontal, showsIndicators: false) { HStack { ForEach(libraries) {library in @@ -22,9 +27,10 @@ struct DashboardLibraryView: View { NavigationLink { LibraryDetailView(library: library) } label: { - LibraryIconView(library: library, height: 200) + LibraryIconView(library: library, height: 150) .padding() } + .buttonStyle(PlainButtonStyle()) } } } @@ -36,11 +42,11 @@ struct DashboardLibraryView: View { if let results = try await jellyfinClient.send(request).value.items { libraries = results } + loading = false } catch { } } - } - } + }} } //#Preview { diff --git a/Jel/Views/Library/LibraryDetailView.swift b/Jel/Views/Library/LibraryDetailView.swift index 3d5a04b..37ab613 100644 --- a/Jel/Views/Library/LibraryDetailView.swift +++ b/Jel/Views/Library/LibraryDetailView.swift @@ -15,11 +15,22 @@ struct LibraryDetailView: View { @State var library: BaseItemDto @State var items: [BaseItemDto]? = [] + @State var loading: Bool = true + + let columns = [ + GridItem(.adaptive(minimum: 150)) + ] var body: some View { + if loading { + ProgressView() + .progressViewStyle(.circular) + } ScrollView { - ForEach(items ?? []) {item in - LibraryIconView(library: item, imageType: "Primary", width: 120) - .padding() + LazyVGrid(columns: columns) { + ForEach(items ?? []) {item in + LibraryIconView(library: item, imageType: "Primary", height: 150) + .padding() + } } } .navigationTitle(library.name ?? "Unknown") @@ -31,6 +42,7 @@ struct LibraryDetailView: View { do { let res = try await jellyfinClient.send(request) items = res.value.items + loading = false } catch { } } @@ -38,6 +50,6 @@ struct LibraryDetailView: View { } } -#Preview { - LibraryDetailView(library: BaseItemDto()) -} +//#Preview { +// LibraryDetailView(library: BaseItemDto()) +//} diff --git a/Jel/Views/Library/LibraryIconView.swift b/Jel/Views/Library/LibraryIconView.swift index e5f42b0..6a7d5ae 100644 --- a/Jel/Views/Library/LibraryIconView.swift +++ b/Jel/Views/Library/LibraryIconView.swift @@ -18,20 +18,38 @@ struct LibraryIconView: View { var width: CGFloat? var height: CGFloat? - @State var loadedImageBinaryData: Data? - + @State var blurHashImage: UIImage = UIImage() + @State var imageUrl: URL? var body: some View { - VStack { - AsyncImageView(imageId: library.id ?? "", - blurhash: library.imageBlurHashes?.primary?[library.imageTags?[imageType] ?? ""] ?? "", - imageType: imageType) - .aspectRatio(contentMode: .fill) - .frame(width: width, height: height) - .clipShape(RoundedRectangle(cornerRadius: 5)) + AsyncImage(url: imageUrl) {image in + VStack { + image + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: width, height: height) + .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() - - Text(library.name ?? "Unknown") - .font(.subheadline) + let imageId = library.id ?? "" + let request = Paths.getItemImage(itemID: imageId, imageType: imageType) + imageUrl = jellyfinClient.getUrl()?.appending(path: request.url?.absoluteString ?? "") } } } diff --git a/Jel/Views/Utility/AsyncImageView.swift b/Jel/Views/Utility/AsyncImageView.swift deleted file mode 100644 index 5b9f99c..0000000 --- a/Jel/Views/Utility/AsyncImageView.swift +++ /dev/null @@ -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: "") -//}