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

Add update and move support #18

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 26 additions & 2 deletions Examples/Example-iOS/MountainsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ final class MountainsViewController: UIViewController {

struct Mountain: Hashable {
var name: String
var highlightedName: NSAttributedString

func hash(into hasher: inout Hasher) {
hasher.combine(name)
}

func contains(_ filter: String) -> Bool {
guard !filter.isEmpty else {
Expand All @@ -24,13 +29,13 @@ final class MountainsViewController: UIViewController {

private lazy var dataSource = CollectionViewDiffableDataSource<Section, Mountain>(collectionView: collectionView) { collectionView, indexPath, mountain in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LabelCell.name, for: indexPath) as! LabelCell
cell.label.text = mountain.name
cell.label.attributedText = mountain.highlightedName
return cell
}

private let allMountains: [Mountain] = mountainsRawData.components(separatedBy: .newlines).map { line in
let name = line.components(separatedBy: ",")[0]
return Mountain(name: name)
return Mountain(name: name, highlightedName: NSAttributedString(string: name))
}

override func viewDidLoad() {
Expand All @@ -49,6 +54,10 @@ final class MountainsViewController: UIViewController {
let mountains = allMountains.lazy
.filter { $0.contains(filter) }
.sorted { $0.name < $1.name }
.map { mountain -> Mountain in
let attrName = underlineOccurences(of: filter.lowercased(), in: NSMutableAttributedString(string: mountain.name))
return Mountain(name: mountain.name, highlightedName: attrName)
}

var snapshot = DiffableDataSourceSnapshot<Section, Mountain>()
snapshot.appendSections([.main])
Expand All @@ -57,6 +66,21 @@ final class MountainsViewController: UIViewController {
}
}

private func underlineOccurences(of searchString: String, in text: NSMutableAttributedString) -> NSMutableAttributedString {
let inputLength = text.string.count
let searchLength = searchString.count
var range = NSRange(location: 0, length: text.length)

while range.location != NSNotFound {
range = (text.string.lowercased() as NSString).range(of: searchString, options: [], range: range)
if range.location != NSNotFound {
text.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: range.location, length: searchLength))
range = NSRange(location: range.location + range.length, length: inputLength - (range.location + range.length))
}
}
return text
}

extension MountainsViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
search(filter: searchText)
Expand Down
4 changes: 2 additions & 2 deletions Sources/Internal/DiffableDataSourceCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ final class DiffableDataSourceCore<SectionIdentifierType: Hashable, ItemIdentifi
return nil
}

return items[indexPath.item].differenceIdentifier
return items[indexPath.item].identifier
}

func unsafeItemIdentifier(for indexPath: IndexPath, file: StaticString = #file, line: UInt = #line) -> ItemIdentifierType {
Expand All @@ -83,7 +83,7 @@ final class DiffableDataSourceCore<SectionIdentifierType: Hashable, ItemIdentifi
let indexPathMap: [ItemIdentifierType: IndexPath] = sections.enumerated()
.reduce(into: [:]) { result, section in
for (itemIndex, item) in section.element.elements.enumerated() {
result[item.differenceIdentifier] = IndexPath(
result[item.identifier] = IndexPath(
item: itemIndex,
section: section.offset
)
Expand Down
14 changes: 8 additions & 6 deletions Sources/Internal/SnapshotStructure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import DifferenceKit

struct SnapshotStructure<SectionID: Hashable, ItemID: Hashable> {
struct Item: Differentiable, Equatable {
var differenceIdentifier: ItemID
var differenceIdentifier: Int
var identifier: ItemID
var isReloaded: Bool

init(id: ItemID, isReloaded: Bool) {
self.differenceIdentifier = id
self.identifier = id
self.differenceIdentifier = id.hashValue

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hash value is deprecated, so maybe do

Suggested change
self.differenceIdentifier = id.hashValue
var hasher = Hasher()
hasher.combine(id)
self.differenceIdentifier = hasher.finalize()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the docs state that "hashValue is deprecated as a Hashable requirement." However, the variable itself is not deprecated, and is intended as a way to get the exact result produced by the three lines of code you provided.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, was not sure that it was meant like that 😅

self.isReloaded = isReloaded
}

Expand All @@ -16,7 +18,7 @@ struct SnapshotStructure<SectionID: Hashable, ItemID: Hashable> {
}

func isContentEqual(to source: Item) -> Bool {
return !isReloaded && differenceIdentifier == source.differenceIdentifier
return !isReloaded && identifier == source.identifier
}
}

Expand Down Expand Up @@ -53,15 +55,15 @@ struct SnapshotStructure<SectionID: Hashable, ItemID: Hashable> {
var allItemIDs: [ItemID] {
return sections.lazy
.flatMap { $0.elements }
.map { $0.differenceIdentifier }
.map { $0.identifier }
}

func items(in sectionID: SectionID, file: StaticString = #file, line: UInt = #line) -> [ItemID] {
guard let sectionIndex = sectionIndex(of: sectionID) else {
specifiedSectionIsNotFound(sectionID, file: file, line: line)
}

return sections[sectionIndex].elements.map { $0.differenceIdentifier }
return sections[sectionIndex].elements.map { $0.identifier }
}

func section(containing itemID: ItemID) -> SectionID? {
Expand Down Expand Up @@ -270,7 +272,7 @@ private extension SnapshotStructure {
func itemPositionMap() -> [ItemID: ItemPosition] {
return sections.enumerated().reduce(into: [:]) { result, section in
for (itemRelativeIndex, item) in section.element.elements.enumerated() {
result[item.differenceIdentifier] = ItemPosition(
result[item.identifier] = ItemPosition(
item: item,
itemRelativeIndex: itemRelativeIndex,
section: section.element,
Expand Down