// Copyright SIX DAY LLC. All rights reserved. import Foundation import UIKit import StatefulViewController import Result protocol TokensViewControllerDelegate: class { func didSelect(token: TokenObject, in viewController: UIViewController) func didDelete(token: TokenObject, in viewController: UIViewController) } class TokensViewController: UIViewController { private let dataStore: TokensDataStore var viewModel: TokensViewModel = TokensViewModel(tokens: [], tickers: .none) { didSet { refreshView(viewModel: viewModel) } } let account: Account let tableView: UITableView let refreshControl = UIRefreshControl() weak var delegate: TokensViewControllerDelegate? init( account: Account, dataStore: TokensDataStore ) { self.account = account self.dataStore = dataStore tableView = UITableView(frame: .zero, style: .plain) super.init(nibName: nil, bundle: nil) dataStore.delegate = self tableView.translatesAutoresizingMaskIntoConstraints = false tableView.delegate = self tableView.dataSource = self tableView.separatorStyle = .none tableView.backgroundColor = .white tableView.rowHeight = 72 view.addSubview(tableView) NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), ]) refreshControl.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged) tableView.addSubview(refreshControl) errorView = ErrorView(onRetry: fetch) loadingView = LoadingView() emptyView = EmptyView( title: NSLocalizedString("emptyView.noTokens.label.title", value: "You haven't received any tokens yet!", comment: ""), onRetry: fetch ) refreshView(viewModel: viewModel) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) fetch() } @objc func pullToRefresh() { refreshControl.beginRefreshing() fetch() } func fetch() { startLoading() dataStore.fetch() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func refreshView(viewModel: TokensViewModel) { title = viewModel.title view.backgroundColor = viewModel.backgroundColor let header = TokensHeaderView(frame: .zero) header.amountLabel.text = viewModel.headerBalance header.amountLabel.textColor = viewModel.headerBalanceTextColor header.backgroundColor = viewModel.headerBackgroundColor header.amountLabel.font = viewModel.headerBalanceFont header.frame.size = header.systemLayoutSizeFitting(UILayoutFittingExpandedSize) tableView.tableHeaderView = header let footer = TokensFooterView(frame: .zero) footer.textLabel.text = viewModel.footerTitle footer.textLabel.font = viewModel.footerTextFont footer.textLabel.textColor = viewModel.footerTextColor footer.frame.size = header.systemLayoutSizeFitting(UILayoutFittingExpandedSize) tableView.tableFooterView = footer } } extension TokensViewController: StatefulViewController { func hasContent() -> Bool { return viewModel.hasContent } } extension TokensViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let token = viewModel.item(for: indexPath.row, section: indexPath.section) delegate?.didSelect(token: token, in: self) } func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return viewModel.canDelete(for: indexPath.row, section: indexPath.section) } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == UITableViewCellEditingStyle.delete { delegate?.didDelete(token: viewModel.item(for: indexPath.row, section: indexPath.section), in: self) } } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 80 } } extension TokensViewController: TokensDataStoreDelegate { func didUpdate(result: Result) { switch result { case .success(let viewModel): self.viewModel = viewModel endLoading() case .failure(let error): endLoading(error: error) } tableView.reloadData() if refreshControl.isRefreshing { refreshControl.endRefreshing() } } } extension TokensViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return viewModel.numberOfSections } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let token = viewModel.item(for: indexPath.row, section: indexPath.section) let cell = TokenViewCell(style: .default, reuseIdentifier: TokenViewCell.identifier) cell.configure( viewModel: .init( token: token, ticker: viewModel.ticker(for: token) ) ) return cell } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return viewModel.numberOfItems(for: section) } }