From 7aa602f19dec3cf526c4550c5e63a8fc6dfac723 Mon Sep 17 00:00:00 2001 From: Shav Kinderlehrer Date: Wed, 27 Dec 2023 08:25:35 -0500 Subject: Implement auto aspect ratio for LibraryIconViews --- Jel/Views/Library/Item/ItemInfoView.swift | 4 +- Jel/Views/Library/Item/ItemMediaView.swift | 77 ++++++++++++++++++++++++ Jel/Views/Library/Item/ItemMovieView.swift | 77 ------------------------ Jel/Views/Library/Item/Types/ItemMovieView.swift | 22 +++++++ Jel/Views/Library/LibraryDetailView.swift | 65 +++++++++----------- Jel/Views/Library/LibraryIconView.swift | 21 ++++++- 6 files changed, 150 insertions(+), 116 deletions(-) create mode 100644 Jel/Views/Library/Item/ItemMediaView.swift delete mode 100644 Jel/Views/Library/Item/ItemMovieView.swift create mode 100644 Jel/Views/Library/Item/Types/ItemMovieView.swift (limited to 'Jel/Views/Library') diff --git a/Jel/Views/Library/Item/ItemInfoView.swift b/Jel/Views/Library/Item/ItemInfoView.swift index d48dfef..103acf9 100644 --- a/Jel/Views/Library/Item/ItemInfoView.swift +++ b/Jel/Views/Library/Item/ItemInfoView.swift @@ -14,9 +14,9 @@ struct ItemInfoView: View { var body: some View { VStack(alignment: .leading) { HStack { - Text(item.genres?.first ?? "---") - Text("•") Text((item.productionYear != nil) ? String(item.productionYear!) : "---") + Text("•") + Text(item.genres?.first ?? "---") } Text(item.getRuntime() ?? "-:--") } diff --git a/Jel/Views/Library/Item/ItemMediaView.swift b/Jel/Views/Library/Item/ItemMediaView.swift new file mode 100644 index 0000000..38c242d --- /dev/null +++ b/Jel/Views/Library/Item/ItemMediaView.swift @@ -0,0 +1,77 @@ +// +// ItemMediaView.swift +// Jel +// +// Created by zerocool on 12/23/23. +// + +import SwiftUI +import JellyfinKit + +struct ItemMediaView: View { + @EnvironmentObject var jellyfinClient: JellyfinClientController + @StateObject var authState: AuthStateController = AuthStateController.shared + + @State var item: BaseItemDto + @State var loading: Bool = true + + @State var navigationTitle: String = "" + + var body: some View { + VStack { + if loading { + ProgressView() + .progressViewStyle(.circular) + } else { + ScrollView { + ItemHeaderView(item: item) + .padding(.bottom) + .background { + GeometryReader {geo in + EmptyView() + .onChange(of: geo.frame(in: .global).minY) { + let minY = geo.frame(in: .global).minY + if minY < 0 { + navigationTitle = item.name ?? "" + } else { + navigationTitle = "" + } + } + } + } + + VStack(alignment: .leading) { + Text(item.taglines?.count ?? 0 > 0 ? item.taglines?[0] ?? "" : "") + .font(.headline) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.bottom) + + Text(item.overview ?? "---") + } + .padding() + } + } + } + .toolbarRole(.editor) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(navigationTitle) + .ignoresSafeArea() + .scrollIndicators(.hidden) + .onAppear { + Task { + do { + let request = Paths.getItem(userID: authState.userId ?? "", itemID: item.id ?? "") + let response = try await jellyfinClient.send(request) + item = response.value + loading = false + } catch { + } + } + } + } +} + +//#Preview { +// ItemMovieView(item: BaseItemDto()) + +//} diff --git a/Jel/Views/Library/Item/ItemMovieView.swift b/Jel/Views/Library/Item/ItemMovieView.swift deleted file mode 100644 index eed083e..0000000 --- a/Jel/Views/Library/Item/ItemMovieView.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// ItemMovieView.swift -// Jel -// -// Created by zerocool on 12/23/23. -// - -import SwiftUI -import JellyfinKit - -struct ItemMovieView: View { - @EnvironmentObject var jellyfinClient: JellyfinClientController - @StateObject var authState: AuthStateController = AuthStateController.shared - - @State var item: BaseItemDto - @State var loading: Bool = true - - @State var navigationTitle: String = "" - - var body: some View { - VStack { - if loading { - ProgressView() - .progressViewStyle(.circular) - } else { - ScrollView { - ItemHeaderView(item: item) - .padding(.bottom) - .background { - GeometryReader {geo in - EmptyView() - .onChange(of: geo.frame(in: .global).minY) { - let minY = geo.frame(in: .global).minY - if minY < 0 { - navigationTitle = item.name ?? "" - } else { - navigationTitle = "" - } - } - } - } - - VStack(alignment: .leading) { - Text(item.taglines?.count ?? 0 > 0 ? item.taglines?[0] ?? "" : "") - .font(.headline) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.bottom) - - Text(item.overview ?? "---") - } - .padding() - } - } - } - .toolbarRole(.editor) - .navigationBarTitleDisplayMode(.inline) - .navigationTitle(navigationTitle) - .ignoresSafeArea() - .scrollIndicators(.hidden) - .onAppear { - Task { - do { - let request = Paths.getItem(userID: authState.userId ?? "", itemID: item.id ?? "") - let response = try await jellyfinClient.send(request) - item = response.value - loading = false - } catch { - } - } - } - } -} - -//#Preview { -// ItemMovieView(item: BaseItemDto()) - -//} diff --git a/Jel/Views/Library/Item/Types/ItemMovieView.swift b/Jel/Views/Library/Item/Types/ItemMovieView.swift new file mode 100644 index 0000000..22de82d --- /dev/null +++ b/Jel/Views/Library/Item/Types/ItemMovieView.swift @@ -0,0 +1,22 @@ +// +// ItemMovieView.swift +// Jel +// +// Created by zerocool on 12/26/23. +// + +import SwiftUI +import JellyfinKit + +struct ItemMovieView: View { + @State var item: BaseItemDto + var body: some View { + VStack { + ItemMediaView(item: item) + } + } +} + +//#Preview { +// ItemMovieView() +//} diff --git a/Jel/Views/Library/LibraryDetailView.swift b/Jel/Views/Library/LibraryDetailView.swift index 5d0e695..5b58a4e 100644 --- a/Jel/Views/Library/LibraryDetailView.swift +++ b/Jel/Views/Library/LibraryDetailView.swift @@ -34,55 +34,50 @@ struct LibraryDetailView: View { } ScrollView { LazyVGrid(columns: columns) { - if !searchText.isEmpty { - ForEach(searchResultItems ?? []) {item in - NavigationLink { - ItemView(item: item) - } label: { - LibraryIconView(library: item, imageType: "Primary", width: 170) - .padding() - } - .buttonStyle(PlainButtonStyle()) - } - } else { - ForEach(items ?? []) {item in - NavigationLink { - ItemView(item: item) - } label: { - LibraryIconView(library: item, imageType: "Primary", width: 170) - .padding() - } - .buttonStyle(PlainButtonStyle()) + // uses searchResultItems only if searchText is not empty + ForEach(!searchText.isEmpty ? (searchResultItems ?? items) ?? [] : items ?? []) {item in + NavigationLink { + ItemView(item: item) + } label: { + LibraryIconView(library: item, imageType: "Primary", width: 170) + .setAspectRatio(item.primaryImageAspectRatio ?? 0.6) + .padding() + } + .buttonStyle(PlainButtonStyle()) } } } .if(!loading) {view in view.searchable(text: $searchText) - .onChange(of: searchText) { - Task { - let parameters = Paths.GetParameters( - userID: AuthStateController.shared.userId, - searchTerm: searchText.lowercased(), - parentID: library.id - ) - searchResultHints = await jellyfinClient.search(parameters: parameters) - - searchResultItems = items?.filter { item in - for hint in searchResultHints?.searchHints ?? [] { - if hint.name == item.name { - return true + .onChange(of: searchText) { + Task { + let parameters = Paths.GetParameters( + userID: AuthStateController.shared.userId, + searchTerm: searchText.lowercased(), + parentID: library.id + ) + searchResultHints = await jellyfinClient.search(parameters: parameters) + + searchResultItems = items?.filter { item in + for hint in searchResultHints?.searchHints ?? [] { + if hint.name == item.name { + return true + } } + return false } - return false } } - } } .navigationTitle(library.name ?? "Unknown") .onAppear { Task { - let params = Paths.GetItemsParameters(userID: authState.userId, parentID: library.id) + let params = Paths.GetItemsParameters( + userID: authState.userId, + parentID: library.id, + fields: [.primaryImageAspectRatio] + ) let request = Paths.getItems(parameters: params) do { diff --git a/Jel/Views/Library/LibraryIconView.swift b/Jel/Views/Library/LibraryIconView.swift index a849446..9bd3182 100644 --- a/Jel/Views/Library/LibraryIconView.swift +++ b/Jel/Views/Library/LibraryIconView.swift @@ -32,21 +32,22 @@ struct LibraryIconView: View { if let image = state.image { image .resizable() + .aspectRatio(contentMode: contentMode) } else { if let content = placeHolder { content } else { Image(uiImage: blurHashImage) .resizable() + .aspectRatio(contentMode: .fill) } } } - .aspectRatio(contentMode: contentMode) .frame(width: width, height: height) .clipShape(RoundedRectangle(cornerRadius: imageCornerRadius)) .onAppear { let blurhash = library.imageBlurHashes?.primary?[library.imageTags?[imageType] ?? ""] ?? "" - blurHashImage = UIImage(blurHash: blurhash, size: CGSize(width: 16, height: 16)) ?? UIImage() + blurHashImage = UIImage(blurHash: blurhash, size: CGSize(width: 32, height: 32)) ?? UIImage() let imageId = library.id ?? "" let request = Paths.getItemImage(itemID: imageId, imageType: imageType) @@ -70,6 +71,22 @@ struct LibraryIconView: View { copy.imageCornerRadius = cornerRadius return copy } + + func setAspectRatio(_ aspectRatio: Double?) -> Self { + var copy = self + if aspectRatio == nil { + return copy + } + + if let newWidth = copy.width { + copy.height = newWidth / aspectRatio! + } + if let newHeight = copy.height { + copy.width = newHeight * aspectRatio! + } + + return copy + } } //#Preview { -- cgit v1.2.3