Created
June 3, 2020 14:55
-
-
Save SkylerSeamans/647b772a83be036f88946cee318420d5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*: | |
## 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