diff --git a/Package.swift b/Package.swift index bcec957c2be3321cb1b9f1bcc1dd176814764b54..c53f1bb2c4a4aec111c8a015e8de375ea9a34605 100644 --- a/Package.swift +++ b/Package.swift @@ -678,6 +678,7 @@ let package = Package( "Integration", "Presentation", "ContactFeature", + "CollectionView", "DependencyInjection", .product( name: "DifferenceKit", diff --git a/Sources/ContactListFeature/Controllers/ContactListController.swift b/Sources/ContactListFeature/Controllers/ContactListController.swift index 34612913362943bf2f5de5c6819a14c282c84af9..aab6f249a4559cf4b340529173a7760157e837cf 100644 --- a/Sources/ContactListFeature/Controllers/ContactListController.swift +++ b/Sources/ContactListFeature/Controllers/ContactListController.swift @@ -3,6 +3,7 @@ import Theme import Shared import Combine import XXModels +import CollectionView import DependencyInjection public final class ContactListController: UIViewController { @@ -36,23 +37,18 @@ public final class ContactListController: UIViewController { private func setupCollectionView() { screenView.collectionView.delegate = self - screenView.collectionView.register(AvatarCell.self) screenView.collectionView.dataSource = dataSource screenView.collectionView.tintColor = Asset.neutralDark.color + CellFactory.contactListCellFactory.register(in: screenView.collectionView) dataSource = IndexedContactList( collectionView: screenView.collectionView ) { collectionView, indexPath, contact in - let cell: AvatarCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) - let name = (contact.nickname ?? contact.username) ?? "Fetching username..." - - cell.set( - image: contact.photo, - h1Text: name, - showSeparator: false + CellFactory.contactListCellFactory.build( + for: contact, + in: collectionView, + at: indexPath ) - - return cell } } diff --git a/Sources/ContactListFeature/Controllers/CreateGroupController.swift b/Sources/ContactListFeature/Controllers/CreateGroupController.swift index a8c75d45d6289c1fe8fd5a9380100664b0e85b91..137851c728584310312de2551d3811d90ae1342f 100644 --- a/Sources/ContactListFeature/Controllers/CreateGroupController.swift +++ b/Sources/ContactListFeature/Controllers/CreateGroupController.swift @@ -4,6 +4,7 @@ import Models import Shared import Combine import XXModels +import CollectionView import DependencyInjection public final class CreateGroupController: UIViewController { @@ -65,36 +66,29 @@ public final class CreateGroupController: UIViewController { } private func setupCollectionViews() { - screenView.bottomCollectionView.register(AvatarCell.self) - screenView.topCollectionView.register(CreateGroupCollectionCell.self) + CellFactory.createGroupHeroCellFactory + .register(in: screenView.topCollectionView) + CellFactory.createGroupListCellFactory + .register(in: screenView.bottomCollectionView) topCollectionDataSource = UICollectionViewDiffableDataSource<Int, Contact>( collectionView: screenView.topCollectionView - ) { [weak viewModel] collectionView, indexPath, contact in - let cell: CreateGroupCollectionCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) - - let title = (contact.nickname ?? contact.username) ?? "" - cell.setup(title: title, image: contact.photo) - cell.didTapRemove = { viewModel?.didSelect(contact: contact) } - - return cell + ) { collectionView, indexPath, contact in + CellFactory.createGroupHeroCellFactory.build( + for: contact, + in: collectionView, + at: indexPath + ) } bottomCollectionDataSource = UICollectionViewDiffableDataSource<Int, Contact>( collectionView: screenView.bottomCollectionView - ) { [weak self] collectionView, indexPath, contact in - let cell: AvatarCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) - let title = (contact.nickname ?? contact.username) ?? "" - - cell.set(image: contact.photo, h1Text: title) - - if let selectedElements = self?.selectedElements, selectedElements.contains(contact) { - collectionView.selectItem(at: indexPath, animated: true, scrollPosition: []) - } else { - collectionView.deselectItem(at: indexPath, animated: true) - } - - return cell + ) { collectionView, indexPath, contact in + CellFactory.createGroupListCellFactory.build( + for: contact, + in: collectionView, + at: indexPath + ) } screenView.bottomCollectionView.delegate = self diff --git a/Sources/ContactListFeature/Utils/ContactListCellConfigurators.swift b/Sources/ContactListFeature/Utils/ContactListCellConfigurators.swift new file mode 100644 index 0000000000000000000000000000000000000000..69e63438700a764cbf9ad41263b29df966f6a86e --- /dev/null +++ b/Sources/ContactListFeature/Utils/ContactListCellConfigurators.swift @@ -0,0 +1,73 @@ +import Shared +import XXModels +import CollectionView + +extension CellFactory where Model == Contact { + static let contactListCellFactory = CellFactory<Contact>( + register: .init( + register: { $0.register(AvatarCell.self) } + ), + build: .init(build: { contact, collectionView, indexPath in + let cell: AvatarCell = collectionView.dequeueReusableCell( + forIndexPath: indexPath + ) + + cell.set( + image: contact.photo, + h1Text: (contact.nickname ?? contact.username) ?? "", + showSeparator: false + ) + + return cell + }) + ) + + static let createGroupHeroCellFactory = CellFactory<Contact>( + register: .init( + register: { $0.register(CreateGroupHeroCollectionCell.self) } + ), + build: .init(build: { contact, collectionView, indexPath in + let name = (contact.nickname ?? contact.username) ?? "" + + let cell: CreateGroupHeroCollectionCell = collectionView.dequeueReusableCell( + forIndexPath: indexPath + ) + + cell.setup( + title: name, + image: contact.photo, + action: { + // viewModel?.didSelect(contact: contact) + } + ) + + return cell + }) + ) + + static let createGroupListCellFactory = CellFactory<Contact>( + register: .init( + register: { $0.register(AvatarCell.self) } + ), + build: .init(build: { contact, collectionView, indexPath in + let name = (contact.nickname ?? contact.username) ?? "" + + let cell: AvatarCell = collectionView.dequeueReusableCell( + forIndexPath: indexPath + ) + + cell.set( + image: contact.photo, + h1Text: name + ) + + //if let selectedElements = self?.selectedElements, selectedElements.contains(contact) { + // collectionView.selectItem(at: indexPath, animated: true, scrollPosition: []) + //} else { + // collectionView.deselectItem(at: indexPath, animated: true) + //} + + return cell + }) + ) +} diff --git a/Sources/ContactListFeature/Views/CreateGroupCollectionCell.swift b/Sources/ContactListFeature/Views/CreateGroupHeroCollectionCell.swift similarity index 71% rename from Sources/ContactListFeature/Views/CreateGroupCollectionCell.swift rename to Sources/ContactListFeature/Views/CreateGroupHeroCollectionCell.swift index 1717365300ab0ae52380cc47e6073f8118684957..e4d4be9e3df8b1bc40c65d672913c27eabbdfa5e 100644 --- a/Sources/ContactListFeature/Views/CreateGroupCollectionCell.swift +++ b/Sources/ContactListFeature/Views/CreateGroupHeroCollectionCell.swift @@ -2,14 +2,13 @@ import UIKit import Shared import Combine -final class CreateGroupCollectionCell: UICollectionViewCell { - let titleLabel = UILabel() - let removeButton = UIButton() - let upperView = UIView() - let avatarView = AvatarView() - - var didTapRemove: (() -> Void)? - var cancellables = Set<AnyCancellable>() +final class CreateGroupHeroCollectionCell: UICollectionViewCell { + private let upperView = UIView() + private let titleLabel = UILabel() + private let avatarView = AvatarView() + private let removeButton = UIButton() + private var didTapAction: (() -> Void)? + private var cancellables = Set<AnyCancellable>() override init(frame: CGRect) { super.init(frame: frame) @@ -29,6 +28,43 @@ final class CreateGroupCollectionCell: UICollectionViewCell { contentView.addSubview(upperView) contentView.addSubview(removeButton) + setupConstraints() + } + + required init?(coder: NSCoder) { nil } + + override func prepareForReuse() { + super.prepareForReuse() + + didTapAction = nil + titleLabel.text = nil + avatarView.prepareForReuse() + cancellables.removeAll() + } + + func setup( + title: String, + image: Data?, + action: @escaping () -> Void + ) { + avatarView.setupProfile( + title: title, + image: image, + size: .large + ) + + titleLabel.text = title + didTapAction = action + + cancellables.removeAll() + + removeButton + .publisher(for: .touchUpInside) + .sink { [unowned self] in didTapAction?() } + .store(in: &cancellables) + } + + private func setupConstraints() { upperView.snp.makeConstraints { $0.top.equalToSuperview() $0.left.equalToSuperview() @@ -58,23 +94,4 @@ final class CreateGroupCollectionCell: UICollectionViewCell { $0.bottom.equalToSuperview() } } - - required init?(coder: NSCoder) { nil } - - override func prepareForReuse() { - super.prepareForReuse() - titleLabel.text = nil - avatarView.prepareForReuse() - cancellables.removeAll() - } - - func setup(title: String, image: Data?) { - titleLabel.text = title - avatarView.setupProfile(title: title, image: image, size: .large) - cancellables.removeAll() - - removeButton.publisher(for: .touchUpInside) - .sink { [unowned self] in didTapRemove?() } - .store(in: &cancellables) - } }