blockchainethereumblockchain-walleterc20erc721walletxdaidappdecentralizederc1155erc875iosswifttokens
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
6.0 KiB
185 lines
6.0 KiB
// Copyright SIX DAY LLC. All rights reserved.
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import StatefulViewController
|
|
import Result
|
|
import TrustKeystore
|
|
|
|
protocol TokensViewControllerDelegate: class {
|
|
func didPressAddToken( in viewController: UIViewController)
|
|
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: Wallet
|
|
let tableView: UITableView
|
|
let refreshControl = UIRefreshControl()
|
|
weak var delegate: TokensViewControllerDelegate?
|
|
|
|
init(
|
|
account: Wallet,
|
|
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
|
|
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)
|
|
|
|
footer.addGestureRecognizer(
|
|
UITapGestureRecognizer(target: self, action: #selector(missingToken))
|
|
)
|
|
|
|
tableView.tableFooterView = footer
|
|
}
|
|
|
|
@objc func missingToken() {
|
|
delegate?.didPressAddToken(in: self)
|
|
}
|
|
}
|
|
|
|
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<TokensViewModel, TokenError>) {
|
|
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)
|
|
}
|
|
}
|
|
|