Something went wrong on our end
-
Bruno Muniz authoredBruno Muniz authored
ChatListController.swift 7.89 KiB
import UIKit
import Shared
import Combine
import XXModels
import MenuFeature
import XXNavigation
import DI
public final class ChatListController: UIViewController {
@Dependency var navigator: Navigator
@Dependency var barStylist: StatusBarStylist
private lazy var screenView = ChatListView()
private lazy var topLeftView = ChatListTopLeftNavView()
private lazy var topRightView = ChatListTopRightNavView()
private lazy var tableController = ChatListTableController(viewModel)
private lazy var searchTableController = ChatSearchTableController(viewModel)
private var collectionDataSource: UICollectionViewDiffableDataSource<SectionId, Contact>!
private let viewModel = ChatListViewModel()
private var cancellables = Set<AnyCancellable>()
private var drawerCancellables = Set<AnyCancellable>()
private var isEditingSearch = false {
didSet {
screenView.listContainerView
.showRecentsCollection(isEditingSearch ? false : shouldBeShowingRecents)
}
}
private var shouldBeShowingRecents = false {
didSet {
screenView.listContainerView
.showRecentsCollection(isEditingSearch ? false : shouldBeShowingRecents)
}
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
navigationItem.backButtonTitle = ""
}
required init?(coder: NSCoder) { nil }
public override func loadView() {
view = screenView
}
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
barStylist.styleSubject.send(.darkContent)
navigationController?.navigationBar.customize(backgroundColor: Asset.neutralWhite.color)
}
public override func viewDidLoad() {
super.viewDidLoad()
setupChatList()
setupBindings()
setupNavigationBar()
setupRecentContacts()
}
private func setupNavigationBar() {
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: topLeftView)
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: topRightView)
topRightView
.actionPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
switch $0 {
case .didTapSearch:
navigator.perform(PresentSearch(replacing: false))
case .didTapNewGroup:
navigator.perform(PresentNewGroup())
}
}.store(in: &cancellables)
viewModel
.badgeCountPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
topLeftView.updateBadge($0)
}.store(in: &cancellables)
topLeftView
.actionPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
navigator.perform(PresentMenu(currentItem: .chats))
}.store(in: &cancellables)
}
private func setupChatList() {
addChild(tableController)
addChild(searchTableController)
screenView.listContainerView.addSubview(tableController.view)
screenView.searchListContainerView.addSubview(searchTableController.view)
tableController.view.snp.makeConstraints {
$0.top.equalTo(screenView.listContainerView.collectionContainerView.snp.bottom)
$0.left.equalToSuperview()
$0.right.equalToSuperview()
$0.bottom.equalToSuperview()
}
searchTableController.view.snp.makeConstraints {
$0.top.equalToSuperview()
$0.left.equalToSuperview()
$0.right.equalToSuperview()
$0.bottom.equalToSuperview()
}
tableController.didMove(toParent: self)
searchTableController.didMove(toParent: self)
}
private func setupRecentContacts() {
screenView
.listContainerView
.collectionView
.register(ChatListRecentContactCell.self)
collectionDataSource = UICollectionViewDiffableDataSource<SectionId, Contact>(
collectionView: screenView.listContainerView.collectionView
) { collectionView, indexPath, contact in
let cell: ChatListRecentContactCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
let title = (contact.nickname ?? contact.username) ?? ""
cell.setup(title: title, image: contact.photo)
return cell
}
screenView.listContainerView.collectionView.delegate = self
screenView.listContainerView.collectionView.dataSource = collectionDataSource
viewModel
.recentsPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
collectionDataSource.apply($0)
shouldBeShowingRecents = $0.numberOfItems > 0
}.store(in: &cancellables)
}
private func setupBindings() {
screenView
.searchView
.rightPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
navigator.perform(PresentScan())
}.store(in: &cancellables)
screenView
.searchView
.textPublisher
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [unowned self] query in
viewModel.updateSearch(query: query)
screenView.searchListContainerView.emptyView.updateSearched(content: query)
}.store(in: &cancellables)
Publishers.CombineLatest(
viewModel.searchPublisher,
screenView.searchView.textPublisher.removeDuplicates()
)
.receive(on: DispatchQueue.main)
.sink { [unowned self] items, query in
guard query.isEmpty == false else {
screenView.searchListContainerView.isHidden = true
screenView.listContainerView.isHidden = false
screenView.bringSubviewToFront(screenView.listContainerView)
return
}
screenView.listContainerView.isHidden = true
screenView.searchListContainerView.isHidden = false
guard items.numberOfItems > 0 else {
screenView.searchListContainerView.emptyView.isHidden = false
screenView.bringSubviewToFront(screenView.searchListContainerView)
screenView.searchListContainerView.bringSubviewToFront(screenView.searchListContainerView.emptyView)
return
}
screenView.searchListContainerView.bringSubviewToFront(searchTableController.view)
screenView.searchListContainerView.emptyView.isHidden = true
}.store(in: &cancellables)
screenView
.searchView
.isEditingPublisher
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
isEditingSearch = $0
}.store(in: &cancellables)
viewModel
.chatsPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
guard $0.isEmpty == false else {
screenView.listContainerView.bringSubviewToFront(screenView.listContainerView.emptyView)
screenView.listContainerView.emptyView.isHidden = false
return
}
screenView.listContainerView.bringSubviewToFront(tableController.view)
screenView.listContainerView.emptyView.isHidden = true
}.store(in: &cancellables)
screenView
.searchListContainerView
.emptyView
.searchButton
.publisher(for: .touchUpInside)
.sink { [unowned self] in
navigator.perform(PresentSearch(replacing: false))
}.store(in: &cancellables)
screenView
.listContainerView
.emptyView
.contactsButton
.publisher(for: .touchUpInside)
.receive(on: DispatchQueue.main)
.sink { [unowned self] in
navigator.perform(PresentContactList())
}.store(in: &cancellables)
viewModel
.isOnline
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [weak screenView] connected in
screenView?.showConnectingBanner(!connected)
}.store(in: &cancellables)
}
}
extension ChatListController: UICollectionViewDelegate {
public func collectionView(
_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath
) {
if let contact = collectionDataSource.itemIdentifier(for: indexPath) {
navigator.perform(PresentChat(contact: contact))
}
}
}