ZcashLightClientKit/Example/ZcashLightClientSample/ZcashLightClientSample/Transaction Detail/TransactionDetailViewContro...

170 lines
5.6 KiB
Swift

//
// TransactionDetailViewController.swift
// ZcashLightClientSample
//
// Created by Francisco Gindre on 12/16/19.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
import UIKit
import ZcashLightClientKit
final class TransactionDetailModel {
enum Transaction {
case sent(ZcashTransaction.Overview)
case received(ZcashTransaction.Overview)
case pending(ZcashTransaction.Overview)
case cleared(ZcashTransaction.Overview)
}
let transaction: Transaction
var id: Data?
var minedHeight: BlockHeight?
var expiryHeight: BlockHeight?
var created: Date?
var zatoshi: Zatoshi
var memo: Memo?
init(sendTransaction transaction: ZcashTransaction.Overview, memos: [Memo]) {
self.transaction = .sent(transaction)
self.id = transaction.rawID
self.minedHeight = transaction.minedHeight
self.expiryHeight = transaction.expiryHeight
self.zatoshi = transaction.value
self.memo = memos.first
if let blockTime = transaction.blockTime {
created = Date(timeIntervalSince1970: blockTime)
} else {
created = nil
}
}
init(receivedTransaction transaction: ZcashTransaction.Overview, memos: [Memo]) {
self.transaction = .received(transaction)
self.id = transaction.rawID
self.minedHeight = transaction.minedHeight
self.expiryHeight = transaction.expiryHeight
self.zatoshi = transaction.value
self.memo = memos.first
self.created = Date(timeIntervalSince1970: transaction.blockTime ?? Date().timeIntervalSince1970)
}
init(pendingTransaction transaction: ZcashTransaction.Overview, memos: [Memo]) {
self.transaction = .pending(transaction)
self.id = transaction.rawID
self.minedHeight = transaction.minedHeight
self.expiryHeight = transaction.expiryHeight
self.created = Date(timeIntervalSince1970: transaction.blockTime ?? Date().timeIntervalSince1970)
self.zatoshi = transaction.value
self.memo = memos.first
}
init(transaction: ZcashTransaction.Overview, memos: [Memo]) {
self.transaction = .cleared(transaction)
self.id = transaction.rawID
self.minedHeight = transaction.minedHeight
self.expiryHeight = transaction.expiryHeight
self.zatoshi = transaction.value
self.memo = memos.first
if let blockTime = transaction.blockTime {
created = Date(timeIntervalSince1970: blockTime)
} else {
created = nil
}
}
func loadMemos(from synchronizer: Synchronizer) async throws -> [Memo] {
switch transaction {
case let .sent(transaction):
return try await synchronizer.getMemos(for: transaction)
case let .received(transaction):
return try await synchronizer.getMemos(for: transaction)
case .pending:
return []
case let .cleared(transaction):
return try await synchronizer.getMemos(for: transaction)
}
}
func loadMemos(from synchronizer: Synchronizer, completion: @escaping (Result<[Memo], Error>) -> Void) {
Task {
do {
let memos = try await loadMemos(from: synchronizer)
DispatchQueue.main.async {
completion(.success(memos))
}
} catch {
DispatchQueue.main.async {
completion(.failure(error))
}
}
}
}
}
extension TransactionDetailModel {
var dateDescription: String {
self.created?.formatted(date: .abbreviated, time: .shortened) ?? "No date"
}
var amountDescription: String {
self.zatoshi.amount.description
}
}
// swiftlint:disable implicitly_unwrapped_optional
class TransactionDetailViewController: UITableViewController {
@IBOutlet weak var idLabel: UILabel!
@IBOutlet weak var minedHeightLabel: UILabel!
@IBOutlet weak var expiryHeightLabel: UILabel!
@IBOutlet weak var createdLabel: UILabel!
@IBOutlet weak var zatoshiLabel: UILabel!
@IBOutlet weak var memoLabel: UILabel!
var model: TransactionDetailModel!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setup()
}
func setup() {
guard model != nil else { return }
idLabel.text = model.id?.toHexStringTxId()
minedHeightLabel.text = model.minedHeight?.description ?? "no height"
expiryHeightLabel.text = model.expiryHeight?.description ?? "no height"
createdLabel.text = model.created?.ISO8601Format()
zatoshiLabel.text = model.zatoshi.amount.description
memoLabel.text = model.memo?.toString() ?? "No memo"
loggerProxy.debug("tx id: \(model.id?.toHexStringTxId() ?? "no id!!"))")
Task {
do {
let memos = try await model.loadMemos(from: AppDelegate.shared.sharedSynchronizer)
DispatchQueue.main.async { [weak self] in
self?.didLoad(memos: memos)
}
} catch {
loggerProxy.error("Error when loading memos: \(error)")
}
}
}
func didLoad(memos: [Memo]) {
memoLabel.text = memos.first?.toString()
}
func formatMemo(_ memo: Data?) -> String {
guard let memo = memo, let string = String(bytes: memo, encoding: .utf8) else { return "No Memo" }
return string
}
func heightToString(height: BlockHeight?) -> String {
guard let height else { return "NULL" }
return String(height)
}
}