Tap on cell containing "Add / Hide Tokens" in Wallet tab shouldn't select the 0th token #2110

pull/2111/head
Vladyslav shepitko 4 years ago
parent e379844fdc
commit 5a8ffc9169
  1. 4
      AlphaWallet.xcodeproj/project.pbxproj
  2. 215
      AlphaWallet/Tokens/ViewControllers/TokensViewController.swift
  3. 37
      AlphaWallet/Tokens/Views/AddHideTokensCell.swift
  4. 10
      AlphaWallet/Tokens/Views/AddHideTokensView.swift
  5. 4
      AlphaWallet/Tokens/Views/TokensViewControllerCollectiblesCollectionViewHeader.swift

@ -438,7 +438,6 @@
5E7C78FF93B0DD68700FAFB6 /* NativeCryptoCurrencyBalanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7D0476B2C4EEB526189D /* NativeCryptoCurrencyBalanceView.swift */; };
5E7C79284D45EF4C5440E546 /* EnabledServersCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7C7CB95B7EE4B2547585 /* EnabledServersCoordinator.swift */; };
5E7C792AA15C1D3560A18CF8 /* ConsoleCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7C51CEC4AAFDFBD75482 /* ConsoleCoordinator.swift */; };
5E7C793B619672CCC8EA02D9 /* AddHideTokensCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C709FA1317A56BC12CD35 /* AddHideTokensCell.swift */; };
5E7C793BF142AEC0792A68C3 /* BackupSeedPhraseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C79107D8AAA345518435F /* BackupSeedPhraseCoordinator.swift */; };
5E7C793F7E346402CDAF771F /* AssetDefinitionStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7FE30D58E4022AF04E48 /* AssetDefinitionStoreTests.swift */; };
5E7C797BE2C8DB7EF6F217B3 /* OnboardingPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7103135DCCCAB96EE5FC /* OnboardingPage.swift */; };
@ -983,7 +982,6 @@
5E7C706658D72CC1C8BB698C /* BookmarkViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkViewCell.swift; sourceTree = "<group>"; };
5E7C7084B3FA83B36252B129 /* TokenScriptFilterParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenScriptFilterParserTests.swift; sourceTree = "<group>"; };
5E7C708DE897B6677EAD769B /* ScriptMessageProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScriptMessageProxy.swift; sourceTree = "<group>"; };
5E7C709FA1317A56BC12CD35 /* AddHideTokensCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddHideTokensCell.swift; sourceTree = "<group>"; };
5E7C70A03A120A74A832DD62 /* BackupState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupState.swift; sourceTree = "<group>"; };
5E7C70A6D4A3737631D092D9 /* EnabledServersViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnabledServersViewModel.swift; sourceTree = "<group>"; };
5E7C70B3651BDFE549C28466 /* PromptBackupCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromptBackupCoordinator.swift; sourceTree = "<group>"; };
@ -2066,7 +2064,6 @@
5E7C7F54FD247553A7427881 /* TokensViewControllerCollectiblesCollectionViewHeader.swift */,
5E7C73BD3FD2C2844F5DEA45 /* SegmentedControl.swift */,
5E7C78FF8A5682C27E15B488 /* UITableViewCell+TokenCell.swift */,
5E7C709FA1317A56BC12CD35 /* AddHideTokensCell.swift */,
87D1757724ADAEEB002130D2 /* BlockchainTagLabel.swift */,
);
path = Views;
@ -4620,7 +4617,6 @@
5E7C7193C577A84710D71F5C /* TokenScriptFilterParser.swift in Sources */,
5E7C708F30E73521E6A494D5 /* TokenScriptSelection.swift in Sources */,
5E7C775B971EFCCEBE9B10A4 /* UITableViewCell+TokenCell.swift in Sources */,
5E7C793B619672CCC8EA02D9 /* AddHideTokensCell.swift in Sources */,
5E7C710D1522AFA533B0C22B /* XMLHandler+XPaths.swift in Sources */,
5E7C782069BAD4A667543979 /* SettingsViewController.swift in Sources */,
5E7C750721DA2745432B1857 /* TokenObject+UI.swift in Sources */,

@ -13,8 +13,10 @@ protocol TokensViewControllerDelegate: class {
class TokensViewController: UIViewController {
private static let filterViewHeight = CGFloat(50)
private static let addHideTokensViewHeight = CGFloat(60)
private enum Section {
private enum Section: CaseIterable {
case filters
case addHideToken
case tokens
}
@ -22,7 +24,7 @@ class TokensViewController: UIViewController {
private let tokenCollection: TokenCollection
private let assetDefinitionStore: AssetDefinitionStore
private let eventsDataStore: EventsDataStoreProtocol
private let sections: [Section] = [.addHideToken, .tokens]
private let sections: [Section] = Section.allCases
private var viewModel: TokensViewModel {
didSet {
@ -34,10 +36,36 @@ class TokensViewController: UIViewController {
private let account: Wallet
lazy private var tableViewFilterView = SegmentedControl(titles: TokensViewModel.segmentedControlTitles)
lazy private var collectiblesCollectionViewFilterView = SegmentedControl(titles: TokensViewModel.segmentedControlTitles)
private let tableView: UITableView
private let tableViewRefreshControl = UIRefreshControl()
private let collectiblesCollectionViewRefreshControl = UIRefreshControl()
private let collectiblesCollectionView = { () -> UICollectionView in
private lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.register(FungibleTokenViewCell.self)
tableView.register(EthTokenViewCell.self)
tableView.register(NonFungibleTokenViewCell.self)
tableView.registerHeaderFooterView(TableViewSectionHeader.self)
tableView.registerHeaderFooterView(ShowAddHideTokensView.self)
tableView.estimatedRowHeight = 100
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView.tableFooterToRemoveEmptyCellSeparators()
tableView.separatorInset = .zero
tableView.addSubview(tableViewRefreshControl)
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}()
private lazy var tableViewRefreshControl: UIRefreshControl = {
let control = UIRefreshControl()
control.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
return control
}()
private lazy var collectiblesCollectionViewRefreshControl: UIRefreshControl = {
let control = UIRefreshControl()
control.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
return control
}()
private lazy var collectiblesCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let numberOfColumns = CGFloat(3)
let dimension = (UIScreen.main.bounds.size.width / numberOfColumns).rounded(.down)
@ -46,7 +74,19 @@ class TokensViewController: UIViewController {
layout.minimumInteritemSpacing = 0
layout.headerReferenceSize = .init(width: 100, height: TokensViewController.filterViewHeight)
layout.sectionHeadersPinToVisibleBounds = true
return UICollectionView(frame: .zero, collectionViewLayout: layout)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = viewModel.backgroundColor
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.alwaysBounceVertical = true
collectionView.register(OpenSeaNonFungibleTokenViewCell.self)
collectionView.registerSupplementaryView(CollectiblesCollectionViewHeader.self, of: UICollectionView.elementKindSectionHeader)
collectionView.dataSource = self
collectionView.isHidden = true
collectionView.delegate = self
collectionView.refreshControl = collectiblesCollectionViewRefreshControl
return collectionView
}()
private var currentCollectiblesContractsDisplayed = [AlphaWallet.Address]()
private let searchController: UISearchController
@ -129,7 +169,6 @@ class TokensViewController: UIViewController {
self.assetDefinitionStore = assetDefinitionStore
self.eventsDataStore = eventsDataStore
self.viewModel = TokensViewModel(filterTokensCoordinator: filterTokensCoordinator, tokens: [], tickers: .init())
tableView = UITableView(frame: .zero, style: .plain)
searchController = UISearchController(searchResultsController: nil)
super.init(nibName: nil, bundle: nil)
@ -146,33 +185,7 @@ class TokensViewController: UIViewController {
consoleButton.addTarget(self, action: #selector(openConsole), for: .touchUpInside)
tableView.register(AddHideTokensCell.self)
tableView.register(FungibleTokenViewCell.self)
tableView.register(EthTokenViewCell.self)
tableView.register(NonFungibleTokenViewCell.self)
tableView.registerHeaderFooterView(TableViewSectionHeader.self)
// tableView.estimatedRowHeight = 0
tableView.estimatedRowHeight = 100
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView.tableFooterToRemoveEmptyCellSeparators()
tableView.separatorInset = .zero
tableViewRefreshControl.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
tableView.addSubview(tableViewRefreshControl)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
collectiblesCollectionView.backgroundColor = viewModel.backgroundColor
collectiblesCollectionView.translatesAutoresizingMaskIntoConstraints = false
collectiblesCollectionView.alwaysBounceVertical = true
collectiblesCollectionView.register(OpenSeaNonFungibleTokenViewCell.self)
collectiblesCollectionView.registerSupplementaryView(CollectiblesCollectionViewHeader.self, of: UICollectionView.elementKindSectionHeader)
collectiblesCollectionView.dataSource = self
collectiblesCollectionView.isHidden = true
collectiblesCollectionView.delegate = self
collectiblesCollectionViewRefreshControl.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
collectiblesCollectionView.refreshControl = collectiblesCollectionViewRefreshControl
view.addSubview(collectiblesCollectionView)
NSLayoutConstraint.activate([
@ -248,7 +261,7 @@ class TokensViewController: UIViewController {
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
return nil
}
func refreshView(viewModel: TokensViewModel) {
@ -305,80 +318,92 @@ extension TokensViewController: StatefulViewController {
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, heightForHeaderInSection section: Int) -> CGFloat {
guard section == 0 else { return 0 }
return TokensViewController.filterViewHeight
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return nil
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard section == 0 else { return nil }
let header: TableViewSectionHeader = tableView.dequeueReusableHeaderFooterView()
header.filterView = tableViewFilterView
return header
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.01
}
}
extension TokensViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let section = sections[indexPath.section]
switch section {
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
switch sections[section] {
case .filters:
return TokensViewController.filterViewHeight
case .addHideToken:
return addHideTokenCell(forIndexPath: indexPath)
return TokensViewController.addHideTokensViewHeight
case .tokens:
return tokenCell(forIndexPath: indexPath)
return 0.01
}
}
private func addHideTokenCell(forIndexPath indexPath: IndexPath) -> UITableViewCell {
let cell: AddHideTokensCell = tableView.dequeueReusableCell(for: indexPath)
cell.delegate = self
cell.configure()
return cell
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
switch sections[section] {
case .filters:
let header: TableViewSectionHeader = tableView.dequeueReusableHeaderFooterView()
header.filterView = tableViewFilterView
return header
case .addHideToken:
let header: ShowAddHideTokensView = tableView.dequeueReusableHeaderFooterView()
header.delegate = self
header.configure(viewModel: .init())
return header
case .tokens:
return nil
}
}
}
private func tokenCell(forIndexPath indexPath: IndexPath) -> UITableViewCell {
let token = viewModel.item(for: indexPath.row, section: indexPath.section)
let server = token.server
let session = sessions[server]
switch token.type {
case .nativeCryptocurrency:
let cell: EthTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(
viewModel: .init(
token: token,
ticker: viewModel.ticker(for: token),
currencyAmount: session.balanceCoordinator.viewModel.currencyAmount,
currencyAmountWithoutSymbol: session.balanceCoordinator.viewModel.currencyAmountWithoutSymbol,
server: server,
assetDefinitionStore: assetDefinitionStore
)
)
return cell
case .erc20:
let cell: FungibleTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(token: token, server: server, assetDefinitionStore: assetDefinitionStore))
return cell
case .erc721, .erc721ForTickets:
let cell: NonFungibleTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(token: token, server: server, assetDefinitionStore: assetDefinitionStore))
return cell
case .erc875:
let cell: NonFungibleTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(token: token, server: server, assetDefinitionStore: assetDefinitionStore))
return cell
extension TokensViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch sections[indexPath.section] {
case .addHideToken, .filters:
return UITableViewCell()
case .tokens:
let token = viewModel.item(for: indexPath.row, section: indexPath.section)
let server = token.server
let session = sessions[server]
switch token.type {
case .nativeCryptocurrency:
let cell: EthTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(
token: token,
ticker: viewModel.ticker(for: token),
currencyAmount: session.balanceCoordinator.viewModel.currencyAmount,
currencyAmountWithoutSymbol: session.balanceCoordinator.viewModel.currencyAmountWithoutSymbol,
server: server,
assetDefinitionStore: assetDefinitionStore
))
return cell
case .erc20:
let cell: FungibleTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(token: token, server: server, assetDefinitionStore: assetDefinitionStore))
return cell
case .erc721, .erc721ForTickets:
let cell: NonFungibleTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(token: token, server: server, assetDefinitionStore: assetDefinitionStore))
return cell
case .erc875:
let cell: NonFungibleTokenViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(token: token, server: server, assetDefinitionStore: assetDefinitionStore))
return cell
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let section = sections[section]
switch section {
case .addHideToken:
return 1
switch sections[section] {
case .addHideToken, .filters:
return 0
case .tokens:
return viewModel.numberOfItems()
}
@ -389,9 +414,8 @@ extension TokensViewController: UITableViewDataSource {
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let section = sections[indexPath.section]
switch section {
case .addHideToken:
switch sections[indexPath.section] {
case .addHideToken, .filters:
return nil
case .tokens:
return trailingSwipeActionsConfiguration(forRowAt: indexPath)
@ -456,6 +480,11 @@ extension TokensViewController: SegmentedControlDelegate {
}
extension TokensViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//Defensive check to make sure we don't return the wrong count. iOS might decide to load (the first time especially) the collection view at some point even if we don't switch to it, thus getting the wrong count and then at some point asking for a cell for those non-existent rows/items. E.g 10 tokens total, only 3 are collectibles and asked for the 6th cell
switch viewModel.filter {

@ -1,37 +0,0 @@
// Copyright © 2020 Stormbird PTE. LTD.
import UIKit
class AddHideTokensCell: UITableViewCell {
lazy private var addHideTokensView = ShowAddHideTokensView()
weak var delegate: ShowAddHideTokensViewDelegate?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addHideTokensView.delegate = self
addHideTokensView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(addHideTokensView)
NSLayoutConstraint.activate([
addHideTokensView.anchorsConstraint(to: contentView),
addHideTokensView.heightAnchor.constraint(equalToConstant: 60),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure() {
addHideTokensView.configure(viewModel: .init())
}
}
extension AddHideTokensCell: ShowAddHideTokensViewDelegate {
func view(_ view: ShowAddHideTokensView, didSelectAddHideTokensButton sender: UIButton) {
delegate?.view(view, didSelectAddHideTokensButton: sender)
}
}

@ -6,14 +6,14 @@ protocol ShowAddHideTokensViewDelegate: class {
func view(_ view: ShowAddHideTokensView, didSelectAddHideTokensButton sender: UIButton)
}
class ShowAddHideTokensView: UIView {
class ShowAddHideTokensView: UITableViewHeaderFooterView {
private let addTokenTitleLeftInset: CGFloat = 7
private lazy var addTokenButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.semanticContentAttribute = .forceRightToLeft
button.titleEdgeInsets = UIEdgeInsets(top: 0, left: -addTokenTitleLeftInset, bottom: 0, right: addTokenTitleLeftInset)
button.addTarget(self, action: #selector(addHideTokensSelected(_:)), for: .touchUpInside)
button.addTarget(self, action: #selector(addHideTokensSelected), for: .touchUpInside)
return button
}()
@ -49,13 +49,13 @@ class ShowAddHideTokensView: UIView {
weak var delegate: ShowAddHideTokensViewDelegate?
init() {
super.init(frame: .zero)
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
return nil
}
private func setupViews() {

@ -17,7 +17,7 @@ extension TokensViewController {
addSubview(filterView)
NSLayoutConstraint.activate([
filterView.anchorsConstraint(to: self, edgeInsets: .init(top: 0, left: 0, bottom: 7, right: 0)),
filterView.anchorsConstraint(to: self, edgeInsets: .zero),
])
}
}
@ -28,7 +28,7 @@ extension TokensViewController {
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
return nil
}
}
}

Loading…
Cancel
Save