diff --git a/Shared/Coordinators/LibraryCoordinator.swift b/Shared/Coordinators/LibraryCoordinator.swift index a19a72d3..2c987659 100644 --- a/Shared/Coordinators/LibraryCoordinator.swift +++ b/Shared/Coordinators/LibraryCoordinator.swift @@ -48,6 +48,8 @@ final class LibraryCoordinator: NavigationCoordinatable { var item = makeItem @Route(.modal) var filter = makeFilter + @Route(.push) + var library = makeLibrary #endif private let parameters: Parameters @@ -77,5 +79,9 @@ final class LibraryCoordinator: NavigationCoordinatable { func makeFilter(parameters: FilterCoordinator.Parameters) -> NavigationViewCoordinator { NavigationViewCoordinator(FilterCoordinator(parameters: parameters)) } + + func makeLibrary(parameters: LibraryCoordinator.Parameters) -> LibraryCoordinator { + LibraryCoordinator(parameters: parameters) + } #endif } diff --git a/Shared/ViewModels/LibraryViewModel.swift b/Shared/ViewModels/LibraryViewModel.swift index a772e0d8..f0fc27de 100644 --- a/Shared/ViewModels/LibraryViewModel.swift +++ b/Shared/ViewModels/LibraryViewModel.swift @@ -86,26 +86,26 @@ final class LibraryViewModel: ViewModel { } } + var recursive = true let includeItemTypes: [BaseItemKind] if filters.filters.contains(ItemFilter.isFavorite.filter) { includeItemTypes = [.movie, .boxSet, .series, .season, .episode] } else if type == .folders { - includeItemTypes = [.collectionFolder] + recursive = false + includeItemTypes = [.movie, .boxSet, .series, .folder, .collectionFolder] } else { - includeItemTypes = [.movie, .series, .boxSet] + includeItemTypes = [.movie, .boxSet, .series] } - let excludedIDs: [String]? + var excludedIDs: [String]? if filters.sortBy.first == SortBy.random.filter { excludedIDs = items.compactMap(\.id) - } else { - excludedIDs = nil } let genreIDs = filters.genres.compactMap(\.id) - let sortBy: [String] = filters.sortBy.map(\.filterName) + let sortBy: [String] = filters.sortBy.map(\.filterName).appending("IsFolder") let sortOrder = filters.sortOrder.map { SortOrder(rawValue: $0.filterName) ?? .ascending } let itemFilters: [ItemFilter] = filters.filters.compactMap { .init(rawValue: $0.filterName) } let tags: [String] = filters.tags.map(\.filterName) @@ -115,7 +115,7 @@ final class LibraryViewModel: ViewModel { excludeItemIds: excludedIDs, startIndex: currentPage * pageItemSize, limit: pageItemSize, - recursive: true, + recursive: recursive, sortOrder: sortOrder, parentId: libraryID, fields: ItemFields.allCases, diff --git a/Swiftfin/Components/PosterButton.swift b/Swiftfin/Components/PosterButton.swift index b379baed..342d7ecd 100644 --- a/Swiftfin/Components/PosterButton.swift +++ b/Swiftfin/Components/PosterButton.swift @@ -14,10 +14,10 @@ struct PosterButton Content - private var imageOverlay: (Item) -> ImageOverlay - private var contextMenu: (Item) -> ContextMenu - private var onSelect: (Item) -> Void + private var content: () -> Content + private var imageOverlay: () -> ImageOverlay + private var contextMenu: () -> ContextMenu + private var onSelect: () -> Void private var singleImage: Bool private var itemWidth: CGFloat { @@ -29,10 +29,10 @@ struct PosterButton Content, - @ViewBuilder imageOverlay: @escaping (Item) -> ImageOverlay, - @ViewBuilder contextMenu: @escaping (Item) -> ContextMenu, - onSelect: @escaping (Item) -> Void, + @ViewBuilder content: @escaping () -> Content, + @ViewBuilder imageOverlay: @escaping () -> ImageOverlay, + @ViewBuilder contextMenu: @escaping () -> ContextMenu, + onSelect: @escaping () -> Void, singleImage: Bool ) { self.item = item @@ -49,7 +49,7 @@ struct PosterButton, type: type, itemScale: 1, horizontalAlignment: .leading, - content: { PosterButtonDefaultContentView(item: $0) }, - imageOverlay: { _ in EmptyView() }, - contextMenu: { _ in EmptyView() }, - onSelect: { _ in }, + content: { PosterButtonDefaultContentView(item: item) }, + imageOverlay: { EmptyView() }, + contextMenu: { EmptyView() }, + onSelect: {}, singleImage: singleImage ) } @@ -109,7 +109,7 @@ extension PosterButton { } @ViewBuilder - func content(@ViewBuilder _ content: @escaping (Item) -> C) -> PosterButton { + func content(@ViewBuilder _ content: @escaping () -> C) -> PosterButton { PosterButton( item: item, type: type, @@ -124,7 +124,7 @@ extension PosterButton { } @ViewBuilder - func imageOverlay(@ViewBuilder _ imageOverlay: @escaping (Item) -> O) -> PosterButton { + func imageOverlay(@ViewBuilder _ imageOverlay: @escaping () -> O) -> PosterButton { PosterButton( item: item, type: type, @@ -139,7 +139,7 @@ extension PosterButton { } @ViewBuilder - func contextMenu(@ViewBuilder _ contextMenu: @escaping (Item) -> M) -> PosterButton { + func contextMenu(@ViewBuilder _ contextMenu: @escaping () -> M) -> PosterButton { PosterButton( item: item, type: type, @@ -153,7 +153,7 @@ extension PosterButton { ) } - func onSelect(_ action: @escaping (Item) -> Void) -> Self { + func onSelect(_ action: @escaping () -> Void) -> Self { var copy = self copy.onSelect = action return copy diff --git a/Swiftfin/Components/PosterHStack.swift b/Swiftfin/Components/PosterHStack.swift index 1c9970c7..1319dcb2 100644 --- a/Swiftfin/Components/PosterHStack.swift +++ b/Swiftfin/Components/PosterHStack.swift @@ -65,9 +65,9 @@ struct PosterHStack: View { var body: some View { PosterButton(item: episode, type: .landscape, singleImage: true) .scaleItem(1.2) - .imageOverlay { _ in + .imageOverlay { if let progress = episode.progress { LandscapePosterProgressBar( title: progress, @@ -40,7 +40,7 @@ struct EpisodeCard: View { } } } - .content { _ in + .content { Button { router.route(to: \.item, episode) } label: { @@ -78,7 +78,7 @@ struct EpisodeCard: View { } } } - .onSelect { _ in + .onSelect { episode.createVideoPlayerViewModel() .sink { completion in self.viewModel.handleAPIRequestError(completion: completion) diff --git a/Swiftfin/Views/ItemView/ItemView.swift b/Swiftfin/Views/ItemView/ItemView.swift index 35ad436c..deada00f 100644 --- a/Swiftfin/Views/ItemView/ItemView.swift +++ b/Swiftfin/Views/ItemView/ItemView.swift @@ -45,7 +45,8 @@ struct ItemView: View { case .person: LibraryView(viewModel: .init(parent: item, type: .person)) case .collectionFolder: - LibraryView(viewModel: .init(parent: item, type: .folders)) + Text("Here") +// LibraryView(viewModel: .init(parent: item, type: .folders)) default: Text(L10n.notImplementedYetWithType(item.type ?? "--")) } diff --git a/Swiftfin/Views/LibraryView/Components/LibraryItemRow.swift b/Swiftfin/Views/LibraryView/Components/LibraryItemRow.swift index 3efcead2..43979873 100644 --- a/Swiftfin/Views/LibraryView/Components/LibraryItemRow.swift +++ b/Swiftfin/Views/LibraryView/Components/LibraryItemRow.swift @@ -15,10 +15,11 @@ struct LibraryItemRow: View { private var router: LibraryCoordinator.Router let item: BaseItemDto + private var onSelect: () -> Void var body: some View { Button { - router.route(to: \.item, item) + onSelect() } label: { HStack(alignment: .bottom) { ImageView(item.portraitPosterImageSource(maxWidth: 60)) @@ -55,3 +56,16 @@ struct LibraryItemRow: View { } } } + +extension LibraryItemRow { + init(item: BaseItemDto) { + self.item = item + self.onSelect = {} + } + + func onSelect(_ action: @escaping () -> Void) -> Self { + var copy = self + copy.onSelect = action + return copy + } +} diff --git a/Swiftfin/Views/LibraryView/LibraryView.swift b/Swiftfin/Views/LibraryView/LibraryView.swift index a4e5c20f..5520b19c 100644 --- a/Swiftfin/Views/LibraryView/LibraryView.swift +++ b/Swiftfin/Views/LibraryView/LibraryView.swift @@ -8,6 +8,7 @@ import CollectionView import Defaults +import JellyfinAPI import SwiftUI struct LibraryView: View { @@ -40,10 +41,27 @@ struct LibraryView: View { } } + private func baseItemOnSelect(_ item: BaseItemDto) { + if let baseParent = viewModel.parent as? BaseItemDto { + if baseParent.collectionType == "folders" { + router.route(to: \.library, .init(parent: item, type: .folders, filters: .init())) + } else if item.type == .folder { + router.route(to: \.library, .init(parent: item, type: .library, filters: .init())) + } else { + router.route(to: \.item, item) + } + } else { + router.route(to: \.item, item) + } + } + @ViewBuilder private var libraryListView: some View { CollectionView(items: viewModel.items) { _, item, _ in LibraryItemRow(item: item) + .onSelect { + baseItemOnSelect(item) + } .padding() } .layout { _, layoutEnvironment in @@ -65,8 +83,8 @@ struct LibraryView: View { CollectionView(items: viewModel.items) { _, item, _ in PosterButton(item: item, type: libraryGridPosterType) .scaleItem(libraryGridPosterType == .landscape && UIDevice.isPhone ? 0.85 : 1) - .onSelect { item in - router.route(to: \.item, item) + .onSelect { + baseItemOnSelect(item) } } .layout { _, layoutEnvironment in diff --git a/Swiftfin/Views/MediaView.swift b/Swiftfin/Views/MediaView.swift index ae66c486..27206dd3 100644 --- a/Swiftfin/Views/MediaView.swift +++ b/Swiftfin/Views/MediaView.swift @@ -30,7 +30,7 @@ struct MediaView: View { CollectionView(items: viewModel.libraryItems) { _, item, _ in PosterButton(item: item, type: .landscape) .scaleItem(UIDevice.isPhone ? 0.85 : 1) - .onSelect { _ in + .onSelect { switch item.library.collectionType { case "favorites": router.route(to: \.library, .init(parent: item.library, type: .library, filters: .favorites)) @@ -42,7 +42,7 @@ struct MediaView: View { router.route(to: \.library, .init(parent: item.library, type: .library, filters: .init())) } } - .imageOverlay { _ in + .imageOverlay { ZStack { Color.black .opacity(0.5)