import HUD import UIKit import Models import Shared import Combine import XXModels import DependencyInjection public final class CreateGroupController: UIViewController { @Dependency private var hud: HUDType @Dependency private var coordinator: ContactListCoordinating lazy private var titleLabel = UILabel() lazy private var createButton = UIButton() lazy private var screenView = CreateGroupView() private var selectedElements = [Contact]() { didSet { screenView.tableView.reloadData() } } private let viewModel = CreateGroupViewModel() private var cancellables = Set<AnyCancellable>() private var tableDataSource: UITableViewDiffableDataSource<SectionId, Contact>! private var collectionDataSource: UICollectionViewDiffableDataSource<SectionId, Contact>! private var count = 0 { didSet { createButton.isEnabled = count >= 2 && count <= 10 let text = Localized.CreateGroup.title("\(count)") let attString = NSMutableAttributedString(string: text) attString.addAttribute(.font, value: Fonts.Mulish.semiBold.font(size: 18.0) as Any) attString.addAttribute(.foregroundColor, value: Asset.neutralActive.color) attString.addAttribute(name: .foregroundColor, value: Asset.neutralDisabled.color, betweenCharacters: "#") titleLabel.attributedText = attString } } public override func loadView() { view = screenView } public override func viewDidLoad() { super.viewDidLoad() setupNavigationBar() setupTableAndCollection() setupBindings() } private func setupNavigationBar() { navigationItem.backButtonTitle = " " let back = UIButton.back() back.addTarget(self, action: #selector(didTapBack), for: .touchUpInside) navigationItem.leftBarButtonItem = UIBarButtonItem( customView: UIStackView(arrangedSubviews: [back, titleLabel]) ) createButton.setTitle(Localized.CreateGroup.create, for: .normal) createButton.setTitleColor(Asset.brandPrimary.color, for: .normal) createButton.titleLabel?.font = Fonts.Mulish.semiBold.font(size: 16.0) createButton.setTitleColor(Asset.neutralDisabled.color, for: .disabled) navigationItem.rightBarButtonItem = UIBarButtonItem(customView: createButton) } private func setupTableAndCollection() { screenView.tableView.rowHeight = 64.0 screenView.tableView.register(AvatarCell.self) screenView.collectionView.register(CreateGroupCollectionCell.self) collectionDataSource = UICollectionViewDiffableDataSource<SectionId, Contact>( collectionView: screenView.collectionView ) { [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 } tableDataSource = DiffEditableDataSource<SectionId, Contact>( tableView: screenView.tableView ) { [weak self] tableView, indexPath, contact in let cell = tableView.dequeueReusableCell(forIndexPath: indexPath, ofType: AvatarCell.self) let title = (contact.nickname ?? contact.username) ?? "" cell.setup(title: title, image: contact.photo) if let selectedElements = self?.selectedElements, selectedElements.contains(contact) { tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none) } else { tableView.deselectRow(at: indexPath, animated: true) } return cell } screenView.tableView.delegate = self screenView.tableView.dataSource = tableDataSource screenView.collectionView.dataSource = collectionDataSource } private func setupBindings() { viewModel.hud .receive(on: DispatchQueue.main) .sink { [hud] in hud.update(with: $0) } .store(in: &cancellables) let selected = viewModel.selected.share() selected .receive(on: DispatchQueue.main) .sink { [unowned self] in screenView.collectionView.isHidden = $0.count < 1 count = $0.count selectedElements = $0 }.store(in: &cancellables) selected.map { selectedContacts in var snapshot = NSDiffableDataSourceSnapshot<SectionId, Contact>() let sections = [SectionId()] snapshot.appendSections(sections) sections.forEach { section in snapshot.appendItems(selectedContacts, toSection: section) } return snapshot } .receive(on: DispatchQueue.main) .sink { [unowned self] in collectionDataSource.apply($0) } .store(in: &cancellables) viewModel.contacts .map { contacts in var snapshot = NSDiffableDataSourceSnapshot<SectionId, Contact>() let sections = [SectionId()] snapshot.appendSections(sections) sections.forEach { section in snapshot.appendItems(contacts, toSection: section) } return snapshot } .receive(on: DispatchQueue.main) .sink { [unowned self] in tableDataSource.apply($0, animatingDifferences: tableDataSource.snapshot().numberOfItems > 0) }.store(in: &cancellables) screenView.searchComponent.textPublisher .removeDuplicates() .sink { [unowned self] in viewModel.filter($0) } .store(in: &cancellables) viewModel.info .receive(on: DispatchQueue.main) .sink { [unowned self] in coordinator.toGroupChat(with: $0, from: self) } .store(in: &cancellables) createButton .publisher(for: .touchUpInside) .receive(on: DispatchQueue.main) .sink { [unowned self] in coordinator.toGroupDrawer( with: count + 1, from: self, { (name, welcome) in viewModel.create(name: name, welcome: welcome, members: selectedElements) } ) }.store(in: &cancellables) } @objc private func didTapBack() { navigationController?.popViewController(animated: true) } } extension CreateGroupController: UITableViewDelegate { public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let contact = tableDataSource.itemIdentifier(for: indexPath) { viewModel.didSelect(contact: contact) } } public func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { if let contact = tableDataSource.itemIdentifier(for: indexPath) { viewModel.didSelect(contact: contact) } } }