forked from ra1028/DifferenceKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
854 additions
and
507 deletions.
There are no files selected for viewing
140 changes: 122 additions & 18 deletions
140
Examples/Example-iOS/Example-iOS.xcodeproj/project.pbxproj
Large diffs are not rendered by default.
Oops, something went wrong.
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import UIKit | ||
|
||
protocol NibLoadable: class { | ||
static var nibName: String { get } | ||
static var nibBundle: Bundle? { get } | ||
} | ||
|
||
extension NibLoadable { | ||
static var nib: UINib { | ||
return UINib(nibName: nibName, bundle: nibBundle) | ||
} | ||
|
||
static var nibName: String { | ||
return String(describing: self) | ||
} | ||
|
||
static var nibBundle: Bundle? { | ||
return Bundle(for: self) | ||
} | ||
} | ||
|
||
extension NibLoadable where Self: UIView { | ||
static func loadFromNib() -> Self { | ||
return nib.instantiate(withOwner: nil, options: nil).first as! Self | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
protocol Reusable: class { | ||
static var reuseIdentifier: String { get } | ||
} | ||
|
||
extension Reusable { | ||
static var reuseIdentifier: String { | ||
return String(reflecting: self) | ||
} | ||
} | ||
|
||
typealias NibReusable = NibLoadable & Reusable |
65 changes: 65 additions & 0 deletions
65
Examples/Example-iOS/Sources/Common/ReusableViewExtensions.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import UIKit | ||
|
||
extension UITableView { | ||
func register<T: UITableViewCell>(cellType: T.Type) where T: NibReusable { | ||
register(T.nib, forCellReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func register<T: UITableViewCell>(cellType: T.Type) where T: Reusable { | ||
register(T.self, forCellReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func register<T: UITableViewHeaderFooterView>(viewType: T.Type) where T: NibReusable { | ||
register(T.nib, forHeaderFooterViewReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func register<T: UITableViewHeaderFooterView>(viewType: T.Type) where T: Reusable { | ||
register(T.self, forHeaderFooterViewReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func dequeueReusableCell<T: UITableViewCell>(for indexPath: IndexPath, cellType: T.Type = T.self) -> T where T: Reusable { | ||
guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { | ||
fatalError() | ||
} | ||
return cell | ||
} | ||
|
||
func dequeueReusableHeaderFooterView<T: UITableViewHeaderFooterView>(viewType: T.Type = T.self) -> T where T: Reusable { | ||
guard let view = dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T else { | ||
fatalError() | ||
} | ||
return view | ||
} | ||
} | ||
|
||
extension UICollectionView { | ||
func register<T: UICollectionViewCell>(cellType: T.Type) where T: NibReusable { | ||
register(T.nib, forCellWithReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func register<T: UICollectionViewCell>(cellType: T.Type) where T: Reusable { | ||
register(T.self, forCellWithReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func register<T: UICollectionReusableView>(viewType: T.Type, forSupplementaryViewOfKind kind: String) where T: NibReusable { | ||
register(T.nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func register<T: UICollectionReusableView>(viewType: T.Type, forSupplementaryViewOfKind kind: String) where T: Reusable { | ||
register(T.self, forSupplementaryViewOfKind: kind, withReuseIdentifier: T.reuseIdentifier) | ||
} | ||
|
||
func dequeueReusableCell<T: UICollectionViewCell>(for indexPath: IndexPath, cellType: T.Type = T.self) -> T where T: Reusable { | ||
guard let cell = dequeueReusableCell(withReuseIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { | ||
fatalError() | ||
} | ||
return cell | ||
} | ||
|
||
func dequeueReusableSupplementaryView<T: UICollectionReusableView>(ofKind kind: String, for indexPath: IndexPath, viewType: T.Type = T.self) -> T where T: Reusable { | ||
guard let view = dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: T.reuseIdentifier, for: indexPath) as? T else { | ||
fatalError() | ||
} | ||
return view | ||
} | ||
} |
1 change: 0 additions & 1 deletion
1
...e-iOS/Sources/String+Differentiable.swift → ...iOS/Sources/Common/StringExtensions.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
import UIKit | ||
import DifferenceKit | ||
|
||
extension String: Differentiable {} |
3 changes: 3 additions & 0 deletions
3
Examples/Example-iOS/Sources/HeaderFooter/HeaderFooterCell.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import UIKit | ||
|
||
final class HeaderFooterPlainCell: UITableViewCell, Reusable {} |
9 changes: 9 additions & 0 deletions
9
Examples/Example-iOS/Sources/HeaderFooter/HeaderFooterMoreView.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import UIKit | ||
|
||
final class HeaderFooterMoreView: UITableViewHeaderFooterView, NibReusable { | ||
var onMorePressed: (() -> Void)? | ||
|
||
@IBAction func handleMorePressed() { | ||
onMorePressed?() | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
Examples/Example-iOS/Sources/HeaderFooter/HeaderFooterMoreView.xib
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | ||
<device id="retina6_1" orientation="portrait"> | ||
<adaptation id="fullscreen"/> | ||
</device> | ||
<dependencies> | ||
<deployment identifier="iOS"/> | ||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/> | ||
<capability name="Safe area layout guides" minToolsVersion="9.0"/> | ||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | ||
</dependencies> | ||
<objects> | ||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> | ||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> | ||
<view contentMode="scaleToFill" id="9Un-o1-tzh" customClass="HeaderFooterMoreView" customModule="Example_iOS" customModuleProvider="target"> | ||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/> | ||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> | ||
<subviews> | ||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="l5o-Rr-49h"> | ||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/> | ||
<fontDescription key="fontDescription" type="system" pointSize="18"/> | ||
<state key="normal" title="More"/> | ||
<connections> | ||
<action selector="handleMorePressed" destination="-2" eventType="touchUpInside" id="zzb-Pr-W6j"/> | ||
</connections> | ||
</button> | ||
</subviews> | ||
<constraints> | ||
<constraint firstItem="l5o-Rr-49h" firstAttribute="top" secondItem="9Un-o1-tzh" secondAttribute="top" id="6LZ-tU-yN1"/> | ||
<constraint firstAttribute="bottom" secondItem="l5o-Rr-49h" secondAttribute="bottom" id="LQK-iA-9FV"/> | ||
<constraint firstAttribute="trailing" secondItem="l5o-Rr-49h" secondAttribute="trailing" id="amX-Pz-M4V"/> | ||
<constraint firstItem="l5o-Rr-49h" firstAttribute="leading" secondItem="9Un-o1-tzh" secondAttribute="leading" id="exN-an-G2q"/> | ||
</constraints> | ||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> | ||
<viewLayoutGuide key="safeArea" id="0jJ-Kp-0ak"/> | ||
<point key="canvasLocation" x="-42" y="-30"/> | ||
</view> | ||
</objects> | ||
</document> |
14 changes: 14 additions & 0 deletions
14
Examples/Example-iOS/Sources/HeaderFooter/HeaderFooterSectionModel.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import DifferenceKit | ||
|
||
struct HeaderFooterSectionModel: Differentiable, Equatable { | ||
var id: Int | ||
var hasFooter: Bool | ||
|
||
var differenceIdentifier: Int { | ||
return id | ||
} | ||
|
||
var headerTitle: String { | ||
return "Section \(id)" | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
Examples/Example-iOS/Sources/HeaderFooter/HeaderFooterViewController.swift
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import UIKit | ||
import DifferenceKit | ||
|
||
final class HeaderFooterViewController: UITableViewController { | ||
typealias Section = ArraySection<HeaderFooterSectionModel, String> | ||
|
||
private var data = [Section]() | ||
|
||
private var dataInput: [Section] { | ||
get { return data } | ||
set { | ||
let changeset = StagedChangeset(source: data, target: newValue) | ||
tableView.reload(using: changeset, with: .fade) { data in | ||
self.data = data | ||
} | ||
} | ||
} | ||
|
||
private let allTexts = (0x0041...0x005A).compactMap { UnicodeScalar($0).map(String.init) } | ||
|
||
@objc private func refresh() { | ||
let model = HeaderFooterSectionModel(id: 0, hasFooter: true) | ||
let section = Section(model: model, elements: allTexts.prefix(7)) | ||
dataInput = [section] | ||
} | ||
|
||
private func showMore(in sectionIndex: Int) { | ||
var section = dataInput[sectionIndex] | ||
let texts = allTexts.dropFirst(section.elements.count).prefix(7) | ||
section.elements.append(contentsOf: texts) | ||
section.model.hasFooter = section.elements.count < allTexts.count | ||
dataInput[sectionIndex] = section | ||
|
||
let lastIndex = section.elements.index(before: section.elements.endIndex) | ||
let lastIndexPath = IndexPath(row: lastIndex, section: sectionIndex) | ||
tableView.scrollToRow(at: lastIndexPath, at: .bottom, animated: true) | ||
} | ||
|
||
override func viewWillAppear(_ animated: Bool) { | ||
super.viewWillAppear(animated) | ||
refresh() | ||
} | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
|
||
title = "Header Footer" | ||
tableView.allowsSelection = false | ||
|
||
tableView.register(cellType: HeaderFooterPlainCell.self) | ||
tableView.register(viewType: HeaderFooterMoreView.self) | ||
|
||
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(refresh)) | ||
} | ||
} | ||
|
||
extension HeaderFooterViewController { | ||
override func numberOfSections(in tableView: UITableView) -> Int { | ||
return data.count | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | ||
return data[section].elements.count | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | ||
let cell: HeaderFooterPlainCell = tableView.dequeueReusableCell(for: indexPath) | ||
cell.textLabel?.text = data[indexPath.section].elements[indexPath.row] | ||
return cell | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { | ||
return data[section].model.headerTitle | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { | ||
guard data[section].model.hasFooter else { return nil } | ||
|
||
let view: HeaderFooterMoreView = tableView.dequeueReusableHeaderFooterView() | ||
view.onMorePressed = { [weak self] in | ||
self?.showMore(in: section) | ||
} | ||
|
||
return view | ||
} | ||
|
||
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { | ||
return data[section].model.hasFooter ? 44 : 0 | ||
} | ||
} |
Oops, something went wrong.