Skip to content

Instantly share code, notes, and snippets.

@SkylerSeamans
Created June 3, 2020 14:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SkylerSeamans/647b772a83be036f88946cee318420d5 to your computer and use it in GitHub Desktop.
Save SkylerSeamans/647b772a83be036f88946cee318420d5 to your computer and use it in GitHub Desktop.
/*:
## Welcome to `DifferenceKit` Playground
----
> 1. Open DifferenceKit.xcworkspace.
> 2. Build the DifferenceKit.
> 3. Open DifferenceKit playground in project navigator.
> 4. Show the live view in assistant editor.
*/
import DifferenceKit
import PlaygroundSupport
import UIKit
class TestTableViewController: UITableViewController {
public var refreshAction: (() -> Void)?
public var dataInput: [SectionViewModel] {
get { return data }
set {
let changeset = StagedChangeset(source: data, target: newValue)
print(changeset)
tableView.reload(using: changeset, with: .fade) { data in
self.data = data
}
}
}
private var data = [SectionViewModel]()
public init() {
super.init(style: .grouped)
tableView.sectionHeaderHeight = 30
tableView.sectionFooterHeight = 0
tableView.register(UITableViewCell.self, forCellReuseIdentifier: String(describing: UITableViewCell.self))
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(refresh))
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func refresh() {
refreshAction?()
}
public override func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].elements.count
}
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UITableViewCell.self), for: indexPath)
cell.textLabel?.text = data[indexPath.section].elements[indexPath.row].identifier
return cell
}
public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return data[section].title
}
}
enum Status {
case going
case notGoing
}
class SectionViewModel: DifferentiableSection {
let title: String
let status: Status
var elements: [CellViewModel]
var differenceIdentifier: String {
get {
SectionViewModel.string(for: status)
}
}
/// Used for DifferentiableSection
public required convenience init<C: Swift.Collection>(source: SectionViewModel, elements: C) where C.Element == CellViewModel {
self.init(status: source.status, elements: source.elements)
}
init(status: Status, elements: [CellViewModel]) {
self.status = status
self.title = SectionViewModel.title(status: status, count: elements.count)
self.elements = elements
}
private static func title(status: Status, count: Int) -> String {
String(format: "%@ (%@)", string(for: status), String(count))
}
private static func string(for status: Status) -> String {
switch status {
case .going:
return NSLocalizedString("Going", comment: "Going")
case .notGoing:
return NSLocalizedString("Not Going", comment: "Not Going")
}
}
func isContentEqual(to source: SectionViewModel) -> Bool {
guard type(of: source) == type(of: self) else {
return false
}
if source.status != status {
return false
}
if source.title != title {
return false
}
return true
}
}
class CellViewModel {
let identifier: String
let status: Status
init(identifier: String, status: Status) {
self.identifier = identifier
self.status = status
}
}
extension CellViewModel: Differentiable {
func isContentEqual(to other: CellViewModel) -> Bool {
if status != other.status {
return false
}
return true
}
var differenceIdentifier: String {
identifier
}
}
let viewController = TestTableViewController()
let navigationController = UINavigationController(rootViewController: viewController)
navigationController.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = navigationController.view
let source = [
SectionViewModel(status: .going, elements: [CellViewModel(identifier: "A", status: .going),
CellViewModel(identifier: "B", status: .going)]),
SectionViewModel(status: .notGoing, elements: [CellViewModel(identifier: "C", status: .notGoing),
CellViewModel(identifier: "D", status: .notGoing)])
]
let target = [
SectionViewModel(status: .going, elements: [CellViewModel(identifier: "B", status: .going)]),
SectionViewModel(status: .notGoing, elements: [CellViewModel(identifier: "A", status: .going),
CellViewModel(identifier: "C", status: .notGoing),
CellViewModel(identifier: "D", status: .notGoing)])
]
viewController.dataInput = source
var isSourceShown = true
viewController.refreshAction = {
viewController.dataInput = isSourceShown ? target : source
isSourceShown = !isSourceShown
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment