// // LocationsListViewController.swift // Locations // // Created by Javier Cicchelli on 08/04/2023. // Copyright © 2023 Röck+Cöde. All rights reserved. // import Combine import Core import UIKit class LocationsListViewController: BaseViewController { // MARK: Properties private let viewModel: LocationsListViewModeling private var cancellables: Set = [] // MARK: Outlets private lazy var error = ErrorMessageView() private lazy var loading = LoadingSpinnerView() private lazy var table = { let table = UITableView(frame: .zero, style: .plain) table.dataSource = self table.delegate = self table.translatesAutoresizingMaskIntoConstraints = false return table }() // MARK: Initialisers init(viewModel: LocationsListViewModeling) { self.viewModel = viewModel super.init() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: UIViewController override func viewDidLoad() { super.viewDidLoad() setupBar() setupView() bindViewModel() viewModel.loadLocations() } } // MARK: - UITableViewDataSource extension LocationsListViewController: UITableViewDataSource { // MARK: Functions func numberOfSections(in tableView: UITableView) -> Int { viewModel.numberOfSectionsInData } func tableView( _ tableView: UITableView, numberOfRowsInSection section: Int ) -> Int { viewModel.numberOfDataItems(in: section) } func tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath ) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath) let entity = viewModel.dataItem(at: indexPath) cell.textLabel?.text = entity.name return cell } } // MARK: - UITableViewDelegate extension LocationsListViewController: UITableViewDelegate {} // MARK: - Helpers private extension LocationsListViewController { // MARK: Functions func setupBar() { navigationController?.navigationBar.prefersLargeTitles = true navigationController?.navigationBar.tintColor = .red navigationItem.rightBarButtonItem = .init( title: "Add", style: .plain, target: self, action: #selector(addLocationPressed) ) title = "Locations" } func setupView() { view.addSubview(table) view.addSubview(error) view.addSubview(loading) error.onRetry = { self.viewModel.loadLocations() } table.register(UITableViewCell.self, forCellReuseIdentifier: "cellID") NSLayoutConstraint.activate([ error.widthAnchor.constraint(equalToConstant: 300), view.centerXAnchor.constraint(equalTo: error.centerXAnchor), view.centerYAnchor.constraint(equalTo: error.centerYAnchor), view.centerXAnchor.constraint(equalTo: loading.centerXAnchor), view.centerYAnchor.constraint(equalTo: loading.centerYAnchor), view.bottomAnchor.constraint(equalTo: table.bottomAnchor), view.leadingAnchor.constraint(equalTo: table.leadingAnchor), view.topAnchor.constraint(equalTo: table.topAnchor), view.trailingAnchor.constraint(equalTo: table.trailingAnchor), ]) } func bindViewModel() { viewModel .viewStatusPublisher .receive(on: RunLoop.main) .sink { viewStatus in self.navigationItem.rightBarButtonItem?.isEnabled = viewStatus == .loaded self.error.isHidden = viewStatus != .error self.loading.isHidden = viewStatus != .loading self.table.isHidden = viewStatus != .loaded if viewStatus == .loaded { self.table.reloadData() } } .store(in: &cancellables) } @objc func addLocationPressed() { viewModel.openAddLocation() } }