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:
PangMo5 2022-01-03 00:27:44 +09:00
parent c75e5d227e
commit 2888099328
2 changed files with 54 additions and 39 deletions

View File

@ -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

View File

@ -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 {
@ -159,22 +163,18 @@ final class LibraryViewModel: ViewModel {
} }
var rowCells = [LibraryRowCell]() var rowCells = [LibraryRowCell]()
for item in itemList[firstItemIndex..<lastItemIndex] { for item in itemList[firstItemIndex ..< lastItemIndex] {
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
} }