Skip to content

Commit

Permalink
Show loading indicator when loading slate detail content
Browse files Browse the repository at this point in the history
  • Loading branch information
David Skuza authored and dskuza committed Jul 15, 2022
1 parent 4e81fec commit f774e66
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 26 deletions.
71 changes: 46 additions & 25 deletions PocketKit/Sources/PocketKit/Home/SlateDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,11 @@ class SlateDetailViewController: UIViewController {
}

private lazy var dataSource: UICollectionViewDiffableDataSource<SlateDetailViewModel.Section, SlateDetailViewModel.Cell> = {
let registration = UICollectionView.CellRegistration<RecommendationCell, SlateDetailViewModel.Cell> { [weak self] cell, indexPath, cellViewModel in
self?.configure(cell, at: indexPath, viewModel: cellViewModel)
}

let dataSource = UICollectionViewDiffableDataSource<SlateDetailViewModel.Section, SlateDetailViewModel.Cell>(
UICollectionViewDiffableDataSource<SlateDetailViewModel.Section, SlateDetailViewModel.Cell>(
collectionView: collectionView
) { (collectionView, indexPath, recommendation) -> UICollectionViewCell? in
return collectionView.dequeueConfiguredReusableCell(using: registration, for: indexPath, item: recommendation)
) { [weak self] (collectionView, indexPath, viewModelCell) -> UICollectionViewCell? in
return self?.cell(for: viewModelCell, at: indexPath)
}

return dataSource
}()

private lazy var collectionView: UICollectionView = {
Expand Down Expand Up @@ -69,6 +63,7 @@ class SlateDetailViewController: UIViewController {
collectionView.dataSource = dataSource
collectionView.delegate = self

collectionView.register(cellClass: LoadingCell.self)
collectionView.register(cellClass: RecommendationCell.self)
collectionView.register(viewClass: DividerView.self, forSupplementaryViewOfKind: "divider")

Expand Down Expand Up @@ -155,6 +150,23 @@ private extension SlateDetailViewController {
func section(for index: Int, environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
let section = self.dataSource.sectionIdentifier(for: index)
switch section {
case .loading:
let item = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(1)
)
)

let group = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(0.8)
),
subitems: [item]
)

return NSCollectionLayoutSection(group: group)
case .slate(let slate):
let width = environment.container.effectiveContentSize.width
let dividerHeight: CGFloat = 17
Expand Down Expand Up @@ -216,26 +228,35 @@ private extension SlateDetailViewController {
}
}

func configure(
_ cell: RecommendationCell,
at indexPath: IndexPath,
viewModel cellViewModel: SlateDetailViewModel.Cell
) {
cell.mode = .hero
func cell(
for viewModelCell: SlateDetailViewModel.Cell,
at indexPath: IndexPath
) -> UICollectionViewCell {
switch viewModelCell {
case .loading:
let cell: LoadingCell = collectionView.dequeueCell(for: indexPath)
return cell
case .recommendation(let objectID):
let cell: RecommendationCell = collectionView.dequeueCell(for: indexPath)
cell.mode = .hero

guard let viewModel = self.model.viewModel(for: objectID) else {
return cell
}

guard case .recommendation(let objectID) = cellViewModel,
let viewModel = model.viewModel(for: objectID) else {
return
}
cell.configure(model: viewModel)

cell.configure(model: viewModel)
if let action = self.model.saveAction(for: viewModelCell, at: indexPath),
let uiAction = UIAction(action) {
cell.saveButton.addAction(uiAction, for: .primaryActionTriggered)
}

if let action = model.saveAction(for: cellViewModel, at: indexPath), let uiAction = UIAction(action) {
cell.saveButton.addAction(uiAction, for: .primaryActionTriggered)
}
if let action = self.model.reportAction(for: viewModelCell, at: indexPath),
let uiAction = UIAction(action) {
cell.overflowButton.addAction(uiAction, for: .primaryActionTriggered)
}

if let action = model.reportAction(for: cellViewModel, at: indexPath), let uiAction = UIAction(action) {
cell.overflowButton.addAction(uiAction, for: .primaryActionTriggered)
return cell
}
}
}
Expand Down
19 changes: 18 additions & 1 deletion PocketKit/Sources/PocketKit/Home/SlateDetailViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class SlateDetailViewModel {
private var viewModelSubscriptions: Set<AnyCancellable> = []

@Published
var snapshot = Snapshot()
var snapshot: Snapshot

@Published
var selectedReadableViewModel: RecommendationViewModel? = nil
Expand All @@ -34,6 +34,8 @@ class SlateDetailViewModel {
self.source = source
self.tracker = tracker
self.slateController = source.makeSlateController(byID: slateID)
self.snapshot = Self.loadingSnapshot()

self.slateController.delegate = self
}

Expand All @@ -50,6 +52,8 @@ class SlateDetailViewModel {

func select(cell: SlateDetailViewModel.Cell, at indexPath: IndexPath) {
switch cell {
case .loading:
return
case .recommendation:
select(recommendation: cell, at: indexPath)
}
Expand Down Expand Up @@ -80,6 +84,8 @@ class SlateDetailViewModel {

func willDisplay(_ cell: SlateDetailViewModel.Cell, at indexPath: IndexPath) {
switch cell {
case .loading:
return
case .recommendation:
tracker.track(
event: ImpressionEvent(component: .content, requirement: .instant),
Expand All @@ -102,6 +108,13 @@ class SlateDetailViewModel {
}

private extension SlateDetailViewModel {
static func loadingSnapshot() -> Snapshot {
var snapshot = Snapshot()
snapshot.appendSections([.loading])
snapshot.appendItems([.loading], toSection: .loading)
return snapshot
}

func buildSnapshot() -> Snapshot {
viewModels = [:]
viewModelSubscriptions = []
Expand Down Expand Up @@ -215,6 +228,8 @@ private extension SlateDetailViewModel {

private func contexts(for cell: SlateDetailViewModel.Cell, at indexPath: IndexPath) -> [Context] {
switch cell {
case .loading:
return []
case .recommendation(let objectID):
guard let viewModel = viewModel(for: objectID),
let slate = slateController.slate,
Expand Down Expand Up @@ -260,10 +275,12 @@ extension SlateDetailViewModel: SlateControllerDelegate {

extension SlateDetailViewModel {
enum Section: Hashable {
case loading
case slate(Slate)
}

enum Cell: Hashable {
case loading
case recommendation(NSManagedObjectID)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class SlateDetailViewModelTests: XCTestCase {
viewModel.$snapshot.dropFirst().sink { snapshot in
let reloaded = snapshot.reloadedItemIdentifiers.compactMap { cell -> NSManagedObjectID? in
switch cell {
case .loading:
return nil
case .recommendation(let objectID):
return objectID
}
Expand Down

0 comments on commit f774e66

Please sign in to comment.