Это источник данных для достижений, который можно переключать для просмотра в сетке или макете списка. Мысли / заметки
- Этот код ранее дублировался в двух разных ViewController.
- Должен ли быть здесь код CollectionLayout?
- Должны ли сюда входить заголовок раздела и делегат кнопки переключения макета?
- Правильно ли я реализовал DiffableDataSource?
Любые комментарии или советы приветствуются.
class AchievementDataSource: UICollectionViewDiffableDataSource<AchievementSectionID, Achievement> {
var sections: [AchievementListSection] = [AchievementListSection(id: 0, name: "")]
lazy var currentLayout = CollectionLayoutToggleHeader.State(rawValue: userLayoutPreferenceProvider()) ?? .list {
didSet {
userLayoutPreferenceSetter(currentLayout.rawValue)
}
}
var userLayoutPreferenceProvider: () -> String
var userLayoutPreferenceSetter: (String) -> Void
private let achievementPlaceholderImage = UIImage(named: "placeholder_home_achievements_home_badge")
init(collectionView: UICollectionView,
userLayoutPreferenceProvider: @escaping () -> String = { LocalUser.PreferenceSettings.groupAchievementLayout() },
userLayoutPreferenceSetter: @escaping (String) -> Void = { layoutString in
LocalUser.PreferenceSettings.setGroupAchievementLayout(layoutString)
} ) {
self.userLayoutPreferenceProvider = userLayoutPreferenceProvider
self.userLayoutPreferenceSetter = userLayoutPreferenceSetter
weak var weakSelf: AchievementDataSource?
super.init(collectionView: collectionView) { collectionView, indexPath, achievement in
return weakSelf?.configureCell(collectionView: collectionView, indexPath: indexPath, achievement: achievement)
}
weakSelf = self
}
func updateCollectionView() {
var snapshot = NSDiffableDataSourceSnapshot<AchievementSectionID, Achievement>()
snapshot.appendSections(sections.map { $0.id })
sections.forEach { section in
guard !section.isCollapsed else { return }
snapshot.appendItems(section.achievements, toSection: section.id)
}
apply(snapshot)
}
private func configureCell(collectionView: UICollectionView, indexPath: IndexPath, achievement: Achievement) -> UICollectionViewCell? {
switch currentLayout {
case .list:
return makeListCell(collectionView: collectionView, indexPath: indexPath, achievement: achievement)
case .grid:
return makeGridCell(collectionView: collectionView, indexPath: indexPath, achievement: achievement)
}
}
private func makeListCell(collectionView: UICollectionView, indexPath: IndexPath, achievement: Achievement) -> UICollectionViewCell? {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: AchievementCell.reuseIdentifier, for: indexPath) as! AchievementCell
cell.titleLabel.text = achievement.name
cell.descriptionLabel.text = achievement.description
cell.rarityIcon.image = achievement.level.icon
cell.rarityIcon.tintColor = achievement.level.color
cell.rarityLabel.text = achievement.level.name
let imageFormatting: ImageFormatType = achievement.isLocked ? .achievementLocked : .none
cell.imageView.pal_setProcessedImage(from: achievement.imageURL,
placeholder: achievementPlaceholderImage,
imageType: imageFormatting)
cell.isLocked = achievement.isLocked
cell.dateLabel.text = achievement.dateUnlocked
cell.isProgressBarHidden = (achievement.type != .multi)
cell.stepCompletionLabel.text = achievement.stepCompletionMessage ?? ""
cell.progressBar.progress = achievement.completionDecimal ?? 0
cell.progressLabel.text = "(achievement.completionPercentage ?? 0)%"
cell.separatorView.isHidden = isLastCellInSection(cell, indexPath: indexPath)
return cell
}
private func makeGridCell(collectionView: UICollectionView, indexPath: IndexPath, achievement: Achievement) -> UICollectionViewCell? {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageSubtitleCell.reuseID, for: indexPath) as! ImageSubtitleCell
cell.titleLabel.text = achievement.name
cell.isLocked = achievement.isLocked
let imageFormatting: ImageFormatType = achievement.isLocked ? .achievementLocked : .none
cell.imageView.pal_setProcessedImage(from: achievement.imageURL,
placeholder: achievementPlaceholderImage,
imageType: imageFormatting)
return cell
}
private func isLastCellInSection(_ cell: UICollectionViewCell, indexPath: IndexPath) -> Bool {
let currentSnapshot = snapshot()
let sectionIdentifier = currentSnapshot.sectionIdentifiers[indexPath.section]
let numberOfItemsInSection = currentSnapshot.numberOfItems(inSection: sectionIdentifier)
return indexPath.item + 1 == numberOfItemsInSection
}
}