Work in progress for integrating exchange

pull/2/head
Michael Scoff 7 years ago
parent 236dc2bd4b
commit 862c070033
  1. 16
      Trust.xcodeproj/project.pbxproj
  2. 21
      Trust/Assets.xcassets/chevron-right.imageset/Contents.json
  3. BIN
      Trust/Assets.xcassets/chevron-right.imageset/chevron-right.png
  4. 41
      Trust/Exchange/ViewControllers/ExchangeViewController.swift
  5. 5
      Trust/Exchange/ViewControllers/SelectTokenViewController.swift
  6. 32
      Trust/Exchange/ViewModels/ExchangeTokensViewModel.swift
  7. 112
      Trust/Exchange/Views/ExchangeTokenInputField.swift
  8. 65
      Trust/Exchange/Views/ExchangeTokensField.swift
  9. 6
      Trust/Extensions/UIView.swift
  10. 1
      Trust/Style/AppStyle.swift
  11. 2
      Trust/Transfer/Controllers/RequestViewController.swift

@ -66,6 +66,8 @@
293112171FC5555500966EEA /* ExchangeTokensViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293112161FC5555500966EEA /* ExchangeTokensViewModel.swift */; };
293112191FC55E5500966EEA /* SelectTokenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293112181FC55E5500966EEA /* SelectTokenViewController.swift */; };
2931121B1FC560E500966EEA /* ExchangeTokenTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931121A1FC560E500966EEA /* ExchangeTokenTableViewCell.swift */; };
2931121D1FC65F2900966EEA /* ExchangeCurrencyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931121C1FC65F2900966EEA /* ExchangeCurrencyView.swift */; };
293112201FC6619000966EEA /* ExchangeToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931121F1FC6619000966EEA /* ExchangeToken.swift */; };
293204581F8DC6B20095B7C1 /* ExchangeRateCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293204571F8DC6B20095B7C1 /* ExchangeRateCoordinator.swift */; };
2932045C1F8DCD6E0095B7C1 /* CurrencyRate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2932045B1F8DCD6E0095B7C1 /* CurrencyRate.swift */; };
2932045E1F8EEE760095B7C1 /* BalanceCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2932045D1F8EEE760095B7C1 /* BalanceCoordinator.swift */; };
@ -324,6 +326,8 @@
293112161FC5555500966EEA /* ExchangeTokensViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangeTokensViewModel.swift; sourceTree = "<group>"; };
293112181FC55E5500966EEA /* SelectTokenViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectTokenViewController.swift; sourceTree = "<group>"; };
2931121A1FC560E500966EEA /* ExchangeTokenTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangeTokenTableViewCell.swift; sourceTree = "<group>"; };
2931121C1FC65F2900966EEA /* ExchangeCurrencyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangeCurrencyView.swift; sourceTree = "<group>"; };
2931121F1FC6619000966EEA /* ExchangeToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangeToken.swift; sourceTree = "<group>"; };
293204571F8DC6B20095B7C1 /* ExchangeRateCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangeRateCoordinator.swift; sourceTree = "<group>"; };
2932045B1F8DCD6E0095B7C1 /* CurrencyRate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyRate.swift; sourceTree = "<group>"; };
2932045D1F8EEE760095B7C1 /* BalanceCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceCoordinator.swift; sourceTree = "<group>"; };
@ -854,6 +858,14 @@
path = ViewModels;
sourceTree = "<group>";
};
2931121E1FC6618800966EEA /* Types */ = {
isa = PBXGroup;
children = (
2931121F1FC6619000966EEA /* ExchangeToken.swift */,
);
path = Types;
sourceTree = "<group>";
};
293248881F88D586008A9818 /* Types */ = {
isa = PBXGroup;
children = (
@ -1152,6 +1164,7 @@
298543011FC15F5300CB5081 /* Exchange */ = {
isa = PBXGroup;
children = (
2931121E1FC6618800966EEA /* Types */,
2985430D1FC18A3C00CB5081 /* ViewModels */,
298543081FC1888700CB5081 /* Views */,
298543051FC15FA200CB5081 /* ViewControllers */,
@ -1184,6 +1197,7 @@
2985430B1FC188D200CB5081 /* ExchangeTokensField.swift */,
298543091FC188A700CB5081 /* ExchangeTokenInputField.swift */,
2931121A1FC560E500966EEA /* ExchangeTokenTableViewCell.swift */,
2931121C1FC65F2900966EEA /* ExchangeCurrencyView.swift */,
);
path = Views;
sourceTree = "<group>";
@ -1924,6 +1938,7 @@
290B2B5F1F9177860053C83E /* UIImage.swift in Sources */,
291F52B21F6B814300B369AB /* MG Benchmark Tools.swift in Sources */,
291ED08F1F6F613200E7E93A /* GetTransactionRequest.swift in Sources */,
2931121D1FC65F2900966EEA /* ExchangeCurrencyView.swift in Sources */,
293112171FC5555500966EEA /* ExchangeTokensViewModel.swift in Sources */,
295A59381F71C1B90092F0FC /* AccountsCoordinator.swift in Sources */,
296421971F70C1F200EB363B /* ErrorView.swift in Sources */,
@ -2054,6 +2069,7 @@
29850D2B1F6B30FF00791A49 /* TransactionViewController.swift in Sources */,
29C80D411FB2E1610037B1E0 /* EthplorerService.swift in Sources */,
296AF9AB1F7380920058AF78 /* GetTransactionCountRequest.swift in Sources */,
293112201FC6619000966EEA /* ExchangeToken.swift in Sources */,
298542F51FBD8E6A00CB5081 /* ConfigExplorer.swift in Sources */,
29A13E2C1F6A955700E432A2 /* CreateWalletViewModel.swift in Sources */,
29C80D4F1FB520AF0037B1E0 /* BalanceTokenViewModel.swift in Sources */,

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "chevron-right.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

@ -7,28 +7,35 @@ class ExchangeViewController: UIViewController {
private let viewModel = ExchangeViewModel()
let exchangeFields = ExchangeTokensField()
let currencyView = ExchangeCurrencyView()
let coordinator = ExchangeToksnCoordinator()
init() {
super.init(nibName: nil, bundle: nil)
exchangeFields.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(exchangeFields)
let stackView = UIStackView(arrangedSubviews: [
exchangeFields,
.spacer(height: 20),
currencyView,
])
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
NSLayoutConstraint.activate([
exchangeFields.topAnchor.constraint(equalTo: view.layoutGuide.topAnchor, constant: 20),
exchangeFields.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
exchangeFields.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
stackView.topAnchor.constraint(equalTo: view.layoutGuide.topAnchor, constant: 20),
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
stackView.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -20),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
])
exchangeFields.didPressSwap = { [unowned self] in
self.coordinator.swap()
}
exchangeFields.didPressFrom = { [unowned self] in
self.showSelectToken(direction: .from)
exchangeFields.didPress = { [unowned self] direction in
self.showSelectToken(direction: direction)
}
exchangeFields.didPressTo = { [unowned self] in
self.showSelectToken(direction: .to)
exchangeFields.didPressAvailableBalance = { [unowned self] _ in
self.exchangeFields.fromField.amountField.text = "\(self.coordinator.viewModel.availableBalance)"
}
coordinator.didUpdate = { [weak self] viewModel in
@ -39,11 +46,18 @@ class ExchangeViewController: UIViewController {
view.backgroundColor = viewModel.backgroundColor
navigationItem.title = viewModel.title
exchangeFields.backgroundColor = .white
}
func configure(viewModel: ExchangeTokensViewModel) {
exchangeFields.to.symbolLabel.text = viewModel.toSymbol
exchangeFields.from.symbolLabel.text = viewModel.fromSymbol
exchangeFields.fromField.symbolLabel.text = viewModel.fromSymbol
exchangeFields.toField.symbolLabel.text = viewModel.toSymbol
exchangeFields.fromField.backgroundColor = Colors.veryLightGray
exchangeFields.toField.backgroundColor = Colors.veryLightGray
exchangeFields.availableBalanceLabel.attributedText = viewModel.attributedAvailableBalance
currencyView.currencyLabel.attributedText = viewModel.attributedCurrency
}
func showSelectToken(direction: SelectTokenDirection) {
@ -63,5 +77,6 @@ class ExchangeViewController: UIViewController {
extension ExchangeViewController: SelectTokenViewControllerDelegate {
func didSelect(token: ExchangeToken, in viewController: SelectTokenViewController) {
coordinator.changeToken(direction: viewController.direction, token: token)
navigationController?.popViewController(animated: true)
}
}

@ -54,11 +54,6 @@ class SelectTokenViewController: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let token = tokens[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
NSLog("didSelectRowAt \(token)")
delegate?.didSelect(token: token, in: self)
navigationController?.popViewController(animated: true)
}
}

@ -1,12 +1,8 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
struct ExchangeToken {
let name: String
let symbol: String
let balance: Double
}
import UIKit
import BonMot
struct ExchangeTokensViewModel {
@ -28,4 +24,28 @@ struct ExchangeTokensViewModel {
var toSymbol: String {
return to.symbol
}
var attributedCurrency: NSAttributedString {
let baseStyle = StringStyle(
.lineHeightMultiple(1.2),
.font(UIFont.systemFont(ofSize: 15))
)
let greenStyle = baseStyle.byAdding(.color(Colors.green))
let conversationString = "1 \(fromSymbol) = 0.017648 \(toSymbol) ".styled(with: baseStyle)
let percentString = "(-%)".styled(with: greenStyle)
return (conversationString + percentString).styled(with: .alignment(.center))
}
var availableBalance: Double {
return 2.22
}
var attributedAvailableBalance: NSAttributedString {
return NSAttributedString(
string: "Available \(availableBalance) \(fromSymbol)",
attributes: [:]
)
}
}

@ -4,13 +4,10 @@ import UIKit
class ExchangeTokenInputField: UIView {
let floatLabelView = UIView()
let destinationLabel = UILabel()
let amountField = UITextField()
let tokenView = UIView()
let tokenImageView = UIImageView()
let symbolLabel = UILabel()
let chevronDownImageView = UIImageView(image: R.image.chevronRight())
var didPress: (() -> Void)?
@ -18,100 +15,75 @@ class ExchangeTokenInputField: UIView {
super.init(frame: .zero)
// value
floatLabelView.translatesAutoresizingMaskIntoConstraints = false
destinationLabel.translatesAutoresizingMaskIntoConstraints = false
amountField.translatesAutoresizingMaskIntoConstraints = false
amountField.backgroundColor = .red
amountField.font = UIFont.systemFont(ofSize: 26, weight: UIFontWeightMedium)
let inputStackView = UIStackView(arrangedSubviews: [
destinationLabel,
amountField,
])
inputStackView.translatesAutoresizingMaskIntoConstraints = false
inputStackView.axis = .vertical
inputStackView.spacing = 5
addSubview(floatLabelView)
floatLabelView.addSubview(inputStackView)
NSLayoutConstraint.activate([
inputStackView.centerYAnchor.constraint(equalTo: floatLabelView.centerYAnchor),
inputStackView.leadingAnchor.constraint(equalTo: floatLabelView.leadingAnchor),
inputStackView.trailingAnchor.constraint(equalTo: floatLabelView.trailingAnchor, constant: -15),
floatLabelView.topAnchor.constraint(equalTo: topAnchor),
floatLabelView.leadingAnchor.constraint(equalTo: leadingAnchor),
floatLabelView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
// token view
amountField.placeholder = "0"
amountField.font = UIFont.systemFont(ofSize: 22, weight: UIFontWeightMedium)
symbolLabel.translatesAutoresizingMaskIntoConstraints = false
symbolLabel.textAlignment = .center
symbolLabel.text = "ETH"
symbolLabel.font = UIFont.systemFont(ofSize: 16, weight: UIFontWeightMedium)
symbolLabel.adjustsFontSizeToFitWidth = true
tokenImageView.translatesAutoresizingMaskIntoConstraints = false
tokenImageView.image = R.image.accounts_active()
tokenImageView.contentMode = .scaleAspectFit
chevronDownImageView.translatesAutoresizingMaskIntoConstraints = false
chevronDownImageView.contentMode = .scaleAspectFit
chevronDownImageView.alpha = 0.5
tokenView.translatesAutoresizingMaskIntoConstraints = false
tokenView.backgroundColor = .green
let divider: UIView = .spacerWidth(1, backgroundColor: .lightGray)
let tokenStackView = UIStackView(arrangedSubviews: [
tokenImageView,
symbolLabel,
chevronDownImageView,
])
tokenStackView.translatesAutoresizingMaskIntoConstraints = false
tokenStackView.axis = .vertical
tokenStackView.axis = .horizontal
tokenStackView.spacing = 5
tokenView.addSubview(tokenStackView)
addSubview(tokenView)
let stackView = UIStackView(arrangedSubviews: [
amountField,
divider,
tokenStackView,
])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.alignment = .center
stackView.spacing = 5
addSubview(stackView)
let chevronDownImageView = UIImageView(image: R.image.chevronDown())
chevronDownImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: StyleLayout.sideMargin),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -StyleLayout.sideMargin),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
stackView.heightAnchor.constraint(equalToConstant: 60),
tokenView.addSubview(chevronDownImageView)
amountField.widthAnchor.constraint(equalToConstant: 120),
NSLayoutConstraint.activate([
tokenStackView.centerXAnchor.constraint(equalTo: tokenView.centerXAnchor),
tokenStackView.centerYAnchor.constraint(equalTo: tokenView.centerYAnchor),
symbolLabel.widthAnchor.constraint(equalToConstant: 50),
tokenView.topAnchor.constraint(equalTo: topAnchor),
tokenView.trailingAnchor.constraint(equalTo: trailingAnchor),
tokenView.bottomAnchor.constraint(equalTo: bottomAnchor),
tokenView.widthAnchor.constraint(equalToConstant: 100),
tokenView.leadingAnchor.constraint(equalTo: floatLabelView.trailingAnchor),
divider.topAnchor.constraint(equalTo: topAnchor, constant: StyleLayout.sideMargin),
divider.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -StyleLayout.sideMargin),
chevronDownImageView.leadingAnchor.constraint(equalTo: tokenStackView.trailingAnchor),
chevronDownImageView.centerYAnchor.constraint(equalTo: tokenStackView.centerYAnchor),
tokenImageView.heightAnchor.constraint(equalToConstant: 36),
tokenImageView.widthAnchor.constraint(equalToConstant: 36),
chevronDownImageView.centerYAnchor.constraint(equalTo: stackView.centerYAnchor),
chevronDownImageView.heightAnchor.constraint(equalToConstant: 12),
chevronDownImageView.widthAnchor.constraint(equalToConstant: 12),
])
// main stack
let stackView = UIStackView(arrangedSubviews: [
floatLabelView,
tokenView,
])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.addGestureRecognizer(
tokenStackView.addGestureRecognizer(
UITapGestureRecognizer(target: self, action: #selector(self.tap))
)
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
stackView.heightAnchor.constraint(equalToConstant: 100),
])
layer.cornerRadius = 5
layer.masksToBounds = true
}
func tap() {

@ -4,58 +4,63 @@ import UIKit
class ExchangeTokensField: UIView {
let from = ExchangeTokenInputField()
let to = ExchangeTokenInputField()
let swapButton = UIButton()
var didPressSwap: (() -> Void)?
var didPressTo: (() -> Void)?
var didPressFrom: (() -> Void)?
let fromField = ExchangeTokenInputField()
let toField = ExchangeTokenInputField()
lazy var availableBalanceLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.addGestureRecognizer(
UITapGestureRecognizer(target: self, action: #selector(self.availableBalance))
)
label.isUserInteractionEnabled = true
return label
}()
var didPress: ((SelectTokenDirection) -> Void)?
var didPressAvailableBalance: (() -> Void)?
init() {
super.init(frame: .zero)
from.translatesAutoresizingMaskIntoConstraints = false
from.destinationLabel.text = "You send"
to.translatesAutoresizingMaskIntoConstraints = false
to.destinationLabel.text = "You get"
swapButton.translatesAutoresizingMaskIntoConstraints = false
swapButton.setImage(R.image.swap(), for: .normal)
swapButton.addTarget(self, action: #selector(swap), for: .touchUpInside)
swapButton.layer.cornerRadius = 20
swapButton.backgroundColor = .white
fromField.translatesAutoresizingMaskIntoConstraints = false
toField.translatesAutoresizingMaskIntoConstraints = false
let stackView = UIStackView(arrangedSubviews: [
from,
to,
destinationLabel(text: "From"),
fromField,
availableBalanceLabel,
.spacer(height: 0),
destinationLabel(text: "To"),
toField,
])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = 10
stackView.axis = .vertical
from.didPress = { [unowned self] in self.didPressFrom?() }
to.didPress = { [unowned self] in self.didPressTo?() }
fromField.didPress = { [unowned self] in self.didPress?(.from) }
toField.didPress = { [unowned self] in self.didPress?(.to) }
addSubview(stackView)
addSubview(swapButton)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
swapButton.centerYAnchor.constraint(equalTo: stackView.centerYAnchor),
swapButton.trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: -80),
swapButton.widthAnchor.constraint(equalToConstant: 40),
swapButton.heightAnchor.constraint(equalToConstant: 40),
])
}
func swap() {
didPressSwap?()
private func destinationLabel(text: String) -> UILabel {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = text
return label
}
func availableBalance() {
didPressAvailableBalance?()
}
required init?(coder aDecoder: NSCoder) {

@ -29,18 +29,20 @@ extension UIView {
}
}
static func spacer(height: CGFloat = 1) -> UIView {
static func spacer(height: CGFloat = 1, backgroundColor: UIColor = .clear) -> UIView {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = backgroundColor
NSLayoutConstraint.activate([
view.heightAnchor.constraint(equalToConstant: height),
])
return view
}
static func spacerWidth(_ width: CGFloat = 1) -> UIView {
static func spacerWidth(_ width: CGFloat = 1, backgroundColor: UIColor = .clear) -> UIView {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = backgroundColor
NSLayoutConstraint.activate([
view.widthAnchor.constraint(equalToConstant: width),

@ -25,6 +25,7 @@ struct Colors {
static let veryLightOrange = UIColor(hex: "FFECC9")
static let green = UIColor(hex: "2fbb4f")
static let lightGray = UIColor.lightGray
static let veryLightGray = UIColor(hex: "F6F6F6")
static let gray = UIColor.gray
static let darkGray = UIColor(hex: "606060")
static let black = UIColor(hex: "313849")

@ -106,7 +106,7 @@ class RequestViewController: UIViewController {
func changeQRCode(value: Int) {
let string = "\(account.address.address)"
// EIP67 format not being used much yet, use hex value for now
// let string = "ethereum:\(account.address.address)?value=\(value)"

Loading…
Cancel
Save