Skip to content
Snippets Groups Projects
CreateGroupController.swift 7.03 KiB
Newer Older
Bruno Muniz's avatar
Bruno Muniz committed
import HUD
import UIKit
import Models
import Shared
import Combine
import XXModels
Bruno Muniz's avatar
Bruno Muniz committed
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)
Bruno Muniz's avatar
Bruno Muniz committed
        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)

Bruno Muniz's avatar
Bruno Muniz committed
            let title = (contact.nickname ?? contact.username) ?? ""
            cell.setup(title: title, image: contact.photo)
Bruno Muniz's avatar
Bruno Muniz committed
            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)
Bruno Muniz's avatar
Bruno Muniz committed
            let title = (contact.nickname ?? contact.username) ?? ""

            cell.setup(title: title, image: contact.photo)
Bruno Muniz's avatar
Bruno Muniz committed

            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(
Bruno Muniz's avatar
Bruno Muniz committed
                    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)
        }
    }
}