Fix optional ID case for libraries (#1352)
This commit is contained in:
parent
174487a220
commit
bbfa944b52
|
@ -27,6 +27,13 @@ extension BaseItemDto: LibraryParent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension BaseItemDto: LibraryIdentifiable {
|
||||||
|
|
||||||
|
var unwrappedIDHashOrZero: Int {
|
||||||
|
id?.hashValue ?? 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension BaseItemDto {
|
extension BaseItemDto {
|
||||||
|
|
||||||
var episodeLocator: String? {
|
var episodeLocator: String? {
|
||||||
|
|
|
@ -13,6 +13,10 @@ import UIKit
|
||||||
|
|
||||||
extension BaseItemPerson: Poster {
|
extension BaseItemPerson: Poster {
|
||||||
|
|
||||||
|
var unwrappedIDHashOrZero: Int {
|
||||||
|
id?.hashValue ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
var subtitle: String? {
|
var subtitle: String? {
|
||||||
firstRole
|
firstRole
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,10 @@ extension ChapterInfo {
|
||||||
chapterInfo.displayTitle
|
chapterInfo.displayTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var unwrappedIDHashOrZero: Int {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
let systemImage: String = "film"
|
let systemImage: String = "film"
|
||||||
var subtitle: String?
|
var subtitle: String?
|
||||||
var showTitle: Bool = true
|
var showTitle: Bool = true
|
||||||
|
|
|
@ -42,6 +42,10 @@ struct ChannelProgram: Hashable, Identifiable {
|
||||||
|
|
||||||
extension ChannelProgram: Poster {
|
extension ChannelProgram: Poster {
|
||||||
|
|
||||||
|
var unwrappedIDHashOrZero: Int {
|
||||||
|
channel.id?.hashValue ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
var displayTitle: String {
|
var displayTitle: String {
|
||||||
channel.displayTitle
|
channel.displayTitle
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// A type that is displayed as a poster
|
/// A type that is displayed as a poster
|
||||||
protocol Poster: Displayable, Hashable, Identifiable, SystemImageable {
|
protocol Poster: Displayable, Hashable, LibraryIdentifiable, SystemImageable {
|
||||||
|
|
||||||
/// Optional subtitle when used as a poster
|
/// Optional subtitle when used as a poster
|
||||||
var subtitle: String? { get }
|
var subtitle: String? { get }
|
||||||
|
|
|
@ -18,6 +18,30 @@ import UIKit
|
||||||
/// Magic number for page sizes
|
/// Magic number for page sizes
|
||||||
private let DefaultPageSize = 50
|
private let DefaultPageSize = 50
|
||||||
|
|
||||||
|
/// A protocol for items to conform to if they may be present within a library.
|
||||||
|
///
|
||||||
|
/// Similar to `Identifiable`, but `unwrappedIDHashOrZero` is an `Int`: the hash of the underlying `id`
|
||||||
|
/// value if it is not optional, or if it is optional it must return the hash of the wrapped value,
|
||||||
|
/// or 0 otherwise:
|
||||||
|
///
|
||||||
|
/// struct Item: LibraryIdentifiable {
|
||||||
|
/// var id: String? { "id" }
|
||||||
|
///
|
||||||
|
/// var unwrappedIDHashOrZero: Int {
|
||||||
|
/// // Gets the `hashValue` of the `String.hashValue`, not `Optional.hashValue`.
|
||||||
|
/// id?.hashValue ?? 0
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// This is necessary because if the `ID` is optional, then `Optional.hashValue` will be used instead
|
||||||
|
/// and result in differing hashes.
|
||||||
|
///
|
||||||
|
/// This also helps if items already conform to `Identifiable`, but has an optionally-typed `id`.
|
||||||
|
protocol LibraryIdentifiable: Identifiable {
|
||||||
|
|
||||||
|
var unwrappedIDHashOrZero: Int { get }
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: fix how `hasNextPage` is determined
|
// TODO: fix how `hasNextPage` is determined
|
||||||
// - some subclasses might not have "paging" and only have one call. This can be solved with
|
// - some subclasses might not have "paging" and only have one call. This can be solved with
|
||||||
// a check if elements were actually appended to the set but that requires a redundant get
|
// a check if elements were actually appended to the set but that requires a redundant get
|
||||||
|
@ -33,7 +57,7 @@ private let DefaultPageSize = 50
|
||||||
on remembering other filters.
|
on remembering other filters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PagingLibraryViewModel<Element: Poster & Identifiable>: ViewModel, Eventful, Stateful {
|
class PagingLibraryViewModel<Element: Poster & LibraryIdentifiable>: ViewModel, Eventful, Stateful {
|
||||||
|
|
||||||
// MARK: Event
|
// MARK: Event
|
||||||
|
|
||||||
|
@ -105,11 +129,21 @@ class PagingLibraryViewModel<Element: Poster & Identifiable>: ViewModel, Eventfu
|
||||||
parent: (any LibraryParent)? = nil
|
parent: (any LibraryParent)? = nil
|
||||||
) {
|
) {
|
||||||
self.filterViewModel = nil
|
self.filterViewModel = nil
|
||||||
self.elements = IdentifiedArray(uniqueElements: data, id: \.id.hashValue)
|
self.elements = IdentifiedArray(uniqueElements: data, id: \.unwrappedIDHashOrZero)
|
||||||
self.isStatic = true
|
self.isStatic = true
|
||||||
self.hasNextPage = false
|
self.hasNextPage = false
|
||||||
self.pageSize = DefaultPageSize
|
self.pageSize = DefaultPageSize
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
Notifications[.didDeleteItem]
|
||||||
|
.publisher
|
||||||
|
.receive(on: RunLoop.main)
|
||||||
|
.sink { id in
|
||||||
|
self.elements.remove(id: id.hashValue)
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(
|
convenience init(
|
||||||
|
@ -132,7 +166,7 @@ class PagingLibraryViewModel<Element: Poster & Identifiable>: ViewModel, Eventfu
|
||||||
filters: ItemFilterCollection? = nil,
|
filters: ItemFilterCollection? = nil,
|
||||||
pageSize: Int = DefaultPageSize
|
pageSize: Int = DefaultPageSize
|
||||||
) {
|
) {
|
||||||
self.elements = IdentifiedArray(id: \.id.hashValue)
|
self.elements = IdentifiedArray(id: \.unwrappedIDHashOrZero)
|
||||||
self.isStatic = false
|
self.isStatic = false
|
||||||
self.pageSize = pageSize
|
self.pageSize = pageSize
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
|
@ -36,7 +36,7 @@ import SwiftUI
|
||||||
should be applied.
|
should be applied.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct PagingLibraryView<Element: Poster & Identifiable>: View {
|
struct PagingLibraryView<Element: Poster>: View {
|
||||||
|
|
||||||
@Default(.Customization.Library.enabledDrawerFilters)
|
@Default(.Customization.Library.enabledDrawerFilters)
|
||||||
private var enabledDrawerFilters
|
private var enabledDrawerFilters
|
||||||
|
@ -240,6 +240,7 @@ struct PagingLibraryView<Element: Poster & Identifiable>: View {
|
||||||
private var gridView: some View {
|
private var gridView: some View {
|
||||||
CollectionVGrid(
|
CollectionVGrid(
|
||||||
uniqueElements: viewModel.elements,
|
uniqueElements: viewModel.elements,
|
||||||
|
id: \.unwrappedIDHashOrZero,
|
||||||
layout: layout
|
layout: layout
|
||||||
) { item in
|
) { item in
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue