fix bug related to recursive folders.
fix UI/UX errors in a specific situation when searching. add UI animation in Search.
This commit is contained in:
parent
c75e5d227e
commit
2888099328
|
@ -11,6 +11,7 @@ import Combine
|
||||||
import CombineExt
|
import CombineExt
|
||||||
import Foundation
|
import Foundation
|
||||||
import JellyfinAPI
|
import JellyfinAPI
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
final class LibrarySearchViewModel: ViewModel {
|
final class LibrarySearchViewModel: ViewModel {
|
||||||
|
|
||||||
|
@ -42,8 +43,7 @@ final class LibrarySearchViewModel: ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupPublishersForSupportedItemType() {
|
func setupPublishersForSupportedItemType() {
|
||||||
|
Publishers.CombineLatest3($movieItems, $showItems, $episodeItems)
|
||||||
let supportedItemTypeListPublishers = Publishers.CombineLatest3($movieItems, $showItems, $episodeItems)
|
|
||||||
.debounce(for: 0.25, scheduler: DispatchQueue.main)
|
.debounce(for: 0.25, scheduler: DispatchQueue.main)
|
||||||
.map { arg -> [ItemType] in
|
.map { arg -> [ItemType] in
|
||||||
var typeList = [ItemType]()
|
var typeList = [ItemType]()
|
||||||
|
@ -58,21 +58,29 @@ final class LibrarySearchViewModel: ViewModel {
|
||||||
}
|
}
|
||||||
return typeList
|
return typeList
|
||||||
}
|
}
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
supportedItemTypeListPublishers
|
.sink(receiveValue: { [weak self] typeList in
|
||||||
.assign(to: \.supportedItemTypeList, on: self)
|
withAnimation {
|
||||||
|
self?.supportedItemTypeList = typeList
|
||||||
|
}
|
||||||
|
})
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
supportedItemTypeListPublishers
|
$supportedItemTypeList
|
||||||
.withLatestFrom(supportedItemTypeListPublishers, $selectedItemType)
|
.receive(on: DispatchQueue.main)
|
||||||
.compactMap { typeList, selectedItemType in
|
.withLatestFrom($selectedItemType)
|
||||||
if typeList.contains(selectedItemType) {
|
.compactMap { selectedItemType in
|
||||||
|
if self.supportedItemTypeList.contains(selectedItemType) {
|
||||||
return selectedItemType
|
return selectedItemType
|
||||||
} else {
|
} else {
|
||||||
return typeList.first
|
return self.supportedItemTypeList.first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.assign(to: \.selectedItemType, on: self)
|
.sink(receiveValue: { [weak self] itemType in
|
||||||
|
withAnimation {
|
||||||
|
self?.selectedItemType = itemType
|
||||||
|
}
|
||||||
|
})
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +95,7 @@ final class LibrarySearchViewModel: ViewModel {
|
||||||
enableTotalRecordCount: false,
|
enableTotalRecordCount: false,
|
||||||
enableImages: false)
|
enableImages: false)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.handleAPIRequestError(completion: completion)
|
self?.handleAPIRequestError(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
|
@ -99,8 +108,10 @@ final class LibrarySearchViewModel: ViewModel {
|
||||||
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, limit: 50, recursive: true, searchTerm: query,
|
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, limit: 50, recursive: true, searchTerm: query,
|
||||||
sortOrder: [.ascending], parentId: parentID,
|
sortOrder: [.ascending], parentId: parentID,
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||||
includeItemTypes: [ItemType.movie.rawValue], sortBy: ["SortName"], enableUserData: true, enableImages: true)
|
includeItemTypes: [ItemType.movie.rawValue], sortBy: ["SortName"], enableUserData: true,
|
||||||
|
enableImages: true)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.handleAPIRequestError(completion: completion)
|
self?.handleAPIRequestError(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
|
@ -110,8 +121,10 @@ final class LibrarySearchViewModel: ViewModel {
|
||||||
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, limit: 50, recursive: true, searchTerm: query,
|
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, limit: 50, recursive: true, searchTerm: query,
|
||||||
sortOrder: [.ascending], parentId: parentID,
|
sortOrder: [.ascending], parentId: parentID,
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||||
includeItemTypes: [ItemType.series.rawValue], sortBy: ["SortName"], enableUserData: true, enableImages: true)
|
includeItemTypes: [ItemType.series.rawValue], sortBy: ["SortName"], enableUserData: true,
|
||||||
|
enableImages: true)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.handleAPIRequestError(completion: completion)
|
self?.handleAPIRequestError(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
|
@ -121,8 +134,10 @@ final class LibrarySearchViewModel: ViewModel {
|
||||||
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, limit: 50, recursive: true, searchTerm: query,
|
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, limit: 50, recursive: true, searchTerm: query,
|
||||||
sortOrder: [.ascending], parentId: parentID,
|
sortOrder: [.ascending], parentId: parentID,
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||||
includeItemTypes: [ItemType.episode.rawValue], sortBy: ["SortName"], enableUserData: true, enableImages: true)
|
includeItemTypes: [ItemType.episode.rawValue], sortBy: ["SortName"], enableUserData: true,
|
||||||
|
enableImages: true)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.handleAPIRequestError(completion: completion)
|
self?.handleAPIRequestError(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
|
|
|
@ -48,14 +48,13 @@ final class LibraryViewModel: ViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(
|
init(parentID: String? = nil,
|
||||||
parentID: String? = nil,
|
|
||||||
person: BaseItemPerson? = nil,
|
person: BaseItemPerson? = nil,
|
||||||
genre: NameGuidPair? = nil,
|
genre: NameGuidPair? = nil,
|
||||||
studio: NameGuidPair? = nil,
|
studio: NameGuidPair? = nil,
|
||||||
filters: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.ascending], withGenres: [], sortBy: [.name]),
|
filters: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.ascending], withGenres: [], sortBy: [.name]),
|
||||||
columns: Int = 7
|
columns: Int = 7)
|
||||||
) {
|
{
|
||||||
self.parentID = parentID
|
self.parentID = parentID
|
||||||
self.person = person
|
self.person = person
|
||||||
self.genre = genre
|
self.genre = genre
|
||||||
|
@ -67,7 +66,6 @@ final class LibraryViewModel: ViewModel {
|
||||||
$filters
|
$filters
|
||||||
.sink(receiveValue: requestItems(with:))
|
.sink(receiveValue: requestItems(with:))
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestItems(with filters: LibraryFilters) {
|
func requestItems(with filters: LibraryFilters) {
|
||||||
|
@ -80,10 +78,13 @@ final class LibraryViewModel: ViewModel {
|
||||||
genreIDs = filters.withGenres.compactMap(\.id)
|
genreIDs = filters.withGenres.compactMap(\.id)
|
||||||
}
|
}
|
||||||
let sortBy = filters.sortBy.map(\.rawValue)
|
let sortBy = filters.sortBy.map(\.rawValue)
|
||||||
let shouldBeRecursive: Bool = filters.filters.contains(.isFavorite) || personIDs != [] || studioIDs != [] || genreIDs != []
|
|
||||||
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, startIndex: currentPage * 100, limit: 100, recursive: shouldBeRecursive,
|
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, startIndex: currentPage * 100, limit: 100,
|
||||||
|
recursive: true,
|
||||||
searchTerm: nil, sortOrder: filters.sortOrder, parentId: parentID,
|
searchTerm: nil, sortOrder: filters.sortOrder, parentId: parentID,
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people], includeItemTypes: filters.filters.contains(.isFavorite) ? ["Movie", "Series", "Season", "Episode"] : ["Movie", "Series"],
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||||
|
includeItemTypes: filters.filters
|
||||||
|
.contains(.isFavorite) ? ["Movie", "Series", "Season", "Episode"] : ["Movie", "Series"],
|
||||||
filters: filters.filters, sortBy: sortBy, tags: filters.tags,
|
filters: filters.filters, sortBy: sortBy, tags: filters.tags,
|
||||||
enableUserData: true, personIds: personIDs, studioIds: studioIDs, genreIds: genreIDs, enableImages: true)
|
enableUserData: true, personIds: personIDs, studioIds: studioIDs, genreIds: genreIDs, enableImages: true)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
|
@ -112,10 +113,13 @@ final class LibraryViewModel: ViewModel {
|
||||||
genreIDs = filters.withGenres.compactMap(\.id)
|
genreIDs = filters.withGenres.compactMap(\.id)
|
||||||
}
|
}
|
||||||
let sortBy = filters.sortBy.map(\.rawValue)
|
let sortBy = filters.sortBy.map(\.rawValue)
|
||||||
let shouldBeRecursive: Bool = filters.filters.contains(.isFavorite) || personIDs != [] || studioIDs != [] || genreIDs != []
|
|
||||||
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, startIndex: currentPage * 100, limit: 100, recursive: shouldBeRecursive,
|
ItemsAPI.getItemsByUserId(userId: SessionManager.main.currentLogin.user.id, startIndex: currentPage * 100, limit: 100,
|
||||||
|
recursive: true,
|
||||||
searchTerm: nil, sortOrder: filters.sortOrder, parentId: parentID,
|
searchTerm: nil, sortOrder: filters.sortOrder, parentId: parentID,
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people], includeItemTypes: filters.filters.contains(.isFavorite) ? ["Movie", "Series", "Season", "Episode"] : ["Movie", "Series"],
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||||
|
includeItemTypes: filters.filters
|
||||||
|
.contains(.isFavorite) ? ["Movie", "Series", "Season", "Episode"] : ["Movie", "Series"],
|
||||||
filters: filters.filters, sortBy: sortBy, tags: filters.tags,
|
filters: filters.filters, sortBy: sortBy, tags: filters.tags,
|
||||||
enableUserData: true, personIds: personIDs, studioIds: studioIDs, genreIds: genreIDs, enableImages: true)
|
enableUserData: true, personIds: personIDs, studioIds: studioIDs, genreIds: genreIDs, enableImages: true)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
|
@ -148,10 +152,10 @@ final class LibraryViewModel: ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func calculateRows(for itemList: [BaseItemDto]) -> [LibraryRow] {
|
private func calculateRows(for itemList: [BaseItemDto]) -> [LibraryRow] {
|
||||||
guard itemList.count > 0 else { return [] }
|
guard !itemList.isEmpty else { return [] }
|
||||||
let rowCount = itemList.count / columns
|
let rowCount = itemList.count / columns
|
||||||
var calculatedRows = [LibraryRow]()
|
var calculatedRows = [LibraryRow]()
|
||||||
for i in (0...rowCount) {
|
for i in 0 ... rowCount {
|
||||||
let firstItemIndex = i * columns
|
let firstItemIndex = i * columns
|
||||||
var lastItemIndex = firstItemIndex + columns
|
var lastItemIndex = firstItemIndex + columns
|
||||||
if lastItemIndex > itemList.count {
|
if lastItemIndex > itemList.count {
|
||||||
|
@ -163,18 +167,14 @@ final class LibraryViewModel: ViewModel {
|
||||||
let newCell = LibraryRowCell(item: item)
|
let newCell = LibraryRowCell(item: item)
|
||||||
rowCells.append(newCell)
|
rowCells.append(newCell)
|
||||||
}
|
}
|
||||||
if i == rowCount && hasNextPage {
|
if i == rowCount, hasNextPage {
|
||||||
var loadingCell = LibraryRowCell(item: nil)
|
var loadingCell = LibraryRowCell(item: nil)
|
||||||
loadingCell.loadingCell = true
|
loadingCell.loadingCell = true
|
||||||
rowCells.append(loadingCell)
|
rowCells.append(loadingCell)
|
||||||
}
|
}
|
||||||
|
|
||||||
calculatedRows.append(
|
calculatedRows.append(LibraryRow(section: i,
|
||||||
LibraryRow(
|
items: rowCells))
|
||||||
section: i,
|
|
||||||
items: rowCells
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return calculatedRows
|
return calculatedRows
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue