128 lines
4.9 KiB
Swift
128 lines
4.9 KiB
Swift
// Copyright © 2021 Metabolist. All rights reserved.
|
|
|
|
import Combine
|
|
import UIKit
|
|
import ViewModels
|
|
|
|
enum IdentitiesSection: Hashable {
|
|
case add
|
|
case identities(String)
|
|
}
|
|
|
|
enum IdentitiesItem: Hashable {
|
|
case add
|
|
case identitiy(Identity)
|
|
}
|
|
|
|
final class IdentitiesDataSource: UITableViewDiffableDataSource<IdentitiesSection, IdentitiesItem> {
|
|
private let updateQueue =
|
|
DispatchQueue(label: "com.metabolist.metatext.identities-data-source.update-queue")
|
|
private var cancellables = Set<AnyCancellable>()
|
|
private let deleteAction: (Identity) -> Void
|
|
|
|
init(tableView: UITableView,
|
|
publisher: AnyPublisher<[Identity], Never>,
|
|
viewModelProvider: @escaping (Identity) -> IdentityViewModel,
|
|
deleteAction: @escaping (Identity) -> Void) {
|
|
self.deleteAction = deleteAction
|
|
|
|
tableView.register(UITableViewCell.self,
|
|
forCellReuseIdentifier: String(describing: UITableViewCell.self))
|
|
tableView.register(IdentityTableViewCell.self,
|
|
forCellReuseIdentifier: String(describing: IdentityTableViewCell.self))
|
|
|
|
super.init(tableView: tableView) { tableView, indexPath, item in
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: item.cellReuseIdentifier,
|
|
for: indexPath)
|
|
|
|
switch item {
|
|
case .add:
|
|
var configuration = cell.defaultContentConfiguration()
|
|
|
|
configuration.text = NSLocalizedString("add", comment: "")
|
|
configuration.image = UIImage(systemName: "plus.circle.fill")
|
|
cell.contentConfiguration = configuration
|
|
case let .identitiy(identity):
|
|
let viewModel = viewModelProvider(identity)
|
|
|
|
(cell as? IdentityTableViewCell)?.viewModel = viewModel
|
|
cell.accessoryType = identity.id == viewModel.identityContext.identity.id ? .checkmark : .none
|
|
}
|
|
|
|
return cell
|
|
}
|
|
|
|
publisher
|
|
.sink { [weak self] in self?.update(identities: $0) }
|
|
.store(in: &cancellables)
|
|
}
|
|
|
|
override func apply(_ snapshot: NSDiffableDataSourceSnapshot<IdentitiesSection, IdentitiesItem>,
|
|
animatingDifferences: Bool = true,
|
|
completion: (() -> Void)? = nil) {
|
|
updateQueue.async {
|
|
super.apply(snapshot, animatingDifferences: animatingDifferences, completion: completion)
|
|
}
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
|
let currentSnapshot = snapshot()
|
|
let section = currentSnapshot.sectionIdentifiers[section]
|
|
|
|
if currentSnapshot.numberOfItems(inSection: section) > 0, case let .identities(title) = section {
|
|
return title
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
|
itemIdentifier(for: indexPath) != .add
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView,
|
|
commit editingStyle: UITableViewCell.EditingStyle,
|
|
forRowAt indexPath: IndexPath) {
|
|
guard editingStyle == .delete,
|
|
case let .identitiy(identity) = itemIdentifier(for: indexPath)
|
|
else { return }
|
|
|
|
deleteAction(identity)
|
|
}
|
|
}
|
|
|
|
private extension IdentitiesDataSource {
|
|
private func update(identities: [Identity]) {
|
|
var newSnapshot = NSDiffableDataSourceSnapshot<IdentitiesSection, IdentitiesItem>()
|
|
let sections = [
|
|
(section: IdentitiesSection.identities(NSLocalizedString("identities.accounts", comment: "")),
|
|
identities: identities.filter { $0.authenticated && !$0.pending }.map(IdentitiesItem.identitiy)),
|
|
(section: IdentitiesSection.identities(NSLocalizedString("identities.browsing", comment: "")),
|
|
identities: identities.filter { !$0.authenticated && !$0.pending }.map(IdentitiesItem.identitiy)),
|
|
(section: IdentitiesSection.identities(NSLocalizedString("identities.pending", comment: "")),
|
|
identities: identities.filter { $0.pending }.map(IdentitiesItem.identitiy))
|
|
]
|
|
.filter { !$0.identities.isEmpty }
|
|
|
|
newSnapshot.appendSections([.add] + sections.map(\.section))
|
|
newSnapshot.appendItems([.add], toSection: .add)
|
|
|
|
for section in sections {
|
|
newSnapshot.appendItems(section.identities, toSection: section.section)
|
|
}
|
|
|
|
apply(newSnapshot, animatingDifferences: !snapshot().sectionIdentifiers.filter { $0 != .add }.isEmpty)
|
|
}
|
|
}
|
|
|
|
private extension IdentitiesItem {
|
|
var cellReuseIdentifier: String {
|
|
switch self {
|
|
case .add:
|
|
return String(describing: UITableViewCell.self)
|
|
case .identitiy:
|
|
return String(describing: IdentityTableViewCell.self)
|
|
}
|
|
}
|
|
}
|