IGListKit/Examples/Examples-macOS/IGListKitExamples/ViewControllers/UsersViewController.swift

161 lines
5 KiB
Swift
Raw Normal View History

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import Cocoa
import IGListDiffKit
final class UsersViewController: NSViewController {
@IBOutlet weak var collectionView: NSCollectionView!
// MARK: Data
var users = [User]() {
didSet {
computeFilteredUsers()
}
}
var searchTerm = "" {
didSet {
computeFilteredUsers()
}
}
private func computeFilteredUsers() {
guard !searchTerm.isEmpty else {
filteredUsers = users
return
}
filteredUsers = users.filter({ $0.name.localizedCaseInsensitiveContains(self.searchTerm) })
}
fileprivate func delete(user: User) {
guard let index = self.users.firstIndex(where: { $0.pk == user.pk }) else { return }
self.users.remove(at: index)
}
// MARK: -
// MARK: Diffing
var isFirstRun = true
var filteredUsers = [User]() {
didSet {
// A crash occurs when you try to use performBatchUpdates the first time
guard !isFirstRun else {
collectionView.reloadData()
isFirstRun = false
return
}
// get the difference between the old array of Users and the new array of Users
let diff = ListDiffPaths(fromSection: 0, toSection: 0, oldArray: oldValue, newArray: filteredUsers, option: .equality)
let batchUpdates = diff.forBatchUpdates()
let inserts = Set(batchUpdates.inserts)
let deletes = Set(batchUpdates.deletes)
let updates = Set(batchUpdates.updates)
let moves = Set(batchUpdates.moves)
// this difference is used here to update the collection view, but it can be used
// to update collection views and other similar interface elements
// this code can also be added to an extension of NSCollectionView ;)
// Set the animation duration when updating the collection view
NSAnimationContext.current.duration = 0.25
// Perform the updates to the collection view
collectionView.animator().performBatchUpdates({
collectionView.deleteItems(at: deletes)
collectionView.insertItems(at: inserts)
collectionView.reloadItems(at: updates)
moves.forEach { move in
collectionView.moveItem(at: move.from, to: move.to)
}
}, completionHandler: nil)
}
}
// MARK: -
private func loadSampleUsers() {
guard let file = Bundle.main.url(forResource: "users", withExtension: "json") else { return }
do {
self.users = try UsersProvider(with: file).users
} catch {
NSAlert(error: error).runModal()
}
}
// MARK: Interface
override func viewDidLoad() {
super.viewDidLoad()
// The view needs to be backed by a CALayer to be able to enable the collections view animations you can
// enable this by selecting the view controller's view in the Interface Builder in the Core Animation section
// of the View Effects inspector tab, through code you can do by view.wantsLayer = true
loadSampleUsers()
}
override func viewDidAppear() {
super.viewDidAppear()
view.window?.titleVisibility = .hidden
}
@IBAction func shuffle(_ sender: Any?) {
users = users.shuffled
}
@IBAction func search(_ sender: NSSearchField) {
searchTerm = sender.stringValue
}
}
extension UsersViewController: UserCollectionViewCellDelegate {
func itemDeleted(_ user: User) {
self.delete(user: user)
}
}
extension UsersViewController: NSCollectionViewDelegate {
}
extension UsersViewController: NSCollectionViewDataSource {
private struct Storyboard {
static let cellIdentifier = "UserCollectionViewCell"
}
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return self.filteredUsers.count
}
@available(OSX 10.11, *)
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: Storyboard.cellIdentifier), for: indexPath)
guard let cell = item as? UserCollectionViewCell else { return item }
cell.delegate = self
cell.bindViewModel(filteredUsers[indexPath.item])
return cell
}
}
extension UsersViewController: NSCollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
let availableWidth = collectionView.bounds.width
return CGSize(width: availableWidth, height: 44)
}
}