Fix ItemMediaView NavigationTitle + Implement Genre Filtering

This commit is contained in:
Shav Kinderlehrer 2024-01-07 21:21:36 -05:00
parent 3f74421e5b
commit e807d06319
5 changed files with 64 additions and 14 deletions

View File

@ -18,6 +18,7 @@
3D13F96F2B38A32500E91913 /* StickyHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D13F96E2B38A32500E91913 /* StickyHeaderView.swift */; }; 3D13F96F2B38A32500E91913 /* StickyHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D13F96E2B38A32500E91913 /* StickyHeaderView.swift */; };
3D16FC3C2B2CDFB500E6D8B3 /* DashboardLibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D16FC3B2B2CDFB500E6D8B3 /* DashboardLibraryView.swift */; }; 3D16FC3C2B2CDFB500E6D8B3 /* DashboardLibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D16FC3B2B2CDFB500E6D8B3 /* DashboardLibraryView.swift */; };
3D3816C92B4B5648006414D7 /* ItemGenresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3816C82B4B5648006414D7 /* ItemGenresView.swift */; }; 3D3816C92B4B5648006414D7 /* ItemGenresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3816C82B4B5648006414D7 /* ItemGenresView.swift */; };
3D3816CE2B4B78BB006414D7 /* VisibilityTrackingScrollView in Frameworks */ = {isa = PBXBuildFile; productRef = 3D3816CD2B4B78BB006414D7 /* VisibilityTrackingScrollView */; };
3D41D1F52B2C962500E58234 /* AppearancePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D41D1F42B2C962500E58234 /* AppearancePicker.swift */; }; 3D41D1F52B2C962500E58234 /* AppearancePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D41D1F42B2C962500E58234 /* AppearancePicker.swift */; };
3D41D1FA2B2CAE0000E58234 /* ItemIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D41D1F92B2CAE0000E58234 /* ItemIconView.swift */; }; 3D41D1FA2B2CAE0000E58234 /* ItemIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D41D1F92B2CAE0000E58234 /* ItemIconView.swift */; };
3D4C15722B3CAA670035373E /* DashboardSectionTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D4C15712B3CAA670035373E /* DashboardSectionTitleView.swift */; }; 3D4C15722B3CAA670035373E /* DashboardSectionTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D4C15712B3CAA670035373E /* DashboardSectionTitleView.swift */; };
@ -123,6 +124,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
3D13F95C2B375A9E00E91913 /* NukeUI in Frameworks */, 3D13F95C2B375A9E00E91913 /* NukeUI in Frameworks */,
3D3816CE2B4B78BB006414D7 /* VisibilityTrackingScrollView in Frameworks */,
3D77093B2B29139700199889 /* PulseUI in Frameworks */, 3D77093B2B29139700199889 /* PulseUI in Frameworks */,
3D7709392B29139700199889 /* Pulse in Frameworks */, 3D7709392B29139700199889 /* Pulse in Frameworks */,
3D9064592B27E4C70063DD2A /* JellyfinKit in Frameworks */, 3D9064592B27E4C70063DD2A /* JellyfinKit in Frameworks */,
@ -334,6 +336,7 @@
3D77093A2B29139700199889 /* PulseUI */, 3D77093A2B29139700199889 /* PulseUI */,
3D13F9592B375A9E00E91913 /* Nuke */, 3D13F9592B375A9E00E91913 /* Nuke */,
3D13F95B2B375A9E00E91913 /* NukeUI */, 3D13F95B2B375A9E00E91913 /* NukeUI */,
3D3816CD2B4B78BB006414D7 /* VisibilityTrackingScrollView */,
); );
productName = Jel; productName = Jel;
productReference = 3D9063C72B279A310063DD2A /* Jel.app */; productReference = 3D9063C72B279A310063DD2A /* Jel.app */;
@ -410,6 +413,7 @@
packageReferences = ( packageReferences = (
3D7709372B29139700199889 /* XCRemoteSwiftPackageReference "Pulse" */, 3D7709372B29139700199889 /* XCRemoteSwiftPackageReference "Pulse" */,
3D13F9582B375A9E00E91913 /* XCRemoteSwiftPackageReference "Nuke" */, 3D13F9582B375A9E00E91913 /* XCRemoteSwiftPackageReference "Nuke" */,
3D3816CC2B4B78BA006414D7 /* XCRemoteSwiftPackageReference "VisibilityTrackingScrollView" */,
); );
productRefGroup = 3D9063C82B279A310063DD2A /* Products */; productRefGroup = 3D9063C82B279A310063DD2A /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -852,6 +856,14 @@
minimumVersion = 12.2.0; minimumVersion = 12.2.0;
}; };
}; };
3D3816CC2B4B78BA006414D7 /* XCRemoteSwiftPackageReference "VisibilityTrackingScrollView" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/elegantchaos/VisibilityTrackingScrollView";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 1.0.0;
};
};
3D7709372B29139700199889 /* XCRemoteSwiftPackageReference "Pulse" */ = { 3D7709372B29139700199889 /* XCRemoteSwiftPackageReference "Pulse" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kean/Pulse"; repositoryURL = "https://github.com/kean/Pulse";
@ -873,6 +885,11 @@
package = 3D13F9582B375A9E00E91913 /* XCRemoteSwiftPackageReference "Nuke" */; package = 3D13F9582B375A9E00E91913 /* XCRemoteSwiftPackageReference "Nuke" */;
productName = NukeUI; productName = NukeUI;
}; };
3D3816CD2B4B78BB006414D7 /* VisibilityTrackingScrollView */ = {
isa = XCSwiftPackageProductDependency;
package = 3D3816CC2B4B78BA006414D7 /* XCRemoteSwiftPackageReference "VisibilityTrackingScrollView" */;
productName = VisibilityTrackingScrollView;
};
3D7709382B29139700199889 /* Pulse */ = { 3D7709382B29139700199889 /* Pulse */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 3D7709372B29139700199889 /* XCRemoteSwiftPackageReference "Pulse" */; package = 3D7709372B29139700199889 /* XCRemoteSwiftPackageReference "Pulse" */;

View File

@ -36,6 +36,15 @@
"revision": "4ce950479707ea109f229d7230ec074a133b15d7", "revision": "4ce950479707ea109f229d7230ec074a133b15d7",
"version": "0.2.1" "version": "0.2.1"
} }
},
{
"package": "VisibilityTrackingScrollView",
"repositoryURL": "https://github.com/elegantchaos/VisibilityTrackingScrollView",
"state": {
"branch": null,
"revision": "9a5788298a1e238ed1e1f51b195a1296125a5a8c",
"version": "1.0.3"
}
} }
] ]
}, },

View File

@ -14,7 +14,7 @@ struct ItemGenresView: View {
@StateObject var authState: AuthStateController = AuthStateController.shared @StateObject var authState: AuthStateController = AuthStateController.shared
var item: BaseItemDto var item: BaseItemDto
@State var library: BaseItemDto = BaseItemDto() @State var libraryItems: [BaseItemDto]? = []
var body: some View { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
@ -25,7 +25,7 @@ struct ItemGenresView: View {
HStack { HStack {
ForEach(item.genres ?? [], id: \.self) {genre in ForEach(item.genres ?? [], id: \.self) {genre in
NavigationLink { NavigationLink {
LibraryDetailView(library: library) {items in LibraryDetailView(library: BaseItemDto(name: genre), items: libraryItems) {items in
var matchingItems: [BaseItemDto] = [] var matchingItems: [BaseItemDto] = []
for item in items { for item in items {
@ -47,10 +47,21 @@ struct ItemGenresView: View {
} }
.onAppear { .onAppear {
Task { Task {
let request = Paths.getItem(userID: authState.userId ?? "", itemID: item.parentID ?? "") let parameters = Paths.GetItemsParameters(
userID: authState.userId ?? "",
isRecursive: true,
fields: [.primaryImageAspectRatio,
.genres,
.taglines,
.overview,
.parentID],
includeItemTypes: [.movie, .series],
genres: item.genres ?? []
)
let request = Paths.getItems(parameters: parameters)
do { do {
let res = try await jellyfinClient.send(request) let res = try await jellyfinClient.send(request)
library = res.value libraryItems = res.value.items ?? []
} catch { } catch {
} }
} }

View File

@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
import JellyfinKit import JellyfinKit
import VisibilityTrackingScrollView
struct ItemMediaView: View { struct ItemMediaView: View {
@EnvironmentObject var jellyfinClient: JellyfinClientController @EnvironmentObject var jellyfinClient: JellyfinClientController
@ -15,7 +16,7 @@ struct ItemMediaView: View {
@State var item: BaseItemDto @State var item: BaseItemDto
@State var loading: Bool = true @State var loading: Bool = true
@State var navigationTitle: String = "" @State var pageScrolled: Bool = false
var body: some View { var body: some View {
GeometryReader {geo in GeometryReader {geo in
@ -23,7 +24,7 @@ struct ItemMediaView: View {
ProgressView() ProgressView()
.progressViewStyle(.circular) .progressViewStyle(.circular)
} else { } else {
ScrollView { ScrollView() {
ItemHeaderView(item: item) ItemHeaderView(item: item)
.padding(.bottom) .padding(.bottom)
.background { .background {
@ -31,11 +32,8 @@ struct ItemMediaView: View {
EmptyView() EmptyView()
.onChange(of: geo.frame(in: .global).minY) { .onChange(of: geo.frame(in: .global).minY) {
let minY = geo.frame(in: .global).minY let minY = geo.frame(in: .global).minY
if minY < 0 {
navigationTitle = item.name ?? "" pageScrolled = minY < 0
} else {
navigationTitle = ""
}
} }
} }
} }
@ -49,6 +47,8 @@ struct ItemMediaView: View {
ForEach(item.overview?.components(separatedBy: "<br>") ?? [], id: \.self) {overview in ForEach(item.overview?.components(separatedBy: "<br>") ?? [], id: \.self) {overview in
Text(overview) Text(overview)
} }
ItemGenresView(item: item)
} }
.if(max(geo.safeAreaInsets.leading, geo.safeAreaInsets.trailing) > 0) {view in .if(max(geo.safeAreaInsets.leading, geo.safeAreaInsets.trailing) > 0) {view in
view view
@ -62,9 +62,15 @@ struct ItemMediaView: View {
.ignoresSafeArea() .ignoresSafeArea()
} }
} }
.toolbarRole(.editor)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.navigationTitle(navigationTitle) .navigationTitle(item.name ?? "Untitled")
.toolbarRole(.editor)
.toolbar {
ToolbarItem(placement: .principal) {
Text(pageScrolled ? item.name ?? "Untitled" : "")
.bold()
}
}
.scrollIndicators(.hidden) .scrollIndicators(.hidden)
.onAppear { .onAppear {
Task { Task {

View File

@ -13,9 +13,9 @@ struct LibraryDetailView: View {
@StateObject var authState: AuthStateController = AuthStateController.shared @StateObject var authState: AuthStateController = AuthStateController.shared
@State var library: BaseItemDto @State var library: BaseItemDto
@State var items: [BaseItemDto]? = []
var filter: (_ items: [BaseItemDto]) -> [BaseItemDto] var filter: (_ items: [BaseItemDto]) -> [BaseItemDto]
@State var items: [BaseItemDto]? = []
@State var loading: Bool = true @State var loading: Bool = true
@ -73,6 +73,13 @@ struct LibraryDetailView: View {
} }
} }
.onAppear { .onAppear {
if items?.count ?? 0 > 0 {
items = self.filter(items ?? [])
items?.sort(by: {$0.name?.lowercased() ?? "" < $1.name?.lowercased() ?? ""})
loading = false
return
}
Task { Task {
let params = Paths.GetItemsParameters( let params = Paths.GetItemsParameters(
userID: authState.userId, userID: authState.userId,