Skip to content

Commit

Permalink
implement initial context menus in example project
Browse files Browse the repository at this point in the history
delete works, favorite does not (yet)

#1
  • Loading branch information
jessesquires committed Sep 13, 2021
1 parent f3ed74a commit 1ece8fc
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 20 deletions.
4 changes: 3 additions & 1 deletion Example/Sources/Grid/GridColorCellViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ struct GridColorCellViewModel: CellViewModel {

// MARK: CellViewModel

var id: UniqueIdentifier { self.color.name }
var id: UniqueIdentifier { self.color.id }

let shouldHighlight = false

let contextMenuConfiguration: UIContextMenuConfiguration?

func configure(cell: GridColorCell) {
cell.label.text = self.color.name
cell.backgroundColor = self.color.uiColor
Expand Down
4 changes: 3 additions & 1 deletion Example/Sources/Grid/GridPersonCellViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ struct GridPersonCellViewModel: CellViewModel {

// MARK: CellViewModel

var id: UniqueIdentifier { self.person.name }
var id: UniqueIdentifier { self.person.id }

let contextMenuConfiguration: UIContextMenuConfiguration?

var nibName: String? { "GridPersonCell" }

Expand Down
4 changes: 2 additions & 2 deletions Example/Sources/Grid/GridViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class GridViewController: ExampleCollectionViewController {

override var model: Model {
didSet {
self.driver.viewModel = ViewModel.createGrid(from: self.model)
self.driver.viewModel = self.createCollectionViewModel(style: .grid)
}
}

Expand Down Expand Up @@ -67,7 +67,7 @@ final class GridViewController: ExampleCollectionViewController {

let layout = UICollectionViewCompositionalLayout(section: section)

let viewModel = ViewModel.createGrid(from: self.model)
let viewModel = self.createCollectionViewModel(style: .grid)

self.driver = CollectionViewDriver(
view: self.collectionView,
Expand Down
4 changes: 3 additions & 1 deletion Example/Sources/List/ListColorCellViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ struct ListColorCellViewModel: CellViewModel {

// MARK: CellViewModel

var id: UniqueIdentifier { self.color.name }
var id: UniqueIdentifier { self.color.id }

let shouldHighlight = false

let contextMenuConfiguration: UIContextMenuConfiguration?

func configure(cell: UICollectionViewListCell) {
var contentConfiguration = cell.defaultContentConfiguration()
contentConfiguration.text = self.color.name
Expand Down
4 changes: 3 additions & 1 deletion Example/Sources/List/ListPersonCellViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ struct ListPersonCellViewModel: CellViewModel {

// MARK: CellViewModel

var id: UniqueIdentifier { self.person.name }
var id: UniqueIdentifier { self.person.id }

let contextMenuConfiguration: UIContextMenuConfiguration?

func configure(cell: UICollectionViewListCell) {
var contentConfiguration = UIListContentConfiguration.subtitleCell()
Expand Down
4 changes: 2 additions & 2 deletions Example/Sources/List/ListViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class ListViewController: ExampleCollectionViewController {

override var model: Model {
didSet {
self.driver.viewModel = ViewModel.createList(from: self.model)
self.driver.viewModel = self.createCollectionViewModel(style: .list)
}
}

Expand Down Expand Up @@ -57,7 +57,7 @@ final class ListViewController: ExampleCollectionViewController {
return section
}

let viewModel = ViewModel.createList(from: self.model)
let viewModel = self.createCollectionViewModel(style: .list)

self.driver = CollectionViewDriver(
view: self.collectionView,
Expand Down
19 changes: 19 additions & 0 deletions Example/Sources/Main/ExampleCollectionViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class ExampleCollectionViewController: UICollectionViewController {
self.model = Model()
}

func deleteItem(id: UniqueIdentifier) {
self.model.delete(id: id)
}

func deleteAt(indexPath: IndexPath) {
self.model.deleteModelAt(indexPath: indexPath)
}
Expand All @@ -51,8 +55,23 @@ class ExampleCollectionViewController: UICollectionViewController {
self.model.toggleFavoriteAt(indexPath: indexPath)
}

func toggleFavorite(id: UniqueIdentifier) {
self.model.toggleFavorite(id: id)
}

// MARK: Helpers

func createCollectionViewModel(style: ViewModelStyle) -> CollectionViewModel {
ViewModel.create(
model: self.model,
style: style,
favoriteAction: { [unowned self] in
self.toggleFavorite(id: $0)
}, deleteAction: { [unowned self] in
self.deleteItem(id: $0)
})
}

private func appendRightBarButton(_ item: UIBarButtonItem) {
var items = self.navigationItem.rightBarButtonItems ?? []
items.append(item)
Expand Down
25 changes: 25 additions & 0 deletions Example/Sources/Main/UIKit+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// Copyright © 2019-present Jesse Squires
//

import ReactiveCollectionsKit
import UIKit

extension UIBarButtonItem {
Expand All @@ -21,3 +22,27 @@ extension UIBarButtonItem {
action: action)
}
}

extension UIContextMenuConfiguration {
typealias ItemAction = (UniqueIdentifier) -> Void

static func configFor(
itemId: UniqueIdentifier,
favoriteAction: @escaping ItemAction,
deleteAction: @escaping ItemAction) -> UIContextMenuConfiguration? {
UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
let favorite = UIAction(title: "Favorite",
image: UIImage(systemName: "star.fill")) { _ in
favoriteAction(itemId)
}

let delete = UIAction(title: "Delete",
image: UIImage(systemName: "trash"),
attributes: .destructive) { _ in
deleteAction(itemId)
}

return UIMenu(children: [favorite, delete])
}
}
}
19 changes: 19 additions & 0 deletions Example/Sources/Models/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//

import Foundation
import ReactiveCollectionsKit

struct Model {
private(set) var people = PersonModel.makePeople()
Expand All @@ -36,6 +37,15 @@ struct Model {
}
}

mutating func delete(id: UniqueIdentifier) {
if let index = self.people.firstIndex(where: { $0.id == id }) {
self.people.remove(at: index)
}
if let index = self.colors.firstIndex(where: { $0.id == id }) {
self.colors.remove(at: index)
}
}

mutating func toggleFavoriteAt(indexPath: IndexPath) {
switch indexPath.section {
case 0:
Expand All @@ -48,6 +58,15 @@ struct Model {
fatalError("invalid indexPath: \(indexPath)")
}
}

mutating func toggleFavorite(id: UniqueIdentifier) {
if let index = self.people.firstIndex(where: { $0.id == id }) {
self.people[index].isFavorite.toggle()
}
if let index = self.colors.firstIndex(where: { $0.id == id }) {
self.colors[index].isFavorite.toggle()
}
}
}

extension Model: CustomDebugStringConvertible {
Expand Down
47 changes: 35 additions & 12 deletions Example/Sources/Models/ViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import Foundation
import ReactiveCollectionsKit
import UIKit

enum ViewModelStyle: String {
case grid
Expand All @@ -30,25 +31,35 @@ enum ViewModelStyle: String {
}

enum ViewModel {
static func createGrid(from model: Model) -> CollectionViewModel {
self.create(model: model, style: .grid)
}

static func createList(from model: Model) -> CollectionViewModel {
self.create(model: model, style: .list)
}
typealias ItemAction = (UniqueIdentifier) -> Void

private static func create(model: Model, style: ViewModelStyle) -> CollectionViewModel {
static func create(
model: Model,
style: ViewModelStyle,
favoriteAction: @escaping ItemAction,
deleteAction: @escaping ItemAction) -> CollectionViewModel {

// MARK: People Section

let peopleCellViewModels: [AnyCellViewModel] = model.people.map {
let menuConfig = UIContextMenuConfiguration.configFor(
itemId: $0.id,
favoriteAction: favoriteAction,
deleteAction: deleteAction
)

switch style {
case .grid:
return GridPersonCellViewModel(person: $0).anyViewModel
return GridPersonCellViewModel(
person: $0,
contextMenuConfiguration: menuConfig
).anyViewModel

case .list:
return ListPersonCellViewModel(person: $0).anyViewModel
return ListPersonCellViewModel(
person: $0,
contextMenuConfiguration: menuConfig
).anyViewModel
}
}

Expand All @@ -72,12 +83,24 @@ enum ViewModel {
// MARK: Color Section

let colorCellViewModels: [AnyCellViewModel] = model.colors.map {
let menuConfig = UIContextMenuConfiguration.configFor(
itemId: $0.id,
favoriteAction: favoriteAction,
deleteAction: deleteAction
)

switch style {
case .grid:
return GridColorCellViewModel(color: $0).anyViewModel
return GridColorCellViewModel(
color: $0,
contextMenuConfiguration: menuConfig
).anyViewModel

case .list:
return ListColorCellViewModel(color: $0).anyViewModel
return ListColorCellViewModel(
color: $0,
contextMenuConfiguration: menuConfig
).anyViewModel
}
}

Expand Down

0 comments on commit 1ece8fc

Please sign in to comment.