[Samoa] Improve Add/Hide Tokens screen #2994
parent
86555ad46d
commit
00f556df4f
@ -0,0 +1,21 @@ |
||||
{ |
||||
"images" : [ |
||||
{ |
||||
"filename" : "iconsSystemExpandMore.pdf", |
||||
"idiom" : "universal", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "universal", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "universal", |
||||
"scale" : "3x" |
||||
} |
||||
], |
||||
"info" : { |
||||
"author" : "xcode", |
||||
"version" : 1 |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,27 @@ |
||||
// |
||||
// SortTokensParam.swift |
||||
// AlphaWallet |
||||
// |
||||
// Created by Vladyslav Shepitko on 10.08.2021. |
||||
// |
||||
|
||||
import UIKit |
||||
|
||||
enum SortTokensParam: Int, CaseIterable, DropDownItemType { |
||||
|
||||
var title: String { |
||||
switch self { |
||||
case .name: return R.string.localizable.sortTokensParamName() |
||||
case .value: return R.string.localizable.sortTokensParamValue() |
||||
case .mostUsed: return R.string.localizable.sortTokensParamMostUsed() |
||||
} |
||||
} |
||||
|
||||
case name |
||||
case value |
||||
case mostUsed |
||||
|
||||
static var allCases: [SortTokensParam] { |
||||
return [.name, .value] |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
// |
||||
// DropDownViewModel.swift |
||||
// AlphaWallet |
||||
// |
||||
// Created by Vladyslav Shepitko on 10.08.2021. |
||||
// |
||||
|
||||
import UIKit |
||||
|
||||
|
||||
protocol DropDownItemType: RawRepresentable, Equatable { |
||||
var title: String { get } |
||||
} |
||||
|
||||
struct DropDownViewModel<T: DropDownItemType> { |
||||
let selectionItems: [T] |
||||
var selected: SegmentedControl.Selection |
||||
var placeholder: String = R.string.localizable.sortTokensSortBy("-") |
||||
|
||||
func placeholder(for selection: SegmentedControl.Selection) -> String { |
||||
switch selection { |
||||
case .unselected: |
||||
return placeholder |
||||
case .selected(let idx): |
||||
return R.string.localizable.sortTokensSortBy(selectionItems[Int(idx)].title) |
||||
} |
||||
} |
||||
|
||||
init(selectionItems: [T], selected: T) { |
||||
self.selectionItems = selectionItems |
||||
self.selected = DropDownViewModel.elementSelection(of: selected, in: selectionItems) |
||||
} |
||||
|
||||
func attributedString(item: T) -> NSAttributedString { |
||||
return NSAttributedString(string: item.title, attributes: [ |
||||
.font: Fonts.regular(size: 23), |
||||
.foregroundColor: Colors.sortByTextColor |
||||
]) |
||||
} |
||||
|
||||
static func elementSelection(of selected: T, in selectionItems: [T]) -> SegmentedControl.Selection { |
||||
guard let index = selectionItems.firstIndex(where: { $0 == selected }) else { |
||||
return .unselected |
||||
} |
||||
|
||||
return .selected(UInt(index)) |
||||
} |
||||
} |
@ -0,0 +1,127 @@ |
||||
// |
||||
// DropDownView.swift |
||||
// AlphaWallet |
||||
// |
||||
// Created by Vladyslav Shepitko on 10.08.2021. |
||||
// |
||||
|
||||
import UIKit |
||||
|
||||
protocol DropDownViewDelegate: class { |
||||
func filterDropDownViewDidChange(selection: SegmentedControl.Selection) |
||||
} |
||||
|
||||
final class DropDownView<T: DropDownItemType>: UIView, ReusableTableHeaderViewType, UIPickerViewDelegate, UIPickerViewDataSource { |
||||
|
||||
func numberOfComponents(in pickerView: UIPickerView) -> Int { |
||||
return 1 |
||||
} |
||||
|
||||
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { |
||||
return viewModel.selectionItems.count |
||||
} |
||||
|
||||
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { |
||||
return viewModel.selectionItems[row].title |
||||
} |
||||
|
||||
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { |
||||
return viewModel.attributedString(item: viewModel.selectionItems[row]) |
||||
} |
||||
|
||||
private var selected: SegmentedControl.Selection |
||||
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { |
||||
selected = .selected(UInt(row)) |
||||
} |
||||
|
||||
private var viewModel: DropDownViewModel<T> |
||||
weak var delegate: DropDownViewDelegate? |
||||
|
||||
private lazy var hiddenTextField: UITextField = { |
||||
let textField = UITextField() |
||||
textField.translatesAutoresizingMaskIntoConstraints = false |
||||
textField.inputAccessoryView = UIToolbar.doneToolbarButton(#selector(doneSelected), self) |
||||
textField.inputView = pickerView |
||||
textField.isHidden = true |
||||
|
||||
return textField |
||||
}() |
||||
|
||||
private lazy var pickerView: UIPickerView = { |
||||
let pickerView = UIPickerView(frame: CGRect(x: 0, y: 0, width: bounds.size.width, height: 200)) |
||||
pickerView.translatesAutoresizingMaskIntoConstraints = false |
||||
pickerView.delegate = self |
||||
pickerView.dataSource = self |
||||
|
||||
return pickerView |
||||
}() |
||||
|
||||
private lazy var selectionButton: Button = { |
||||
let button = Button(size: .normal, style: .special) |
||||
button.translatesAutoresizingMaskIntoConstraints = false |
||||
button.addTarget(self, action: #selector(selectionButtonSelected), for: .touchUpInside) |
||||
button.setImage(R.image.iconsSystemExpandMore(), for: .normal) |
||||
button.imageView?.contentMode = .scaleAspectFit |
||||
button.semanticContentAttribute = .forceRightToLeft |
||||
|
||||
return button |
||||
}() |
||||
|
||||
init(viewModel: DropDownViewModel<T>) { |
||||
self.viewModel = viewModel |
||||
self.selected = viewModel.selected |
||||
super.init(frame: .zero) |
||||
|
||||
translatesAutoresizingMaskIntoConstraints = false |
||||
addSubview(hiddenTextField) |
||||
addSubview(selectionButton) |
||||
|
||||
NSLayoutConstraint.activate([ |
||||
selectionButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), |
||||
selectionButton.topAnchor.constraint(equalTo: topAnchor, constant: 16), |
||||
selectionButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16), |
||||
]) |
||||
|
||||
configure(viewModel: viewModel) |
||||
} |
||||
|
||||
required init?(coder: NSCoder) { |
||||
return nil |
||||
} |
||||
|
||||
func configure(viewModel: DropDownViewModel<T>) { |
||||
self.viewModel = viewModel |
||||
self.selected = viewModel.selected |
||||
configure(selection: viewModel.selected) |
||||
} |
||||
|
||||
@objc private func selectionButtonSelected(_ sender: UIButton) { |
||||
hiddenTextField.becomeFirstResponder() |
||||
} |
||||
|
||||
@objc private func doneSelected(_ sender: UITextField) { |
||||
hiddenTextField.endEditing(true) |
||||
|
||||
viewModel.selected = selected |
||||
configure(selection: viewModel.selected) |
||||
|
||||
delegate?.filterDropDownViewDidChange(selection: viewModel.selected) |
||||
} |
||||
|
||||
private func configure(selection: SegmentedControl.Selection) { |
||||
let placeholder = viewModel.placeholder(for: selection) |
||||
selectionButton.setTitle(placeholder, for: .normal) |
||||
selectionButton.semanticContentAttribute = .forceRightToLeft |
||||
} |
||||
|
||||
func value(from selection: SegmentedControl.Selection) -> T? { |
||||
switch selection { |
||||
case .unselected: |
||||
return nil |
||||
case .selected(let index): |
||||
guard viewModel.selectionItems.indices.contains(Int(index)) else { return nil } |
||||
return viewModel.selectionItems[Int(index)] |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,81 @@ |
||||
// |
||||
// EmptyFilteringResultView.swift |
||||
// AlphaWallet |
||||
// |
||||
// Created by Vladyslav Shepitko on 10.08.2021. |
||||
// |
||||
|
||||
import Foundation |
||||
import UIKit |
||||
import StatefulViewController |
||||
|
||||
class EmptyFilteringResultView: UIView { |
||||
private let titleLabel = UILabel() |
||||
private let imageView = UIImageView() |
||||
private let button = Button(size: .large, style: .green) |
||||
private let insets: UIEdgeInsets |
||||
var onRetry: (() -> Void)? = .none |
||||
private let viewModel = StateViewModel() |
||||
|
||||
init( |
||||
frame: CGRect = .zero, |
||||
title: String = R.string.localizable.empty(), |
||||
image: UIImage? = R.image.no_transactions_mascot(), |
||||
insets: UIEdgeInsets = .zero, |
||||
actionButtonTitle: String = R.string.localizable.addCustomTokenTitle(), |
||||
onRetry: (() -> Void)? = .none |
||||
) { |
||||
self.insets = insets |
||||
self.onRetry = onRetry |
||||
super.init(frame: frame) |
||||
|
||||
backgroundColor = .white |
||||
|
||||
titleLabel.translatesAutoresizingMaskIntoConstraints = false |
||||
titleLabel.text = title |
||||
titleLabel.font = viewModel.descriptionFont |
||||
titleLabel.textColor = viewModel.descriptionTextColor |
||||
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false |
||||
imageView.image = image |
||||
|
||||
button.translatesAutoresizingMaskIntoConstraints = false |
||||
button.setTitle(actionButtonTitle, for: .normal) |
||||
button.addTarget(self, action: #selector(retry), for: .touchUpInside) |
||||
|
||||
let stackView = [ |
||||
imageView, |
||||
titleLabel, |
||||
].asStackView(axis: .vertical, spacing: 30, alignment: .center) |
||||
stackView.translatesAutoresizingMaskIntoConstraints = false |
||||
|
||||
if onRetry != nil { |
||||
stackView.addArrangedSubview(button) |
||||
} |
||||
|
||||
addSubview(stackView) |
||||
|
||||
NSLayoutConstraint.activate([ |
||||
stackView.trailingAnchor.constraint(equalTo: trailingAnchor), |
||||
stackView.leadingAnchor.constraint(equalTo: leadingAnchor), |
||||
stackView.centerXAnchor.constraint(equalTo: centerXAnchor), |
||||
stackView.bottomAnchor.constraint(equalTo: centerYAnchor, constant: -30), |
||||
button.widthAnchor.constraint(equalToConstant: 230), |
||||
]) |
||||
} |
||||
|
||||
@objc func retry() { |
||||
onRetry?() |
||||
} |
||||
|
||||
required init?(coder aDecoder: NSCoder) { |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
extension EmptyFilteringResultView: StatefulPlaceholderView { |
||||
func placeholderViewInsets() -> UIEdgeInsets { |
||||
return insets |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue