Skip to content

Commit

Permalink
New ImageView class for loading and showing Erc20 Coin icons (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
ealymbaev committed Feb 5, 2019
1 parent 0dca9d7 commit 74ffbda
Show file tree
Hide file tree
Showing 16 changed files with 99 additions and 21 deletions.
14 changes: 14 additions & 0 deletions BankWallet/BankWallet.xcodeproj/project.pbxproj
Expand Up @@ -137,6 +137,7 @@
11B357FE4C2E1EC8E26ED68F /* GrdbStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A1AE56A94BEB52AC4D1 /* GrdbStorage.swift */; };
11B357FF0E2440D91193C476 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3535DD03F9264351E13A9 /* NetworkManager.swift */; };
11B35807029DA6882DBAAF0C /* BarsProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A686DD5BA335FEB6BEB /* BarsProgressView.swift */; };
11B3580BECA360DE35E89286 /* CoinIconImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D8D844E5AE5C73A6EB8 /* CoinIconImageView.swift */; };
11B358174F4EECAD3CE3F293 /* BaseCurrencySettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B7A44754508AEFDA9FD /* BaseCurrencySettingsPresenter.swift */; };
11B3581B212DB1B428F85501 /* Rate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BBAAAE1A3981B902E89 /* Rate.swift */; };
11B3581B5F15B9F806F1CA8F /* BaseCurrencySettingsPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359DA37B619C35AF93D2A /* BaseCurrencySettingsPresenterTests.swift */; };
Expand All @@ -160,6 +161,7 @@
11B358EE1CB9C9740B526364 /* UnlinkConfirmationAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F86873099E095869F7C /* UnlinkConfirmationAlertModel.swift */; };
11B358EF9A56A05015181CA7 /* BalanceHeaderViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D1D60E1D0A206C70490 /* BalanceHeaderViewItem.swift */; };
11B35901F6922FADADD0CC87 /* SendAddressItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35F54E966E33C901B1736 /* SendAddressItem.swift */; };
11B3590CC5D7FB68ED00F7B7 /* CoinIconImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D8D844E5AE5C73A6EB8 /* CoinIconImageView.swift */; };
11B3590F4A4B907B7B6CD080 /* RestoreInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B354E15658C8BF7D5268D9 /* RestoreInteractor.swift */; };
11B3592A6233A57BED217BD8 /* TransactionViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357776F706C10E8B14C4E /* TransactionViewItem.swift */; };
11B359418FEEF9A492482C73 /* SendConfirmationValueItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35BD5DC556C46CC3893B0 /* SendConfirmationValueItemView.swift */; };
Expand Down Expand Up @@ -227,6 +229,7 @@
11B35D0542ACB56A31C61143 /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3572B7C2F16CD51F37FF0 /* UIImage.swift */; };
11B35D0A9EA408E35FF7062F /* CurrencyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3598F5529D0939EE53A19 /* CurrencyManager.swift */; };
11B35D1E39102FA5DAA9F974 /* LaunchRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C7DCF9B7894F7600623 /* LaunchRouter.swift */; };
11B35D3A74237CE0B77295B6 /* CoinIconImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35D8D844E5AE5C73A6EB8 /* CoinIconImageView.swift */; };
11B35D5C9C08AA5221DDE773 /* TransactionRecordPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3B491E521F1ECC600DAE203 /* TransactionRecordPool.swift */; };
11B35D77A40B7BCA0F7D4ECE /* SendPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35DC75FCA42F7A5FB1E65 /* SendPresenterTests.swift */; };
11B35D7FBD8CBF3D92A03EFF /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35FD3263E331D704EA771 /* Signal.swift */; };
Expand Down Expand Up @@ -1196,6 +1199,7 @@
11B35D1D60E1D0A206C70490 /* BalanceHeaderViewItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceHeaderViewItem.swift; sourceTree = "<group>"; };
11B35D66E95B16C32E3796E8 /* BackupRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupRouter.swift; sourceTree = "<group>"; };
11B35D7125090E2FF868F924 /* BalanceViewItemFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceViewItemFactory.swift; sourceTree = "<group>"; };
11B35D8D844E5AE5C73A6EB8 /* CoinIconImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinIconImageView.swift; sourceTree = "<group>"; };
11B35DC131F98F9EEC864BCA /* OptionalSubject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalSubject.swift; sourceTree = "<group>"; };
11B35DC5A4019EA28C92B1E7 /* BalanceModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BalanceModule.swift; sourceTree = "<group>"; };
11B35DC75FCA42F7A5FB1E65 /* SendPresenterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendPresenterTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1632,6 +1636,7 @@
11B35492B1162F69CA7A0597 /* DateHelper.swift */,
11B354B43B5120F594318FDA /* PermissionsHelper.swift */,
11B35EFB45ECC2D403CA6C89 /* ValueFormatter.swift */,
11B35D8D844E5AE5C73A6EB8 /* CoinIconImageView.swift */,
);
path = UserInterface;
sourceTree = "<group>";
Expand Down Expand Up @@ -2773,6 +2778,7 @@
inputPaths = (
"${SRCROOT}/../Pods/Target Support Files/Pods-Bank Dev/Pods-Bank Dev-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework",
"${BUILT_PRODUCTS_DIR}/BigInt/BigInt.framework",
"${BUILT_PRODUCTS_DIR}/GRDB.swift/GRDB.framework",
"${BUILT_PRODUCTS_DIR}/GrouviActionSheet/GrouviActionSheet.framework",
Expand All @@ -2799,6 +2805,7 @@
);
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BigInt.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GrouviActionSheet.framework",
Expand Down Expand Up @@ -2835,6 +2842,7 @@
inputPaths = (
"${SRCROOT}/../Pods/Target Support Files/Pods-Bank Dev T/Pods-Bank Dev T-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework",
"${BUILT_PRODUCTS_DIR}/BigInt/BigInt.framework",
"${BUILT_PRODUCTS_DIR}/GRDB.swift/GRDB.framework",
"${BUILT_PRODUCTS_DIR}/GrouviActionSheet/GrouviActionSheet.framework",
Expand All @@ -2861,6 +2869,7 @@
);
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BigInt.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GrouviActionSheet.framework",
Expand Down Expand Up @@ -2919,6 +2928,7 @@
inputPaths = (
"${SRCROOT}/../Pods/Target Support Files/Pods-Bank/Pods-Bank-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework",
"${BUILT_PRODUCTS_DIR}/BigInt/BigInt.framework",
"${BUILT_PRODUCTS_DIR}/GRDB.swift/GRDB.framework",
"${BUILT_PRODUCTS_DIR}/GrouviActionSheet/GrouviActionSheet.framework",
Expand All @@ -2945,6 +2955,7 @@
);
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BigInt.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GrouviActionSheet.framework",
Expand Down Expand Up @@ -3409,6 +3420,7 @@
58AAA6941C8B5140B0B5DDAE /* Erc20Adapter.swift in Sources */,
58AAA2363892ED5743CBF2EB /* EthereumBaseAdapter.swift in Sources */,
1A56451041F9A9AB607C3A73 /* Decimal.swift in Sources */,
11B35D3A74237CE0B77295B6 /* CoinIconImageView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -3773,6 +3785,7 @@
58AAABE8E8374ED4211F610C /* Erc20Adapter.swift in Sources */,
58AAA4A377F356194AE08055 /* EthereumBaseAdapter.swift in Sources */,
1A56415A4BB89B9156C6442D /* Decimal.swift in Sources */,
11B3580BECA360DE35E89286 /* CoinIconImageView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -4091,6 +4104,7 @@
58AAA82745E47084A2B18F95 /* Erc20Adapter.swift in Sources */,
58AAAF011B2E9CDF8455CA7B /* EthereumBaseAdapter.swift in Sources */,
1A56491DC545ED4F8A6E6D40 /* Decimal.swift in Sources */,
11B3590CC5D7FB68ED00F7B7 /* CoinIconImageView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "phi@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "phi@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -1,5 +1,5 @@
struct BalanceViewItem {
let title: String
let coin: Coin
let coinValue: CoinValue
let exchangeValue: CurrencyValue?
let currencyValue: CurrencyValue?
Expand Down
Expand Up @@ -12,7 +12,7 @@ class BalanceViewItemFactory {
}

return BalanceViewItem(
title: item.coin.title,
coin: item.coin,
coinValue: CoinValue(coinCode: item.coin.code, value: item.balance),
exchangeValue: exchangeValue,
currencyValue: currencyValue,
Expand Down
7 changes: 4 additions & 3 deletions BankWallet/BankWallet/Modules/Balance/Views/BalanceCell.swift
Expand Up @@ -8,7 +8,7 @@ class BalanceCell: UITableViewCell {

var roundedBackground = UIView()

var coinIconImageView = TintImageView(image: nil, tintColor: BalanceTheme.coinIconTintColor, selectedTintColor: BalanceTheme.coinIconTintColor)
private let coinIconImageView = CoinIconImageView()
var nameLabel = UILabel()
var rateLabel = UILabel()
var currencyValueLabel = UILabel()
Expand Down Expand Up @@ -46,6 +46,7 @@ class BalanceCell: UITableViewCell {
roundedBackground.clipsToBounds = true
roundedBackground.layer.cornerRadius = BalanceTheme.roundedBackgroundCornerRadius

coinIconImageView.tintColor = BalanceTheme.coinIconTintColor
roundedBackground.addSubview(coinIconImageView)
coinIconImageView.snp.makeConstraints { maker in
maker.leading.equalToSuperview().offset(BalanceTheme.cellBigMargin)
Expand Down Expand Up @@ -182,7 +183,7 @@ class BalanceCell: UITableViewCell {
}

func bindView(item: BalanceViewItem, selected: Bool, animated: Bool = false) {
coinIconImageView.image = UIImage(named: "\(item.coinValue.coinCode) Icon")
coinIconImageView.bind(coin: item.coin)

receiveButton.set(hidden: !selected, animated: animated, duration: BalanceTheme.buttonsAnimationDuration)
payButton.set(hidden: !selected, animated: animated, duration: BalanceTheme.buttonsAnimationDuration)
Expand All @@ -193,7 +194,7 @@ class BalanceCell: UITableViewCell {
payButton.state = .disabled
}

nameLabel.text = item.title.localized
nameLabel.text = item.coin.title.localized

if let value = item.exchangeValue, let formattedValue = ValueFormatter.instance.format(currencyValue: value, shortFractionLimit: 100) {
rateLabel.text = "balance.rate_per_coin".localized(formattedValue, item.coinValue.coinCode)
Expand Down
Expand Up @@ -20,7 +20,7 @@ extension DepositPresenter: IDepositViewDelegate {

func addressItems(forCoin coinCode: CoinCode?) -> [AddressItem] {
return interactor.adapters(forCoin: coinCode).map {
AddressItem(title: $0.coin.title, address: $0.receiveAddress, coinCode: $0.coin.code)
AddressItem(coin: $0.coin, address: $0.receiveAddress)
}
}

Expand Down
@@ -1,13 +1,12 @@
struct AddressItem {
let title: String
let coin: Coin
let address: String
let coinCode: CoinCode
}

extension AddressItem: Equatable {

public static func ==(lhs: AddressItem, rhs: AddressItem) -> Bool {
return lhs.title == rhs.title && lhs.address == rhs.address && lhs.coinCode == rhs.coinCode
return lhs.coin == rhs.coin && lhs.address == rhs.address
}

}
Expand Up @@ -2,7 +2,7 @@ import UIKit
import SnapKit

class DepositAddressCollectionCell: UICollectionViewCell {
var iconImageView = UIImageView()
private let iconImageView = CoinIconImageView()
var titleLabel = UILabel()
var separatorView = UIView()
var qrCodeImageView = UIImageView()
Expand All @@ -11,6 +11,7 @@ class DepositAddressCollectionCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)

iconImageView.tintColor = DepositTheme.iconTintColor
contentView.addSubview(iconImageView)
iconImageView.snp.makeConstraints { maker in
maker.leading.equalToSuperview().offset(DepositTheme.regularMargin)
Expand Down Expand Up @@ -65,8 +66,8 @@ class DepositAddressCollectionCell: UICollectionViewCell {
}

func bind(address: AddressItem, onCopy: @escaping () -> ()) {
iconImageView.image = UIImage(named: "\(address.coinCode) Icon")?.tinted(with: DepositTheme.iconTintColor)
titleLabel.text = "deposit.receive_coin".localized(address.title)
iconImageView.bind(coin: address.coin)
titleLabel.text = "deposit.receive_coin".localized(address.coin.title)
qrCodeImageView.backgroundColor = .lightGray
addressButton.bind(value: address.address)

Expand Down
Expand Up @@ -4,7 +4,7 @@ import SnapKit
class ManageCoinCell: UITableViewCell {
let titleLabel = UILabel()
let coinLabel = UILabel()
let coinImageView = UIImageView()
let coinImageView = CoinIconImageView()

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
Expand All @@ -26,6 +26,7 @@ class ManageCoinCell: UITableViewCell {
maker.top.equalTo(self.titleLabel.snp.bottom).offset(ManageCoinsTheme.coinLabelTopMargin)
}

coinImageView.tintColor = ManageCoinsTheme.iconTintColor
contentView.addSubview(coinImageView)
coinImageView.snp.makeConstraints { maker in
maker.centerY.equalToSuperview()
Expand All @@ -40,7 +41,7 @@ class ManageCoinCell: UITableViewCell {
func bind(coin: Coin) {
titleLabel.text = coin.title
coinLabel.text = coin.code
coinImageView.image = UIImage(named: "\(coin.code) Icon")?.tinted(with: ManageCoinsTheme.iconTintColor)
coinImageView.bind(coin: coin)
}

}
Expand Up @@ -4,14 +4,15 @@ import GrouviActionSheet
import SnapKit

class SendTitleItemView: BaseActionItemView {
private let iconImageView = UIImageView()
private let iconImageView = CoinIconImageView()
private let titleLabel = UILabel()

override var item: SendTitleItem? { return _item as? SendTitleItem }

override func initView() {
super.initView()

iconImageView.tintColor = SendTheme.iconColor
addSubview(iconImageView)
iconImageView.snp.makeConstraints { maker in
maker.leading.top.equalToSuperview().offset(SendTheme.margin)
Expand All @@ -26,7 +27,7 @@ class SendTitleItemView: BaseActionItemView {
}

item?.bindCoin = { [weak self] coin in
self?.iconImageView.image = UIImage(named: "\(coin.code) Icon")?.tinted(with: SendTheme.iconColor)
self?.iconImageView.bind(coin: coin)
self?.titleLabel.text = "send.title".localized(coin.title)
}
}
Expand Down
33 changes: 33 additions & 0 deletions BankWallet/BankWallet/UserInterface/CoinIconImageView.swift
@@ -0,0 +1,33 @@
import UIKit
import AlamofireImage

class CoinIconImageView: UIImageView {

private static let filter = DynamicImageFilter("TemplateImageFilter") { image in
return image.withRenderingMode(.alwaysTemplate)
}

private static let erc20placeholderImage = UIImage(named: "Erc20 Placeholder Icon")?.withRenderingMode(.alwaysTemplate)

func bind(coin: Coin) {
switch coin.type {
case let .erc20(address, _):
// let baseApiUrl = App.shared.appConfigProvider.ratesApiUrl
let baseApiUrl = "https://ipfs.horizontalsystems.xyz/ipns/Qmd4Gv2YVPqs6dmSy1XEq7pQRSgLihqYKL2JjK7DMUFPVz/io-hs/data"
let screenScale = Int(UIScreen.main.scale)

let urlString = "\(baseApiUrl)/blockchain/ETH/erc20/\(address)/icons/ios/icon@\(screenScale)x.png"

if let url = URL(string: urlString) {
af_setImage(
withURL: url,
placeholderImage: CoinIconImageView.erc20placeholderImage,
filter: CoinIconImageView.filter
)
}
default:
image = UIImage(named: "\(coin.code) Icon")?.withRenderingMode(.alwaysTemplate)
}
}

}
Expand Up @@ -68,22 +68,22 @@ class DepositPresenterTests: XCTestCase {

func testGetAddressItems() {
let expectedItems = [
AddressItem(title: bitcoinTitle, address: bitcoinAddress, coinCode: bitcoin),
AddressItem(title: etherTitle, address: etherAddress, coinCode: ether)
AddressItem(coin: Coin(title: bitcoinTitle, code: bitcoin, type: .bitcoin), address: bitcoinAddress),
AddressItem(coin: Coin(title: etherTitle, code: ether, type: .ethereum), address: etherAddress)
]

XCTAssertEqual(presenter.addressItems(forCoin: nil), expectedItems)
}

func testOnCopy() {
presenter.onCopy(addressItem: AddressItem(title: bitcoinTitle, address: bitcoinAddress, coinCode: bitcoin))
presenter.onCopy(addressItem: AddressItem(coin: Coin(title: bitcoinTitle, code: bitcoin, type: .bitcoin), address: bitcoinAddress))

verify(mockInteractor).copy(address: equal(to: bitcoinAddress))
verify(mockView).showCopied()
}

func testOnShare() {
presenter.onShare(addressItem: AddressItem(title: bitcoinTitle, address: bitcoinAddress, coinCode: bitcoin))
presenter.onShare(addressItem: AddressItem(coin: Coin(title: bitcoinTitle, code: bitcoin, type: .bitcoin), address: bitcoinAddress))

verify(mockRouter).share(address: equal(to: bitcoinAddress))
}
Expand Down
1 change: 1 addition & 0 deletions Podfile
Expand Up @@ -10,6 +10,7 @@ def appPods
pod 'HSEthereumKit', git: 'https://github.com/horizontalsystems/ethereum-kit-ios/'

pod 'Alamofire'
pod 'AlamofireImage'
pod 'ObjectMapper'

pod 'RxSwift'
Expand Down

0 comments on commit 74ffbda

Please sign in to comment.