Files
raspberry/iOS/Wallet/Sources/Common/View/Card/CommonViewCard.swift
T
2022-07-25 11:26:14 +03:00

307 lines
12 KiB
Swift

//
// CommonViewCard.swift
// Wallet
//
// Created by Igor on 21.02.2021.
// Copyright © 2021 AM. All rights reserved.
//
import UIKit
import SkeletonView
extension Common.Model.Menu {
static func cardsTokensEmpty() -> Common.Model.Menu {
.menu(image: Asset.commonToken.image.tinted(with: Asset.deepWater.color),
title: L10n.Common.Card.Token.title)
}
}
extension CommonMenuAction {
static func cards(
collection: [Common.Model.Menu]? = nil,
icon: UIImage? = nil,
tokens: [Network.Model.Token] = [],
selectedMenu: Common.Model.Menu? = nil,
selected: Network.Model.Token? = nil,
empty: Common.Model.Menu? = .cardsTokensEmpty(),
title: String? = L10n.Common.Card.Token.title,
_ completion: ((Common.Model.Menu) -> Void)? = nil
) -> CommonMenuSelect {
.select(
icon: tokens.isEmpty ? nil : icon ?? Asset.commonMenuHorizontal.image,
kind: .cards,
title: title,
empty: empty,
collection: collection ?? tokens.map({ $0.toMenu() }),
selected: selectedMenu ?? selected?.toMenu(),
completion: completion
)
}
}
class CommonViewCard: CommonControlCustom, CommonMenuSender {
enum Style: String {
case `default`
case data
}
@IBInspectable var styleName: String = Style.default.rawValue {
didSet { update(animated: false) }
}
var style: Style {
get { Style(rawValue: styleName) ?? .default }
set { styleName = newValue.rawValue }
}
@IBInspectable var image: UIImage? {
didSet { update(animated: false) }
}
@IBInspectable var lzHeader: String? {
didSet { update(animated: false) }
}
@IBInspectable var lzSubheader: String? {
didSet { update(animated: false) }
}
@IBInspectable var lzData: String? {
didSet { update(animated: false) }
}
@IBInspectable var icon: UIImage? {
didSet { update(animated: false) }
}
@IBInspectable var badge: String? {
didSet { update(animated: false) }
}
@IBInspectable var badgeColor: UIColor? {
didSet { update(animated: false) }
}
var action: CommonMenuAction? {
didSet { update(animated: false) }
}
var middleAction: (() -> Void)? = nil
var rightAction: (() -> Void)? = nil
@IBOutlet private weak var shadowContainer: CommonViewContainer!
@IBOutlet private weak var indicator: UIActivityIndicatorView!
@IBOutlet private weak var imgShadowView: UIImageView!
@IBOutlet private weak var imgView: UIImageView!
@IBOutlet private weak var imgViewOffset: NSLayoutConstraint!
@IBOutlet private weak var imgViewWidth: NSLayoutConstraint!
@IBOutlet private weak var headerLbl: UILabel!
@IBOutlet private weak var badgeBtn: UIButton!
@IBOutlet private weak var subheaderLbl: UILabel!
@IBOutlet private weak var subheaderOffset: NSLayoutConstraint!
@IBOutlet private weak var dataLbl: UILabel!
@IBOutlet private weak var dataStackView: UIStackView!
@IBOutlet private weak var dataOffset: NSLayoutConstraint!
@IBOutlet private weak var actionBtn: UIButton!
@IBOutlet private weak var bottomStackView: UIStackView!
init(action: CommonMenuAction? = nil) {
super.init(frame: .zero)
self.action = action
update(animated: false)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var cashBillsService: CashBillsService?
private var bills: [CashBillsService.Bill] {
cashBillsService?.collection.filter({ $0.gtoken_out.quantity.symbol == action?.menu?.title }) ?? []
}
var selectedCashBill: CashBillsService.Bill?
// {
// didSet {
// update(animated: true)
// }
// }
var selectCashBillAction: ((CashBillsService.Bill?) -> Void)?
var root: Bool = false
private func generateRichSublabel(certCount: String, lockedCertCount: String) {
dataStackView.arrangedSubviews.forEach({ $0.removeFromSuperview() })
dataStackView.alignment = .center
// dataStackView.addHeightConstraint(height: 24)
let label1 = UILabel()
label1.attributedText = certCount.attributed(style: .bold, size: 20, color: Asset.textCoal.color)
let label2 = UILabel()
label2.attributedText = "+\(lockedCertCount)".attributed(style: .bold, size: 20, color: Asset.textBrick.color)
dataStackView.addArrangedSubview(UIStackView(subviews: [label1, label2], axis: .horizontal, distribution: .fill, alignment: .fill, spacing: 0))
let lockImage = UIImageView(image: Asset.commonLock.image.withRenderingMode(.alwaysTemplate))
lockImage.addHeightWidthConstraints(height: 16, width: 16)
lockImage.tintColor = Asset.brick.color
dataStackView.addArrangedSubview(lockImage)
let label3 = UILabel()
label3.attributedText = L10n.Cccp.Main.sublabelLockedText.attributed(style: .regular, size: 14, color: Asset.textSnow.color)
let view2 = UIView(width: 141, height: 22, color: Asset.pebble.color)
view2.layer.cornerRadius = 6
view2.addSubview(label3)
UIView.activate(constraints: [
label3.centerXAnchor.constraint(equalTo: view2.centerXAnchor),
label3.centerYAnchor.constraint(equalTo: view2.centerYAnchor)
])
dataStackView.addArrangedSubview(view2)
dataStackView.addArrangedSubview(UIView(height: 24))
}
func update(animated: Bool) {
superview?.clipsToBounds = false
headerLbl.text = nil
subheaderLbl.text = nil
dataLbl.text = nil
// dataStackView.isHidden = true
dataLbl.alpha = 1
dataStackView.arrangedSubviews.forEach({ $0.removeFromSuperview() })
let bill = root ? self.selectedCashBill : nil
let header = bill != nil ? L10n.Cccp.Main.bill + " " + bill!.gtoken_out.quantity.symbol
: action?.menu?.title ?? lzHeader
let subheader = bill?.creationDate.string(pattern: "dd.MM.yyyy HH:mm:ss") ?? action?.menu?.text ?? lzSubheader
let data = bill?.token_out.quantity.toNormalizedString(group: true) ?? action?.menu?.details ?? lzData
let badge = action?.menu?.badge?.0 ?? self.badge
let icon = action?.icon ?? self.icon
if style == .default {
headerLbl.attributedText = header?.localized.attributed(style: .medium, size: 14, color: Asset.textGranite.color)
subheaderLbl.attributedText = subheader?.localized.attributed(style: .regular, size: 12, color: Asset.textGranite.color)
subheaderOffset.constant = subheader?.isEmpty == true ? 0 : 2
dataLbl.attributedText = data?.localized.attributed(style: .bold, size: 20, color: Asset.textCoal.color)
dataOffset.constant = data?.isEmpty == true ? 0 : 4
} else {
headerLbl.attributedText = data?.localized.attributed(style: .bold, size: 20, color: Asset.textCoal.color)
subheaderLbl.attributedText = header?.localized.attributed(style: .medium, size: 14, color: Asset.textGranite.color)
subheaderOffset.constant = header?.isEmpty == true ? 0 : 2
dataLbl.attributedText = subheader?.localized.attributed(style: .regular, size: 12, color: Asset.textGranite.color)
dataOffset.constant = subheader?.isEmpty == true ? 0 : 4
}
if let badge = badge?.localized {
badgeBtn.isHidden = false
badgeBtn.setAttributedTitle(badge.attributed(style: .regular, size: 12, color: Asset.textSnow.color), for: .normal)
if let color = action?.menu?.badge?.1 ?? badgeColor {
badgeBtn.backgroundColor = color
}
} else {
badgeBtn.isHidden = true
}
actionBtn.setImage(icon, for: .normal)
imgShadowView.isHidden = true
if let bill = bill {
imgView.image = Asset.cashBill.image
} else if let image = action?.menu?.image ?? image {
imgView.image = image
// uncomment for turn on cash tokens shadow
// if (action?.menu?.uuid.contains(Network.servers.current.contract(.cash)) ?? false)
// && (action?.menu?.uuid.lowercased().dropFirst(3).starts(with: "cash") ?? false) {
// imgShadowView.isHidden = false
// }
} else if let urls = action?.menu?.imageURLs {
downloadImage(urls: urls)
} else {
imgView.image = nil
}
if bills.count > 0 && !root {
actionBtn.setImage(collapsed ? Asset.cashBillUncollapse.image : Asset.cashBillCollapse.image, for: .normal)
if bills.contains(where: { $0.id == selectedCashBill?.id }) {
changeBillsState()
}
if !collapsed && bottomStackView.arrangedSubviews.isEmpty {
changeBillsState()
}
let certCount = Int(data?.replacingOccurrences(of: " ", with: "").amount ?? "0") ?? 0
if bills.count > certCount {
generateRichSublabel(certCount: "\(certCount)", lockedCertCount: "\(bills.count - certCount)")
dataLbl.alpha = 0
}
}
imgViewOffset.constant = imgView.image == nil && (action?.menu?.imageURLs ?? []).isEmpty ? 0 : 12
imgViewWidth.constant = imgView.image == nil && (action?.menu?.imageURLs ?? []).isEmpty ? 0 : 40
animated ? UIView.animate(withDuration: Animation.fast) { self.layoutIfNeeded() } : layoutIfNeeded()
}
private func downloadImage(urls: [URL]) {
if urls.isEmpty {
indicator.stopAnimating()
imgView.image = image
} else {
indicator.startAnimating()
imgView.af.setImage(withURL: urls.first!, placeholderImage: image ?? UIImage(), completion: {
guard $0.error != nil else { self.indicator.stopAnimating();return }
self.downloadImage(urls: Array(urls.dropFirst()))
})
}
}
@IBAction func onAction(_: AnyObject?) {
guard isEnabled else { return }
if let middleAction = middleAction {
middleAction()
} else {
action?.perform(sender: self)
}
}
func prepareForReuse() {
bottomStackView.arrangedSubviews.forEach({ $0.removeFromSuperview() })
}
var collapsed: Bool = false
func changeBillsState() {
if !bills.isEmpty {
if bottomStackView.arrangedSubviews.isEmpty {
collapsed = false
for bill in bills {
let card = CommonViewCard()
card.lzHeader = L10n.Cccp.Main.bill + " " + bill.gtoken_out.quantity.symbol
card.lzSubheader = bill.creationDate.string(pattern: "dd.MM.yyyy HH:mm:ss")
card.lzData = bill.token_out.quantity.amount.toDecimal()
.toString(max: bill.token_out.quantity.precision)
+ " \(bill.token_out.quantity.symbol)"
card.image = Asset.cashBill.image
card.shadowContainer.imgView.isHidden = true
if bill.id == selectedCashBill?.id {
card.actionBtn.setImage(Asset.commonSelected.image, for: .normal)
}
if let selectCashBillAction = selectCashBillAction {
card.middleAction = { selectCashBillAction(bill) }
}
let sepearatorStackView = UIStackView(
subviews: [UIView(width: 12), UIView(height: 1, color: Asset.fog.color), UIView(width: 12)],
axis: .horizontal, distribution: .fill, alignment: .fill, spacing: 0)
bottomStackView.addArrangedSubview(sepearatorStackView)
bottomStackView.addArrangedSubview(card)
}
actionBtn.setImage(Asset.cashBillCollapse.image, for: .normal)
} else {
collapsed = true
bottomStackView.arrangedSubviews.forEach({ $0.removeFromSuperview() })
actionBtn.setImage(Asset.cashBillUncollapse.image, for: .normal)
}
}
}
@IBAction func onRightAction(_: AnyObject?) {
guard isEnabled else { return }
if !root { changeBillsState() }
if let rightAction = rightAction {
rightAction()
} else {
action?.perform(sender: self)
}
}
}