Simplify CellProvider protocol (#65)
In most of the cases users wouldn't need to create cell providers with more than one identifier or more than one section. We would like the most common cases to be as easy to use as possible, this PR renames `SimpleCellProvider` to `CellProvider` and old `CellProvider` to `IdentifiedCellProvider`. Old `Model` associated type is now renamed to `Section` with a default array-based sections type, while the new `Model` associated type allows setting the element type directly. This helps users avoid thinking about nested arrays in the cases where multiple `ListView` sections are not needed. * Simplify CellProvider protocol * Fix AppKitRenderer compilation issue * Fix formatting
This commit is contained in:
parent
fe43b9b9b0
commit
ec695e36b5
|
@ -617,7 +617,7 @@
|
|||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = TokamakDemoMac/TokamakDemoMac.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = "TokamakDemo-macOS/TokamakDemoMac.entitlements";
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
|
@ -650,7 +650,7 @@
|
|||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = TokamakDemoMac/TokamakDemoMac.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = "TokamakDemo-macOS/TokamakDemoMac.entitlements";
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
|
|
|
@ -33,7 +33,7 @@ extension ElementaryParticles: CustomStringConvertible {
|
|||
var description: String { return rawValue.localizedCapitalized }
|
||||
}
|
||||
|
||||
private struct Cells: SimpleCellProvider {
|
||||
private struct Cells: CellProvider {
|
||||
static func cell(
|
||||
props: Null,
|
||||
item: ElementaryParticles,
|
||||
|
@ -52,7 +52,7 @@ private struct Cells: SimpleCellProvider {
|
|||
|
||||
typealias Props = Null
|
||||
|
||||
typealias Model = [[ElementaryParticles]]
|
||||
typealias Model = ElementaryParticles
|
||||
}
|
||||
|
||||
struct CollectionExample: PureLeafComponent {
|
||||
|
@ -64,7 +64,7 @@ struct CollectionExample: PureLeafComponent {
|
|||
Edges.equal(to: .parent, inset: 20),
|
||||
backgroundColor: .white
|
||||
),
|
||||
model: [ElementaryParticles.allCases]
|
||||
singleSection: ElementaryParticles.allCases
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import Tokamak
|
||||
|
||||
private struct Cells: SimpleCellProvider {
|
||||
private struct Cells: CellProvider {
|
||||
static func cell(
|
||||
props: Null,
|
||||
item: AppRoute,
|
||||
|
@ -27,7 +27,7 @@ private struct Cells: SimpleCellProvider {
|
|||
|
||||
typealias Props = Null
|
||||
|
||||
typealias Model = [[AppRoute]]
|
||||
typealias Model = AppRoute
|
||||
}
|
||||
|
||||
struct List: PureLeafComponent {
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
import Tokamak
|
||||
|
||||
struct ListProvider: SimpleCellProvider {
|
||||
struct ListProvider: CellProvider {
|
||||
typealias Props = Null
|
||||
typealias Model = [[Int]]
|
||||
typealias Model = Int
|
||||
|
||||
static func cell(props _: Null, item: Int, path _: CellPath) -> AnyNode {
|
||||
return Label.node(.init(
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
public struct CollectionView<T: CellProvider>: HostComponent {
|
||||
public struct Props: Equatable, StyleProps {
|
||||
public let cellProps: T.Props
|
||||
public let model: T.Model
|
||||
public let sections: T.Sections
|
||||
public let onSelect: Handler<CellPath>?
|
||||
public let style: Style?
|
||||
|
||||
|
@ -16,10 +16,10 @@ public struct CollectionView<T: CellProvider>: HostComponent {
|
|||
_ style: Style? = nil,
|
||||
cellProps: T.Props,
|
||||
onSelect: Handler<CellPath>? = nil,
|
||||
singleSection: T.Model.Element
|
||||
singleSection: T.Sections.Element
|
||||
) {
|
||||
self.cellProps = cellProps
|
||||
model = T.Model.single(section: singleSection)
|
||||
sections = T.Sections.single(section: singleSection)
|
||||
self.onSelect = onSelect
|
||||
self.style = style
|
||||
}
|
||||
|
@ -27,11 +27,11 @@ public struct CollectionView<T: CellProvider>: HostComponent {
|
|||
public init(
|
||||
_ style: Style? = nil,
|
||||
cellProps: T.Props,
|
||||
model: T.Model,
|
||||
sections: T.Sections,
|
||||
onSelect: Handler<CellPath>? = nil
|
||||
) {
|
||||
self.cellProps = cellProps
|
||||
self.model = model
|
||||
self.sections = sections
|
||||
self.onSelect = onSelect
|
||||
self.style = style
|
||||
}
|
||||
|
@ -43,11 +43,11 @@ public struct CollectionView<T: CellProvider>: HostComponent {
|
|||
extension CollectionView.Props where T.Props == Null {
|
||||
public init(
|
||||
_ style: Style? = nil,
|
||||
model: T.Model,
|
||||
sections: T.Sections,
|
||||
onSelect: Handler<CellPath>? = nil
|
||||
) {
|
||||
cellProps = Null()
|
||||
self.model = model
|
||||
self.sections = sections
|
||||
self.onSelect = onSelect
|
||||
self.style = style
|
||||
}
|
||||
|
@ -55,10 +55,10 @@ extension CollectionView.Props where T.Props == Null {
|
|||
public init(
|
||||
_ style: Style? = nil,
|
||||
onSelect: Handler<CellPath>? = nil,
|
||||
singleSection: T.Model.Element
|
||||
singleSection: T.Sections.Element
|
||||
) {
|
||||
cellProps = Null()
|
||||
model = T.Model.single(section: singleSection)
|
||||
sections = T.Sections.single(section: singleSection)
|
||||
self.onSelect = onSelect
|
||||
self.style = style
|
||||
}
|
||||
|
|
|
@ -33,15 +33,17 @@ extension Array: SectionedModel
|
|||
}
|
||||
}
|
||||
|
||||
public protocol CellProvider {
|
||||
public protocol IdentifiedCellProvider {
|
||||
associatedtype Props: Equatable
|
||||
associatedtype Identifier: RawRepresentable, CaseIterable
|
||||
where Identifier.RawValue == String
|
||||
associatedtype Model: SectionedModel & Equatable
|
||||
associatedtype Model: Equatable
|
||||
associatedtype Sections: SectionedModel & Equatable = [[Model]] where
|
||||
Sections.Element.Element == Model
|
||||
|
||||
static func cell(
|
||||
props: Props,
|
||||
item: Model.Element.Element,
|
||||
item: Model,
|
||||
path: CellPath
|
||||
) -> (Identifier, AnyNode)
|
||||
}
|
||||
|
@ -50,19 +52,19 @@ public enum SingleIdentifier: String, CaseIterable {
|
|||
case single
|
||||
}
|
||||
|
||||
public protocol SimpleCellProvider: CellProvider
|
||||
public protocol CellProvider: IdentifiedCellProvider
|
||||
where Identifier == SingleIdentifier {
|
||||
static func cell(
|
||||
props: Props,
|
||||
item: Model.Element.Element,
|
||||
item: Model,
|
||||
path: CellPath
|
||||
) -> AnyNode
|
||||
}
|
||||
|
||||
extension SimpleCellProvider {
|
||||
extension CellProvider {
|
||||
public static func cell(
|
||||
props: Props,
|
||||
item: Model.Element.Element,
|
||||
item: Model,
|
||||
path: CellPath
|
||||
) -> (Identifier, AnyNode) {
|
||||
return (.single, cell(props: props, item: item, path: path))
|
||||
|
@ -72,7 +74,7 @@ extension SimpleCellProvider {
|
|||
public struct ListView<T: CellProvider>: HostComponent {
|
||||
public struct Props: Equatable, StyleProps {
|
||||
public let cellProps: T.Props
|
||||
public let model: T.Model
|
||||
public let model: T.Sections
|
||||
public let onSelect: Handler<CellPath>?
|
||||
public let style: Style?
|
||||
|
||||
|
@ -80,10 +82,10 @@ public struct ListView<T: CellProvider>: HostComponent {
|
|||
_ style: Style? = nil,
|
||||
cellProps: T.Props,
|
||||
onSelect: Handler<CellPath>? = nil,
|
||||
singleSection: T.Model.Element
|
||||
singleSection: T.Sections.Element
|
||||
) {
|
||||
self.cellProps = cellProps
|
||||
model = T.Model.single(section: singleSection)
|
||||
model = T.Sections.single(section: singleSection)
|
||||
self.onSelect = onSelect
|
||||
self.style = style
|
||||
}
|
||||
|
@ -91,7 +93,7 @@ public struct ListView<T: CellProvider>: HostComponent {
|
|||
public init(
|
||||
_ style: Style? = nil,
|
||||
cellProps: T.Props,
|
||||
model: T.Model,
|
||||
model: T.Sections,
|
||||
onSelect: Handler<CellPath>? = nil
|
||||
) {
|
||||
self.cellProps = cellProps
|
||||
|
@ -107,7 +109,7 @@ public struct ListView<T: CellProvider>: HostComponent {
|
|||
extension ListView.Props where T.Props == Null {
|
||||
public init(
|
||||
_ style: Style? = nil,
|
||||
model: T.Model,
|
||||
model: T.Sections,
|
||||
onSelect: Handler<CellPath>? = nil
|
||||
) {
|
||||
cellProps = Null()
|
||||
|
@ -119,10 +121,10 @@ extension ListView.Props where T.Props == Null {
|
|||
public init(
|
||||
_ style: Style? = nil,
|
||||
onSelect: Handler<CellPath>? = nil,
|
||||
singleSection: T.Model.Element
|
||||
singleSection: T.Sections.Element
|
||||
) {
|
||||
cellProps = Null()
|
||||
model = T.Model.single(section: singleSection)
|
||||
model = T.Sections.single(section: singleSection)
|
||||
self.onSelect = onSelect
|
||||
self.style = style
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import Tokamak
|
|||
// let _collectionViewWitnessTableHack: NSHostComponent.Type =
|
||||
// CollectionView<HackyProvider>.self
|
||||
|
||||
struct HackyProvider: SimpleCellProvider {
|
||||
struct HackyProvider: CellProvider {
|
||||
static func cell(
|
||||
props: Props, item: Int, path: CellPath
|
||||
) -> AnyNode {
|
||||
|
@ -29,7 +29,7 @@ struct HackyProvider: SimpleCellProvider {
|
|||
}
|
||||
|
||||
typealias Props = Null
|
||||
typealias Model = [[Int]]
|
||||
typealias Model = Int
|
||||
}
|
||||
|
||||
class NSTarget: Target {
|
||||
|
|
|
@ -32,21 +32,21 @@ private final class DataSource<T: CellProvider>: NSObject,
|
|||
}
|
||||
|
||||
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
return props.model.count
|
||||
return props.sections.count
|
||||
}
|
||||
|
||||
func collectionView(
|
||||
_ collectionView: UICollectionView,
|
||||
numberOfItemsInSection section: Int
|
||||
) -> Int {
|
||||
return props.model[section].count
|
||||
return props.sections[section].count
|
||||
}
|
||||
|
||||
func collectionView(
|
||||
_ collectionView: UICollectionView,
|
||||
cellForItemAt indexPath: IndexPath
|
||||
) -> UICollectionViewCell {
|
||||
let item = props.model[indexPath.section][indexPath.row]
|
||||
let item = props.sections[indexPath.section][indexPath.row]
|
||||
|
||||
let (id, node) = T.cell(
|
||||
props: props.cellProps,
|
||||
|
@ -116,10 +116,10 @@ final class CollectionViewBox<T: CellProvider>: ViewBox<TokamakCollectionView> {
|
|||
return dataSource.props
|
||||
}
|
||||
set {
|
||||
let oldModel = dataSource.props.model
|
||||
let oldSections = dataSource.props.sections
|
||||
dataSource.props = newValue
|
||||
delegate.onSelect = newValue.onSelect?.value
|
||||
if oldModel != newValue.model {
|
||||
if oldSections != newValue.sections {
|
||||
view.reloadData()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ let _listViewWitnessTableHack: UIHostComponent.Type =
|
|||
let _collectionViewWitnessTableHack: UIHostComponent.Type =
|
||||
CollectionView<HackyProvider>.self
|
||||
|
||||
struct HackyProvider: SimpleCellProvider {
|
||||
struct HackyProvider: CellProvider {
|
||||
static func cell(
|
||||
props: Props, item: Int, path: CellPath
|
||||
) -> AnyNode {
|
||||
|
@ -27,7 +27,7 @@ struct HackyProvider: SimpleCellProvider {
|
|||
}
|
||||
|
||||
typealias Props = Null
|
||||
typealias Model = [[Int]]
|
||||
typealias Model = Int
|
||||
}
|
||||
|
||||
class UITarget: Target {
|
||||
|
|
Loading…
Reference in New Issue