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

[Fix] Make section and cell view models diffable by default #119

Merged
merged 2 commits into from
Jul 9, 2018
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
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ The changelog for `ReactiveLists`. Also see the [releases](https://github.com/pl

------

0.1.2
-----

### Changed

- Section and cell view models are now diffable by default. ([#119](https://github.com/plangrid/ReactiveLists/pull/119), [@jessesquires](https://github.com/jessesquires))
Each provide default values for `diffingKey`, but you can customize them for your own needs or opt-out of automatic diffing.
- `CollectionSectionViewModel` protocol now inherits from `DiffableViewModel` protocol
- `CollectionCellViewModel` protocol now inherits from `DiffableViewModel` protocol
- ` TableSectionViewModel` protocol now inherits from `DiffableViewModel` protocol
- `TableCellViewModel` protocol now inherits from `DiffableViewModel` protocol

0.1.1
-----

Expand All @@ -22,7 +34,7 @@ This release closes the [0.1.1 milestone](https://github.com/plangrid/ReactiveLi

### New

- You can now customize the cell insertion and deletion animations on `TableViewDriver`. (#115, @wickwirew)
- You can now customize the cell insertion and deletion animations on `TableViewDriver`. ([#115](https://github.com/plangrid/ReactiveLists/pull/115), [@wickwirew](https://github.com/wickwirew))
- `ViewRegistrationInfo` properties `reuseIdentifier` and `registrationMethod` are now public
- `ViewRegistrationInfo` now conforms to `Equatable`
- `SupplementaryViewInfo` now conforms to `Equatable`
Expand Down
43 changes: 12 additions & 31 deletions Sources/CollectionViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Dwifft
import UIKit

/// View model for the individual cells of a `UICollectionView`.
public protocol CollectionCellViewModel: ReusableCellViewModelProtocol {
public protocol CollectionCellViewModel: ReusableCellViewModelProtocol, DiffableViewModel {

/// `CollectionViewDriver` will automatically apply an `accessibilityIdentifier` to the cell based on this format
var accessibilityFormat: CellAccessibilityFormat { get }
Expand Down Expand Up @@ -110,27 +110,15 @@ public struct CollectionViewModel {
var diffingKeys: SectionedValues<DiffingKey, DiffingKey> {
return SectionedValues(
self.sectionModels.map { section in
// Ensure we have a diffing key for the current section
guard let sectionDiffingKey = section.diffingKey else {
fatalError("When diffing is enabled you need to provide a non-nil diffingKey for each section.")
}

// Ensure we have a diffing key for each cell in this section
let cellDiffingKeys: [DiffingKey] = section.cellViewModels.map { cell in
guard let cell = cell as? DiffableViewModel else {
fatalError("When diffing is enabled you need to provide cells which are DiffableViews.")
}
return "\(type(of: cell))_\(cell.diffingKey)"
}

return (sectionDiffingKey, cellDiffingKeys)
let cellDiffingKeys = section.cellViewModels.map { $0.diffingKey }
return (section.diffingKey, cellDiffingKeys)
}
)
}
}

/// View model for a collection view section.
public struct CollectionSectionViewModel {
public struct CollectionSectionViewModel: DiffableViewModel {

/// Cells to be shown in this section.
let cellViewModels: [CollectionCellViewModel]
Expand All @@ -148,7 +136,7 @@ public struct CollectionSectionViewModel {
/// For example:
///
/// public var diffingKey = { group.identifier }
public var diffingKey: String?
public var diffingKey: String

/// Initializes a collection view section view model.
///
Expand All @@ -161,8 +149,7 @@ public struct CollectionSectionViewModel {
cellViewModels: [CollectionCellViewModel],
headerViewModel: CollectionSupplementaryViewModel? = nil,
footerViewModel: CollectionSupplementaryViewModel? = nil,
diffingKey: String? = nil
) {
diffingKey: String = UUID().uuidString) {
self.cellViewModels = cellViewModels
self.headerViewModel = headerViewModel
self.footerViewModel = footerViewModel
Expand Down Expand Up @@ -190,43 +177,37 @@ extension CollectionSectionViewModel {
cellViewModels: [CollectionCellViewModel],
headerHeight: CGFloat? = nil,
footerViewModel: CollectionSupplementaryViewModel? = nil,
diffingKey: String? = nil
) {
diffingKey: String = UUID().uuidString) {
self.init(
cellViewModels: cellViewModels,
headerViewModel: BlankSupplementaryViewModel(height: headerHeight),
footerViewModel: footerViewModel,
diffingKey: diffingKey
)
diffingKey: diffingKey)
}

/// :nodoc:
public init(
cellViewModels: [CollectionCellViewModel],
headerViewModel: CollectionSupplementaryViewModel? = nil,
footerHeight: CGFloat? = nil,
diffingKey: String? = nil
) {
diffingKey: String = UUID().uuidString) {
self.init(
cellViewModels: cellViewModels,
headerViewModel: headerViewModel,
footerViewModel: BlankSupplementaryViewModel(height: footerHeight),
diffingKey: diffingKey
)
diffingKey: diffingKey)
}

/// :nodoc:
public init(
cellViewModels: [CollectionCellViewModel],
headerHeight: CGFloat? = nil,
footerHeight: CGFloat? = nil,
diffingKey: String? = nil
) {
diffingKey: String = UUID().uuidString) {
self.init(
cellViewModels: cellViewModels,
headerViewModel: BlankSupplementaryViewModel(height: headerHeight),
footerViewModel: BlankSupplementaryViewModel(height: footerHeight),
diffingKey: diffingKey
)
diffingKey: diffingKey)
}
}
52 changes: 18 additions & 34 deletions Sources/TableViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Dwifft
import UIKit

/// View model for the individual cells of a `TableViewModel`.
public protocol TableCellViewModel: ReusableCellViewModelProtocol {
public protocol TableCellViewModel: ReusableCellViewModelProtocol, DiffableViewModel {

/// `TableViewDriver` will automatically apply an `accessibilityIdentifier` to the cell based on this format.
var accessibilityFormat: CellAccessibilityFormat { get }
Expand Down Expand Up @@ -114,7 +114,7 @@ public protocol TableSectionHeaderFooterViewModel: ReusableSupplementaryViewMode
}

/// View model for a table view section.
public struct TableSectionViewModel {
public struct TableSectionViewModel: DiffableViewModel {

/// Cells to be shown in this section.
public let cellViewModels: [TableCellViewModel]
Expand All @@ -136,7 +136,7 @@ public struct TableSectionViewModel {
/// For example:
///
/// public var diffingKey = { group.identifier }
public var diffingKey: String?
public var diffingKey: String

/// Returns `true` is the section is empty, `false` otherwise.
public var isEmpty: Bool {
Expand All @@ -146,18 +146,17 @@ public struct TableSectionViewModel {
/// Initializes a `TableSectionViewModel`.
///
/// - Parameters:
/// - cellViewModels: the cell view models contained in this section.
/// - headerViewModel: a header view model for this section (defaults to `nil`).
/// - footerViewModel: a footer view model for this section (defaults to `nil`).
/// - collapsed: whether or not this section is collapsed (defaults to `false`).
/// - diffingKey: the diffing key, or `nil`. Required for automated diffing.
/// - cellViewModels: The cell view models contained in this section.
/// - headerViewModel: A header view model for this section (defaults to `nil`).
/// - footerViewModel: A footer view model for this section (defaults to `nil`).
/// - collapsed: Whether or not this section is collapsed (defaults to `false`).
/// - diffingKey: A diffing key.
public init(
cellViewModels: [TableCellViewModel],
headerViewModel: TableSectionHeaderFooterViewModel? = nil,
footerViewModel: TableSectionHeaderFooterViewModel? = nil,
collapsed: Bool = false,
diffingKey: String? = nil
) {
diffingKey: String = UUID().uuidString) {
self.cellViewModels = cellViewModels
self.headerViewModel = headerViewModel
self.footerViewModel = footerViewModel
Expand All @@ -168,22 +167,19 @@ public struct TableSectionViewModel {
/// Initializes a `TableSectionViewModel`.
///
/// - Parameters:
/// - headerTitle: title for the header, or `nil`. Setting a title will cause a default header
/// to be added to this section.
/// - headerHeight: the height of the default header, if one exists.
/// - cellViewModels: the cell view models contained in this section.
/// - footerTitle: title for the footer, or `nil`. Setting a title will cause a default footer
/// to be added to this section.
/// - footerHeight: the height of the default footer, if one exists.
/// - diffingKey: the diffing key, or `nil`. Required for automated diffing.
/// - headerTitle: The title for the header, or `nil`. Setting a title will cause a default header to be added to this section.
/// - headerHeight: The height of the default header, if one exists.
/// - cellViewModels: The cell view models contained in this section.
/// - footerTitle: The title for the footer, or `nil`. Setting a title will cause a default footeer to be added to this section.
/// - footerHeight: The height of the default footer, if one exists.
/// - diffingKey: A diffing key.
public init(
headerTitle: String?,
headerHeight: CGFloat?,
cellViewModels: [TableCellViewModel],
footerTitle: String? = nil,
footerHeight: CGFloat? = 0,
diffingKey: String? = nil
) {
diffingKey: String = UUID().uuidString) {
self.cellViewModels = cellViewModels
self.headerViewModel = PlainHeaderFooterViewModel(title: headerTitle, height: headerHeight)
self.footerViewModel = PlainHeaderFooterViewModel(title: footerTitle, height: footerHeight)
Expand Down Expand Up @@ -251,20 +247,8 @@ public struct TableViewModel {
var diffingKeys: SectionedValues<DiffingKey, DiffingKey> {
return SectionedValues(
self.sectionModels.map { section in
// Ensure we have a diffing key for the current section
guard let sectionDiffingKey = section.diffingKey else {
fatalError("When diffing is enabled you need to provide a non-nil diffingKey for each section.")
}

// Ensure we have a diffing key for each cell in this section
let cellDiffingKeys: [DiffingKey] = section.cellViewModels.map { cell in
guard let cell = cell as? DiffableViewModel else {
fatalError("When diffing is enabled you need to provide cells which are DiffableViews.")
}
return "\(type(of: cell))_\(cell.diffingKey)"
}

return (sectionDiffingKey, cellDiffingKeys)
let cellDiffingKeys = section.cellViewModels.map { $0.diffingKey }
return (section.diffingKey, cellDiffingKeys)
}
)
}
Expand Down