Style wallet list screen

pull/325/head
Hwee-Boon Yar 7 years ago
parent bd6aba8e57
commit 90a062766e
  1. 37
      Trust/Accounts/ViewModels/AccountViewModel.swift
  2. 109
      Trust/Accounts/ViewModels/AccountsViewController.swift
  3. 126
      Trust/Accounts/Views/AccountViewCell.swift
  4. 7
      TrustTests/Settings/ConfigTests.swift

@ -13,16 +13,45 @@ struct AccountViewModel {
self.current = current
self.walletBalance = walletBalance
}
var isWatch: Bool {
var showWatchIcon: Bool {
return wallet.type == .watch(wallet.address)
}
var balance: String {
return walletBalance?.amountFull ?? "--"
let amount = walletBalance?.amountFull ?? "--"
return "\(amount) ETH"
}
var title: String {
var address: String {
return wallet.address.description
}
var isActive: Bool {
var showActiveIcon: Bool {
return wallet == current
}
var backgroundColor: UIColor {
return Colors.appWhite
}
var contentsBackgroundColor: UIColor {
return backgroundColor
}
var contentsBorderColor: UIColor {
return Colors.appHighlightGreen
}
var contentsBorderWidth: CGFloat {
return 1
}
var balanceFont: UIFont {
return Fonts.light(size: 20)!
}
var addressFont: UIFont {
return Fonts.semibold(size: 12)!
}
var addressTextColor: UIColor {
return Colors.gray
}
}

@ -9,10 +9,13 @@ protocol AccountsViewControllerDelegate: class {
func didSelectInfoForAccount(account: Wallet, sender: UIView, in viewController: AccountsViewController)
}
class AccountsViewController: UITableViewController {
class AccountsViewController: UIViewController {
let headerHeight = CGFloat(70)
weak var delegate: AccountsViewControllerDelegate?
var allowsAccountDeletion: Bool = false
var headerTitle: String?
let roundedBackground = RoundedBackground()
let header = TicketsViewControllerTitleHeader()
let tableView = UITableView(frame: .zero, style: .plain)
var viewModel: AccountsViewModel {
return AccountsViewModel(
wallets: wallets
@ -30,21 +33,41 @@ class AccountsViewController: UITableViewController {
private var balances: [Address: Balance?] = [:]
private let keystore: Keystore
private let balanceCoordinator: GetBalanceCoordinator
init(
keystore: Keystore,
balanceCoordinator: GetBalanceCoordinator
) {
self.keystore = keystore
self.balanceCoordinator = balanceCoordinator
super.init(style: .grouped)
super.init(nibName: nil, bundle: nil)
view.backgroundColor = Colors.appBackground
roundedBackground.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(roundedBackground)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.delegate = self
tableView.separatorStyle = .none
tableView.backgroundColor = Colors.appWhite
tableView.rowHeight = 80
tableView.tableHeaderView = header
tableView.register(AccountViewCell.self, forCellReuseIdentifier: AccountViewCell.identifier)
roundedBackground.addSubview(tableView)
NSLayoutConstraint.activate([
header.heightAnchor.constraint(equalToConstant: headerHeight),
tableView.leadingAnchor.constraint(equalTo: roundedBackground.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: roundedBackground.trailingAnchor),
tableView.topAnchor.constraint(equalTo: roundedBackground.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
] + roundedBackground.createConstraintsWithContainer(view: view))
fetch()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 55
tableView.register(R.nib.accountViewCell(), forCellReuseIdentifier: R.nib.accountViewCell.name)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetch()
@ -54,37 +77,14 @@ class AccountsViewController: UITableViewController {
wallets = keystore.wallets
}
func configure(viewModel: AccountsViewModel) {
title = headerTitle ?? viewModel.title
tableView.dataSource = self
header.configure(title: viewModel.title)
header.frame.size.height = headerHeight
tableView.tableHeaderView = header
}
func account(for indexPath: IndexPath) -> Wallet {
return viewModel.wallets[indexPath.row]
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.wallets.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: R.nib.accountViewCell.name, for: indexPath) as! AccountViewCell
cell.viewModel = getAccountViewModels(for: indexPath)
cell.delegate = self
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return allowsAccountDeletion && (EtherKeystore.current != viewModel.wallets[indexPath.row] || viewModel.wallets.count == 1)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
let account = self.account(for: indexPath)
confirmDelete(account: account)
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let account = self.account(for: indexPath)
delegate?.didSelectAccount(account: account, in: self)
}
func confirmDelete(account: Wallet) {
confirm(
title: R.string.localizable.accountsConfirmDeleteTitle(),
@ -136,6 +136,43 @@ class AccountsViewController: UITableViewController {
fatalError("init(coder:) has not been implemented")
}
}
extension AccountsViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.wallets.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: AccountViewCell.identifier, for: indexPath) as! AccountViewCell
let cellViewModel = getAccountViewModels(for: indexPath)
cell.configure(viewModel: cellViewModel)
cell.account = cellViewModel.wallet
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return allowsAccountDeletion && (EtherKeystore.current != viewModel.wallets[indexPath.row] || viewModel.wallets.count == 1)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
let account = self.account(for: indexPath)
confirmDelete(account: account)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let account = self.account(for: indexPath)
delegate?.didSelectAccount(account: account, in: self)
}
}
extension AccountsViewController: AccountViewCellDelegate {
func accountViewCell(_ cell: AccountViewCell, didTapInfoViewForAccount account: Wallet) {
self.delegate?.didSelectInfoForAccount(account: account, sender: cell.infoButton, in: self)

@ -1,5 +1,4 @@
// Copyright SIX DAY LLC. All rights reserved.
import TrustKeystore
import UIKit
@ -8,33 +7,110 @@ protocol AccountViewCellDelegate: class {
}
class AccountViewCell: UITableViewCell {
@IBOutlet weak var infoButton: UIButton!
@IBOutlet weak var activeView: UIView!
@IBOutlet weak var glassesImageView: UIImageView!
@IBOutlet weak var walletTypeImageView: UIImageView!
@IBOutlet weak var addressLable: UILabel!
@IBOutlet weak var balanceLable: UILabel!
static let identifier = "AccountViewCell"
let background = UIView()
var infoButton = UIButton(type: .infoLight)
var activeIcon = UIImageView(image: R.image.ticket_bundle_checked())
var watchIcon = UIImageView(image: R.image.glasses())
var addressLabel = UILabel()
var balanceLabel = UILabel()
weak var delegate: AccountViewCellDelegate?
var viewModel: AccountViewModel? {
didSet {
guard let model = viewModel else {
return
}
balanceLable.text = "\(model.balance) ETH"
glassesImageView.isHidden = !model.isWatch
activeView.isHidden = !model.isActive
addressLable.text = model.title
infoButton.tintColor = Colors.appBackground
}
var account: Wallet? = nil
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(background)
background.translatesAutoresizingMaskIntoConstraints = false
activeIcon.translatesAutoresizingMaskIntoConstraints = false
activeIcon.contentMode = .scaleAspectFit
balanceLabel.translatesAutoresizingMaskIntoConstraints = false
addressLabel.translatesAutoresizingMaskIntoConstraints = false
addressLabel.lineBreakMode = .byTruncatingMiddle
infoButton.translatesAutoresizingMaskIntoConstraints = false
infoButton.addTarget(self, action: #selector(infoAction), for: .touchUpInside)
let leftStackView = [
balanceLabel,
addressLabel,
].asStackView(axis: .vertical, distribution: .fillProportionally, spacing: 6)
leftStackView.translatesAutoresizingMaskIntoConstraints = false
let rightStackView = [infoButton].asStackView()
rightStackView.translatesAutoresizingMaskIntoConstraints = false
let stackView = [activeIcon, leftStackView, watchIcon, rightStackView].asStackView(spacing: 15, alignment: .center)
stackView.translatesAutoresizingMaskIntoConstraints = false
activeIcon.setContentHuggingPriority(UILayoutPriority.defaultLow, for: .horizontal)
addressLabel.setContentHuggingPriority(UILayoutPriority.defaultLow, for: .horizontal)
balanceLabel.setContentHuggingPriority(UILayoutPriority.defaultLow, for: .horizontal)
infoButton.setContentHuggingPriority(UILayoutPriority.required, for: .horizontal)
infoButton.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
watchIcon.setContentHuggingPriority(UILayoutPriority.required, for: .horizontal)
watchIcon.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
watchIcon.setContentHuggingPriority(UILayoutPriority.required, for: .vertical)
watchIcon.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
stackView.setContentHuggingPriority(UILayoutPriority.required, for: .horizontal)
background.addSubview(stackView)
// TODO extract constant. Maybe StyleLayout.sideMargin
let xMargin = CGFloat(7)
let yMargin = CGFloat(7)
NSLayoutConstraint.activate([
activeIcon.widthAnchor.constraint(equalToConstant: 44),
watchIcon.widthAnchor.constraint(lessThanOrEqualToConstant: 18),
watchIcon.heightAnchor.constraint(lessThanOrEqualToConstant: 18),
stackView.topAnchor.constraint(equalTo: background.topAnchor, constant: StyleLayout.sideMargin),
stackView.trailingAnchor.constraint(equalTo: background.trailingAnchor, constant: -StyleLayout.sideMargin),
stackView.bottomAnchor.constraint(equalTo: background.bottomAnchor, constant: -StyleLayout.sideMargin),
stackView.leadingAnchor.constraint(equalTo: background.leadingAnchor, constant: StyleLayout.sideMargin),
background.leadingAnchor.constraint(equalTo: leadingAnchor, constant: xMargin),
background.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -xMargin),
background.topAnchor.constraint(equalTo: topAnchor, constant: yMargin),
background.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -yMargin),
])
}
override func prepareForReuse() {
super.prepareForReuse()
self.viewModel = nil
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@IBAction func infoAction(_ sender: Any) {
guard let account = viewModel?.wallet else {
return
}
@objc func infoAction() {
guard let account = account else { return }
delegate?.accountViewCell(self, didTapInfoViewForAccount: account)
}
func configure(viewModel: AccountViewModel) {
selectionStyle = .none
backgroundColor = viewModel.backgroundColor
background.backgroundColor = viewModel.contentsBackgroundColor
background.layer.cornerRadius = 20
background.borderColor = viewModel.contentsBorderColor
background.borderWidth = viewModel.contentsBorderWidth
activeIcon.isHidden = !viewModel.showActiveIcon
balanceLabel.font = viewModel.balanceFont
balanceLabel.text = viewModel.balance
addressLabel.font = viewModel.addressFont
addressLabel.textColor = viewModel.addressTextColor
addressLabel.text = viewModel.address
infoButton.tintColor = Colors.appBackground
watchIcon.isHidden = !viewModel.showWatchIcon
}
}

@ -57,9 +57,10 @@ class ConfigTests: XCTestCase {
config.locale = AppLocale.english.id
config.locale = AppLocale.simplifiedChinese.id
let controller = AccountsViewController(keystore: FakeKeystore(), balanceCoordinator: FakeGetBalanceCoordinator())
let _ = controller.view
XCTAssertNoThrow(controller.tableView.dequeueReusableCell(withIdentifier: R.nib.accountViewCell.name, for: .init(row: 0, section: 0)))
let tableView = UITableView()
tableView.register(R.nib.editTokenTableViewCell(), forCellReuseIdentifier: R.nib.editTokenTableViewCell.name)
XCTAssertNoThrow(tableView.dequeueReusableCell(withIdentifier: R.nib.editTokenTableViewCell.name))
//Must change this back to system, otherwise other tests will break either immediately or the next run
config.locale = AppLocale.system.id

Loading…
Cancel
Save