Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic support for folder-type library items #351

Merged
merged 5 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,12 @@ public extension BaseItemDto {
}

func getSeriesPrimaryImage(maxWidth: Int) -> URL {
guard let seriesId = seriesId else {
return getPrimaryImage(maxWidth: maxWidth)
}

let x = UIScreen.main.nativeScale * CGFloat(maxWidth)
let urlString = ImageAPI.getItemImageWithRequestBuilder(itemId: seriesId ?? "",
let urlString = ImageAPI.getItemImageWithRequestBuilder(itemId: seriesId,
imageType: .primary,
maxWidth: Int(x),
quality: 96,
Expand Down Expand Up @@ -227,6 +231,7 @@ public extension BaseItemDto {
case series = "Series"
case boxset = "BoxSet"
case collectionFolder = "CollectionFolder"
case folder = "Folder"

case unknown

Expand All @@ -249,7 +254,7 @@ public extension BaseItemDto {

func portraitHeaderViewURL(maxWidth: Int) -> URL {
switch itemType {
case .movie, .season, .series, .boxset, .collectionFolder:
case .movie, .season, .series, .boxset, .collectionFolder, .folder:
return getPrimaryImage(maxWidth: maxWidth)
case .episode:
return getSeriesPrimaryImage(maxWidth: maxWidth)
Expand Down
2 changes: 2 additions & 0 deletions Shared/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ internal enum L10n {
internal static var settings: String { return L10n.tr("Localizable", "settings") }
/// Show Cast & Crew
internal static var showCastAndCrew: String { return L10n.tr("Localizable", "showCastAndCrew") }
/// Flatten Library Items
internal static var showFlattenView: String { return L10n.tr("Localizable", "showFlattenView") }
/// Show Missing Episodes
internal static var showMissingEpisodes: String { return L10n.tr("Localizable", "showMissingEpisodes") }
/// Show Missing Seasons
Expand Down
1 change: 1 addition & 0 deletions Shared/SwiftfinStore/SwiftfinStoreDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ extension Defaults.Keys {
// Customize settings
static let showPosterLabels = Key<Bool>("showPosterLabels", default: true, suite: SwiftfinStore.Defaults.generalSuite)
static let showCastAndCrew = Key<Bool>("showCastAndCrew", default: true, suite: SwiftfinStore.Defaults.generalSuite)
static let showFlattenView = Key<Bool>("showFlattenView", default: true, suite: SwiftfinStore.Defaults.generalSuite)

// Video player / overlay settings
static let overlayType = Key<OverlayType>("overlayType", default: .normal, suite: SwiftfinStore.Defaults.generalSuite)
Expand Down
17 changes: 13 additions & 4 deletions Shared/ViewModels/LibraryViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Combine
import Defaults
import Foundation
import JellyfinAPI
import SwiftUICollection
Expand Down Expand Up @@ -94,10 +95,20 @@ final class LibraryViewModel: ViewModel {
genreIDs = filters.withGenres.compactMap(\.id)
}
let sortBy = filters.sortBy.map(\.rawValue)
let queryRecursive = Defaults[.showFlattenView] || filters.filters.contains(.isFavorite) ||
self.person != nil ||
self.genre != nil ||
self.studio != nil
let includeItemTypes: [String]
if filters.filters.contains(.isFavorite) {
includeItemTypes = ["Movie", "Series", "Season", "Episode", "BoxSet"]
} else {
includeItemTypes = ["Movie", "Series", "BoxSet"] + (Defaults[.showFlattenView] ? [] : ["Folder"])
}

ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, startIndex: currentPage * pageItemSize,
limit: pageItemSize,
recursive: true,
recursive: queryRecursive,
searchTerm: nil,
sortOrder: filters.sortOrder,
parentId: parentID,
Expand All @@ -110,9 +121,7 @@ final class LibraryViewModel: ViewModel {
.people,
.chapters,
],
includeItemTypes: filters.filters
.contains(.isFavorite) ? ["Movie", "Series", "Season", "Episode", "BoxSet"] :
["Movie", "Series", "BoxSet"],
includeItemTypes: includeItemTypes,
filters: filters.filters,
sortBy: sortBy,
tags: filters.tags,
Expand Down
2 changes: 1 addition & 1 deletion Swiftfin tvOS/Views/ItemView/ItemView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct ItemView: View {
} else {
SeriesItemView(viewModel: SeriesItemViewModel(item: item))
}
case .boxset:
case .boxset, .folder:
CinematicCollectionItemView(viewModel: CollectionItemViewModel(item: item))
default:
Text(L10n.notImplementedYetWithType(item.type ?? ""))
Expand Down
37 changes: 8 additions & 29 deletions Swiftfin tvOS/Views/LibraryListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,17 @@ struct LibraryListView: View {
@Default(.Experimental.liveTVAlphaEnabled)
var liveTVAlphaEnabled

let supportedCollectionTypes = ["movies", "tvshows", "boxsets", "livetv", "other"]

var body: some View {
ScrollView {
LazyVStack {
if !viewModel.isLoading {

if let collectionLibraryItem = viewModel.libraries.first(where: { $0.collectionType == "boxsets" }) {
Button {
self.libraryListRouter.route(to: \.library,
(viewModel: LibraryViewModel(parentID: collectionLibraryItem.id),
title: collectionLibraryItem.name ?? ""))
}
label: {
ZStack {
HStack {
Spacer()
VStack {
Text(collectionLibraryItem.name ?? "")
.foregroundColor(.white)
.font(.title2)
.fontWeight(.semibold)
}
Spacer()
}.padding(32)
}
.frame(minWidth: 100, maxWidth: .infinity)
.frame(height: 100)
}
.cornerRadius(10)
.shadow(radius: 5)
.padding(.bottom, 5)
}

ForEach(viewModel.libraries.filter { $0.collectionType != "boxsets" }, id: \.id) { library in
ForEach(viewModel.libraries.filter { [self] library in
let collectionType = library.collectionType ?? "other"
return self.supportedCollectionTypes.contains(collectionType)
}, id: \.id) { library in
if library.collectionType == "livetv" {
if liveTVAlphaEnabled {
Button {
Expand Down Expand Up @@ -81,7 +59,8 @@ struct LibraryListView: View {
}
} else {
Button {
self.libraryListRouter.route(to: \.library, (viewModel: LibraryViewModel(), title: library.name ?? ""))
self.libraryListRouter.route(to: \.library,
(viewModel: LibraryViewModel(parentID: library.id), title: library.name ?? ""))
}
label: {
ZStack {
Expand Down
20 changes: 9 additions & 11 deletions Swiftfin tvOS/Views/LibraryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,15 @@ struct LibraryView: View {
} cell: { _, cell in
GeometryReader { _ in
if let item = cell.item {
if item.type != "Folder" {
Button {
libraryRouter.route(to: \.modalItem, item)
} label: {
PortraitItemElement(item: item)
}
.buttonStyle(PlainNavigationLinkButtonStyle())
.onAppear {
if item == viewModel.items.last && viewModel.hasNextPage {
viewModel.requestNextPageAsync()
}
Button {
libraryRouter.route(to: \.modalItem, item)
} label: {
PortraitItemElement(item: item)
}
.buttonStyle(PlainNavigationLinkButtonStyle())
.onAppear {
if item == viewModel.items.last && viewModel.hasNextPage {
viewModel.requestNextPageAsync()
}
}
} else if cell.loadingCell {
Expand Down
3 changes: 3 additions & 0 deletions Swiftfin tvOS/Views/SettingsView/CustomizeViewsSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ struct CustomizeViewsSettings: View {
var showPosterLabels
@Default(.showCastAndCrew)
var showCastAndCrew
@Default(.showFlattenView)
var showFlattenView

var body: some View {
Form {
Expand All @@ -24,6 +26,7 @@ struct CustomizeViewsSettings: View {

// TODO: Uncomment when cast and crew implemented in item views
// Toggle(L10n.showCastAndCrew, isOn: $showCastAndCrew)
Toggle(L10n.showFlattenView, isOn: $showFlattenView)

} header: {
L10n.customize.text
Expand Down
2 changes: 1 addition & 1 deletion Swiftfin/Views/ItemView/ItemView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private struct ItemView: View {
self.viewModel = EpisodeItemViewModel(item: item)
case .series:
self.viewModel = SeriesItemViewModel(item: item)
case .boxset:
case .boxset, .folder:
self.viewModel = CollectionItemViewModel(item: item)
default:
self.viewModel = ItemViewModel(item: item)
Expand Down
51 changes: 11 additions & 40 deletions Swiftfin/Views/LibraryListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ struct LibraryListView: View {
@StateObject
var viewModel = LibraryListViewModel()

let supportedCollectionTypes = ["movies", "tvshows", "boxsets", "other"]

var body: some View {
ScrollView {
LazyVStack {
Expand All @@ -42,21 +44,23 @@ struct LibraryListView: View {
.padding(.bottom, 5)

if !viewModel.isLoading {

if let collectionsLibraryItem = viewModel.libraries.first(where: { $0.collectionType == "boxsets" }) {
ForEach(viewModel.libraries.filter { [self] library in
let collectionType = library.collectionType ?? "other"
return self.supportedCollectionTypes.contains(collectionType)
}, id: \.id) { library in
Button {
libraryListRouter.route(to: \.library,
(viewModel: LibraryViewModel(parentID: collectionsLibraryItem.id),
title: collectionsLibraryItem.name ?? ""))
(viewModel: LibraryViewModel(parentID: library.id),
title: library.name ?? ""))
} label: {
ZStack {
ImageView(src: collectionsLibraryItem.getPrimaryImage(maxWidth: 500),
bh: collectionsLibraryItem.getPrimaryImageBlurHash())
ImageView(src: library.getPrimaryImage(maxWidth: 500), bh: library.getPrimaryImageBlurHash())
.opacity(0.4)
.accessibilityIgnoresInvertColors()
HStack {
Spacer()
VStack {
Text(collectionsLibraryItem.name ?? "")
Text(library.name ?? "")
.foregroundColor(.white)
.font(.title2)
.fontWeight(.semibold)
Expand All @@ -71,39 +75,6 @@ struct LibraryListView: View {
.shadow(radius: 5)
.padding(.bottom, 5)
}

ForEach(viewModel.libraries, id: \.id) { library in
if library.collectionType ?? "" == "movies" || library.collectionType ?? "" == "tvshows" {
Button {
libraryListRouter.route(to: \.library,
(viewModel: LibraryViewModel(parentID: library.id),
title: library.name ?? ""))
} label: {
ZStack {
ImageView(src: library.getPrimaryImage(maxWidth: 500), bh: library.getPrimaryImageBlurHash())
.opacity(0.4)
.accessibilityIgnoresInvertColors()
HStack {
Spacer()
VStack {
Text(library.name ?? "")
.foregroundColor(.white)
.font(.title2)
.fontWeight(.semibold)
}
Spacer()
}.padding(32)
}.background(Color.black)
.frame(minWidth: 100, maxWidth: .infinity)
.frame(height: 100)
}
.cornerRadius(10)
.shadow(radius: 5)
.padding(.bottom, 5)
} else {
EmptyView()
}
}
} else {
ProgressView()
}
Expand Down
6 changes: 2 additions & 4 deletions Swiftfin/Views/LibraryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ struct LibraryView: View {
VStack {
LazyVGrid(columns: tracks) {
ForEach(viewModel.items, id: \.id) { item in
if item.type != "Folder" {
PortraitItemButton(item: item) { item in
libraryRouter.route(to: \.item, item)
}
PortraitItemButton(item: item) { item in
libraryRouter.route(to: \.item, item)
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions Swiftfin/Views/SettingsView/CustomizeViewsSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ struct CustomizeViewsSettings: View {
var showPosterLabels
@Default(.showCastAndCrew)
var showCastAndCrew
@Default(.showFlattenView)
var showFlattenView

var body: some View {
Form {
Section {

Toggle(L10n.showPosterLabels, isOn: $showPosterLabels)
Toggle(L10n.showCastAndCrew, isOn: $showCastAndCrew)
Toggle(L10n.showFlattenView, isOn: $showFlattenView)

} header: {
L10n.customize.text
Expand Down
Binary file modified Translations/en.lproj/Localizable.strings
Binary file not shown.