feat(@desktop/wallet): implement unified currency formatting for transaction details
Fixes #9019
This commit is contained in:
parent
8736dd8a94
commit
53ee992c25
|
@ -70,7 +70,7 @@ proc newModule*(
|
|||
result.allTokensModule = all_tokens_module.newModule(result, events, tokenService, walletAccountService)
|
||||
result.collectiblesModule = collectibles_module.newModule(result, events, collectibleService, walletAccountService, networkService)
|
||||
result.currentAccountModule = current_account_module.newModule(result, events, walletAccountService, networkService, tokenService, currencyService)
|
||||
result.transactionsModule = transactions_module.newModule(result, events, transactionService, walletAccountService, networkService)
|
||||
result.transactionsModule = transactions_module.newModule(result, events, transactionService, walletAccountService, networkService, currencyService)
|
||||
result.savedAddressesModule = saved_addresses_module.newModule(result, events, savedAddressService)
|
||||
result.buySellCryptoModule = buy_sell_crypto_module.newModule(result, events, transactionService)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import io_interface
|
|||
import ../../../../../app_service/service/transaction/service as transaction_service
|
||||
import ../../../../../app_service/service/network/service as network_service
|
||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||
import ../../../../../app_service/service/currency/service as currency_service
|
||||
import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module
|
||||
|
||||
import ../../../../core/[main]
|
||||
|
@ -17,6 +18,7 @@ type
|
|||
transactionService: transaction_service.Service
|
||||
networkService: network_service.Service
|
||||
walletAccountService: wallet_account_service.Service
|
||||
currencyService: currency_service.Service
|
||||
|
||||
# Forward declaration
|
||||
proc loadTransactions*(self: Controller, address: string, toBlock: Uint256, limit: int = 20, loadMore: bool = false)
|
||||
|
@ -28,6 +30,7 @@ proc newController*(
|
|||
transactionService: transaction_service.Service,
|
||||
walletAccountService: wallet_account_service.Service,
|
||||
networkService: network_service.Service,
|
||||
currencyService: currency_service.Service,
|
||||
): Controller =
|
||||
result = Controller()
|
||||
result.events = events
|
||||
|
@ -35,6 +38,7 @@ proc newController*(
|
|||
result.transactionService = transactionService
|
||||
result.walletAccountService = walletAccountService
|
||||
result.networkService = networkService
|
||||
result.currencyService = currencyService
|
||||
|
||||
proc delete*(self: Controller) =
|
||||
discard
|
||||
|
@ -133,3 +137,9 @@ proc authenticateUser*(self: Controller, keyUid = "") =
|
|||
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_WALLET_SECTION_TRANSACTION_MODULE_IDENTIFIER,
|
||||
keyUid: keyUid)
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
|
||||
|
||||
proc getCurrencyFormat*(self: Controller, symbol: string): CurrencyFormatDto =
|
||||
return self.currencyService.getCurrencyFormat(symbol)
|
||||
|
||||
proc findTokenSymbolByAddress*(self: Controller, address: string): string =
|
||||
return self.walletAccountService.findTokenSymbolByAddress(address)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import strformat
|
||||
import ../../../shared_models/currency_amount
|
||||
|
||||
type
|
||||
Item* = object
|
||||
|
@ -8,25 +9,25 @@ type
|
|||
blockNumber: string
|
||||
blockHash: string
|
||||
timestamp: int
|
||||
gasPrice: string
|
||||
gasLimit: string
|
||||
gasUsed: string
|
||||
gasPrice: CurrencyAmount
|
||||
gasLimit: int
|
||||
gasUsed: int
|
||||
nonce: string
|
||||
txStatus: string
|
||||
value: string
|
||||
value: CurrencyAmount
|
||||
fro: string
|
||||
to: string
|
||||
contract: string
|
||||
chainId: int
|
||||
maxFeePerGas: string
|
||||
maxPriorityFeePerGas: string
|
||||
maxFeePerGas: CurrencyAmount
|
||||
maxPriorityFeePerGas: CurrencyAmount
|
||||
input: string
|
||||
txHash: string
|
||||
multiTransactionID: int
|
||||
isTimeStamp: bool
|
||||
baseGasFees: string
|
||||
totalFees: string
|
||||
maxTotalFees: string
|
||||
baseGasFees: CurrencyAmount
|
||||
totalFees: CurrencyAmount
|
||||
maxTotalFees: CurrencyAmount
|
||||
symbol: string
|
||||
|
||||
proc initItem*(
|
||||
|
@ -36,25 +37,25 @@ proc initItem*(
|
|||
blockNumber: string,
|
||||
blockHash: string,
|
||||
timestamp: int,
|
||||
gasPrice: string,
|
||||
gasLimit: string,
|
||||
gasUsed: string,
|
||||
gasPrice: CurrencyAmount,
|
||||
gasLimit: int,
|
||||
gasUsed: int,
|
||||
nonce: string,
|
||||
txStatus: string,
|
||||
value: string,
|
||||
value: CurrencyAmount,
|
||||
fro: string,
|
||||
to: string,
|
||||
contract: string,
|
||||
chainId: int,
|
||||
maxFeePerGas: string,
|
||||
maxPriorityFeePerGas: string,
|
||||
maxFeePerGas: CurrencyAmount,
|
||||
maxPriorityFeePerGas: CurrencyAmount,
|
||||
input: string,
|
||||
txHash: string,
|
||||
multiTransactionID: int,
|
||||
isTimeStamp: bool,
|
||||
baseGasFees: string,
|
||||
totalFees: string,
|
||||
maxTotalFees: string,
|
||||
baseGasFees: CurrencyAmount,
|
||||
totalFees: CurrencyAmount,
|
||||
maxTotalFees: CurrencyAmount,
|
||||
symbol: string
|
||||
): Item =
|
||||
result.id = id
|
||||
|
@ -84,6 +85,19 @@ proc initItem*(
|
|||
result.maxTotalFees = maxTotalFees
|
||||
result.symbol = symbol
|
||||
|
||||
proc initTimestampItem*(timestamp: int): Item =
|
||||
result.timestamp = timestamp
|
||||
result.gasPrice = newCurrencyAmount()
|
||||
result.value = newCurrencyAmount()
|
||||
result.chainId = 0
|
||||
result.maxFeePerGas = newCurrencyAmount()
|
||||
result.maxPriorityFeePerGas = newCurrencyAmount()
|
||||
result.multiTransactionID = 0
|
||||
result.isTimeStamp = true
|
||||
result.baseGasFees = newCurrencyAmount()
|
||||
result.totalFees = newCurrencyAmount()
|
||||
result.maxTotalFees = newCurrencyAmount()
|
||||
|
||||
proc `$`*(self: Item): string =
|
||||
result = fmt"""AllTokensItem(
|
||||
id: {self.id},
|
||||
|
@ -132,13 +146,13 @@ proc getBlockHash*(self: Item): string =
|
|||
proc getTimestamp*(self: Item): int =
|
||||
return self.timestamp
|
||||
|
||||
proc getGasPrice*(self: Item): string =
|
||||
proc getGasPrice*(self: Item): CurrencyAmount =
|
||||
return self.gasPrice
|
||||
|
||||
proc getGasLimit*(self: Item): string =
|
||||
proc getGasLimit*(self: Item): int =
|
||||
return self.gasLimit
|
||||
|
||||
proc getGasUsed*(self: Item): string =
|
||||
proc getGasUsed*(self: Item): int =
|
||||
return self.gasUsed
|
||||
|
||||
proc getNonce*(self: Item): string =
|
||||
|
@ -147,7 +161,7 @@ proc getNonce*(self: Item): string =
|
|||
proc getTxStatus*(self: Item): string =
|
||||
return self.txStatus
|
||||
|
||||
proc getValue*(self: Item): string =
|
||||
proc getValue*(self: Item): CurrencyAmount =
|
||||
return self.value
|
||||
|
||||
proc getfrom*(self: Item): string =
|
||||
|
@ -162,10 +176,10 @@ proc getContract*(self: Item): string =
|
|||
proc getChainId*(self: Item): int =
|
||||
return self.chainId
|
||||
|
||||
proc getMaxFeePerGas*(self: Item): string =
|
||||
proc getMaxFeePerGas*(self: Item): CurrencyAmount =
|
||||
return self.maxFeePerGas
|
||||
|
||||
proc getMaxPriorityFeePerGas*(self: Item): string =
|
||||
proc getMaxPriorityFeePerGas*(self: Item): CurrencyAmount =
|
||||
return self.maxPriorityFeePerGas
|
||||
|
||||
proc getInput*(self: Item): string =
|
||||
|
@ -180,13 +194,13 @@ proc getMultiTransactionID*(self: Item): int =
|
|||
proc getIsTimeStamp*(self: Item): bool =
|
||||
return self.isTimeStamp
|
||||
|
||||
proc getBaseGasFees*(self: Item): string =
|
||||
proc getBaseGasFees*(self: Item): CurrencyAmount =
|
||||
return self.baseGasFees
|
||||
|
||||
proc getTotalFees*(self: Item): string =
|
||||
proc getTotalFees*(self: Item): CurrencyAmount =
|
||||
return self.totalFees
|
||||
|
||||
proc getMaxTotalFees*(self: Item): string =
|
||||
proc getMaxTotalFees*(self: Item): CurrencyAmount =
|
||||
return self.maxTotalFees
|
||||
|
||||
proc getSymbol*(self: Item): string =
|
||||
|
|
|
@ -2,7 +2,6 @@ import NimQml, Tables, strutils, strformat, sequtils, tables, sugar, algorithm,
|
|||
|
||||
import ./item
|
||||
import ../../../../../app_service/service/eth/utils as eth_service_utils
|
||||
import ../../../../../app_service/service/transaction/dto
|
||||
|
||||
type
|
||||
ModelRole {.pure.} = enum
|
||||
|
@ -197,41 +196,12 @@ QtObject:
|
|||
if result == 0:
|
||||
result = cmp(x.getNonce(), y.getNonce())
|
||||
|
||||
proc addNewTransactions*(self: Model, transactions: seq[TransactionDto], wasFetchMore: bool) =
|
||||
proc addNewTransactions*(self: Model, transactions: seq[Item], wasFetchMore: bool) =
|
||||
let existingTxIds = self.items.map(tx => tx.getId())
|
||||
let hasNewTxs = transactions.len > 0 and transactions.any(tx => not existingTxIds.contains(tx.id))
|
||||
let hasNewTxs = transactions.len > 0 and transactions.any(tx => not existingTxIds.contains(tx.getId()))
|
||||
|
||||
if hasNewTxs or not wasFetchMore:
|
||||
let newTxItems = transactions.map(t => initItem(
|
||||
t.id,
|
||||
t.typeValue,
|
||||
t.address,
|
||||
t.blockNumber,
|
||||
t.blockHash,
|
||||
toInt(t.timestamp),
|
||||
t.gasPrice,
|
||||
t.gasLimit,
|
||||
t.gasUsed,
|
||||
t.nonce,
|
||||
t.txStatus,
|
||||
t.value,
|
||||
t.fromAddress,
|
||||
t.to,
|
||||
t.contract,
|
||||
t.chainId,
|
||||
t.maxFeePerGas,
|
||||
t.maxPriorityFeePerGas,
|
||||
t.input,
|
||||
t.txHash,
|
||||
t.multiTransactionID,
|
||||
false,
|
||||
t.baseGasFees,
|
||||
t.totalFees,
|
||||
t.maxTotalFees,
|
||||
t.symbol
|
||||
))
|
||||
|
||||
var allTxs = self.items.concat(newTxItems)
|
||||
var allTxs = self.items.concat(transactions)
|
||||
allTxs.sort(cmpTransactions, SortOrder.Descending)
|
||||
eth_service_utils.deduplicate(allTxs, tx => tx.getTxHash())
|
||||
|
||||
|
@ -241,7 +211,7 @@ QtObject:
|
|||
for tx in allTxs:
|
||||
let durationInDays = (tempTimeStamp.toTimeInterval() - fromUnix(tx.getTimestamp()).toTimeInterval()).days
|
||||
if(durationInDays != 0):
|
||||
itemsWithDateHeaders.add(initItem("", "", "", "", "", tx.getTimestamp(), "", "", "", "", "", "", "", "", "", 0, "", "", "", "", 0, true, "", "", "", ""))
|
||||
itemsWithDateHeaders.add(initTimestampItem(tx.getTimestamp()))
|
||||
itemsWithDateHeaders.add(tx)
|
||||
tempTimeStamp = fromUnix(tx.getTimestamp())
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import NimQml, stint, json
|
||||
import NimQml, stint, json, sequtils, sugar
|
||||
|
||||
import ./io_interface, ./view, ./controller
|
||||
import ./io_interface, ./view, ./controller, ./item, ./utils
|
||||
import ../io_interface as delegate_interface
|
||||
import ../../../../global/global_singleton
|
||||
import ../../../../core/eventemitter
|
||||
import ../../../../../app_service/service/transaction/service as transaction_service
|
||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||
import ../../../../../app_service/service/network/service as network_service
|
||||
import ../../../../../app_service/service/currency/service as currency_service
|
||||
|
||||
export io_interface
|
||||
|
||||
|
@ -39,11 +40,12 @@ proc newModule*(
|
|||
transactionService: transaction_service.Service,
|
||||
walletAccountService: wallet_account_service.Service,
|
||||
networkService: network_service.Service,
|
||||
currencyService: currency_service.Service,
|
||||
): Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = newView(result)
|
||||
result.controller = controller.newController(result, events, transactionService, walletAccountService, networkService)
|
||||
result.controller = controller.newController(result, events, transactionService, walletAccountService, networkService, currencyService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
method delete*(self: Module) =
|
||||
|
@ -58,13 +60,35 @@ method load*(self: Module) =
|
|||
method isLoaded*(self: Module): bool =
|
||||
return self.moduleLoaded
|
||||
|
||||
proc getResolvedSymbol*(self: Module, transaction: TransactionDto): string =
|
||||
if transaction.symbol != "":
|
||||
result = transaction.symbol
|
||||
else:
|
||||
let contractSymbol = self.controller.findTokenSymbolByAddress(transaction.contract)
|
||||
if contractSymbol != "":
|
||||
result = contractSymbol
|
||||
else:
|
||||
result = "ETH"
|
||||
|
||||
proc transactionsToItems(self: Module, transactions: seq[TransactionDto]) : seq[Item] =
|
||||
let gweiFormat = self.controller.getCurrencyFormat("Gwei")
|
||||
let ethFormat = self.controller.getCurrencyFormat("ETH")
|
||||
|
||||
transactions.map(t => (block:
|
||||
let resolvedSymbol = self.getResolvedSymbol(t)
|
||||
transactionToItem(t, resolvedSymbol, self.controller.getCurrencyFormat(resolvedSymbol), ethFormat, gweiFormat)
|
||||
))
|
||||
|
||||
proc setPendingTx(self: Module) =
|
||||
self.view.setPendingTx(self.transactionsToItems(self.controller.checkPendingTransactions()))
|
||||
|
||||
method viewDidLoad*(self: Module) =
|
||||
let accounts = self.getWalletAccounts()
|
||||
|
||||
self.moduleLoaded = true
|
||||
self.delegate.transactionsModuleDidLoad()
|
||||
|
||||
self.view.setPendingTx(self.controller.checkPendingTransactions())
|
||||
self.setPendingTx()
|
||||
|
||||
method switchAccount*(self: Module, accountIndex: int) =
|
||||
let walletAccount = self.controller.getWalletAccount(accountIndex)
|
||||
|
@ -86,7 +110,7 @@ method loadTransactions*(self: Module, address: string, toBlock: string = "0x0",
|
|||
self.controller.loadTransactions(address, toBlockParsed, txLimit, loadMore)
|
||||
|
||||
method setTrxHistoryResult*(self: Module, transactions: seq[TransactionDto], address: string, wasFetchMore: bool) =
|
||||
self.view.setTrxHistoryResult(transactions, address, wasFetchMore)
|
||||
self.view.setTrxHistoryResult(self.transactionsToItems(transactions), address, wasFetchMore)
|
||||
|
||||
method setHistoryFetchState*(self: Module, addresses: seq[string], isFetching: bool) =
|
||||
self.view.setHistoryFetchStateForAccounts(addresses, isFetching)
|
||||
|
@ -144,7 +168,7 @@ method onUserAuthenticated*(self: Module, password: string) =
|
|||
|
||||
method transactionWasSent*(self: Module, result: string) =
|
||||
self.view.transactionWasSent(result)
|
||||
self.view.setPendingTx(self.controller.checkPendingTransactions())
|
||||
self.setPendingTx()
|
||||
|
||||
method suggestedFees*(self: Module, chainId: int): string =
|
||||
return self.controller.suggestedFees(chainId)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import strutils, stint
|
||||
import ../../../../global/global_singleton
|
||||
|
||||
import ../../../../../app_service/service/transaction/dto
|
||||
import ../../../../../app_service/service/currency/dto as currency_dto
|
||||
import ../../../shared_models/currency_amount
|
||||
import ../../../shared_models/currency_amount_utils
|
||||
|
||||
import ./item
|
||||
|
||||
proc hex2GweiCurrencyAmount(hexValueStr: string, gweiFormat: CurrencyFormatDto): CurrencyAmount =
|
||||
let value = parseFloat(singletonInstance.utils.hex2Gwei(hexValueStr))
|
||||
return currencyAmountToItem(value, gweiFormat)
|
||||
|
||||
proc hex2EthCurrencyAmount(hexValueStr: string, ethFormat: CurrencyFormatDto): CurrencyAmount =
|
||||
let value = parseFloat(singletonInstance.utils.hex2Eth(hexValueStr))
|
||||
return currencyAmountToItem(value, ethFormat)
|
||||
|
||||
proc hex2TokenCurrencyAmount(hexValueStr: string, tokenFormat: CurrencyFormatDto): CurrencyAmount =
|
||||
let value = parseFloat(singletonInstance.utils.hex2Eth(hexValueStr))
|
||||
return currencyAmountToItem(value, tokenFormat)
|
||||
|
||||
proc transactionToItem*(t: TransactionDto, resolvedSymbol: string, tokenFormat: CurrencyFormatDto, ethFormat: CurrencyFormatDto, gweiFormat: CurrencyFormatDto): Item =
|
||||
return initItem(
|
||||
t.id,
|
||||
t.typeValue,
|
||||
t.address,
|
||||
t.blockNumber,
|
||||
t.blockHash,
|
||||
toInt(t.timestamp),
|
||||
hex2EthCurrencyAmount(t.gasPrice, ethFormat),
|
||||
parseInt(singletonInstance.utils.hex2Dec(t.gasLimit)),
|
||||
parseInt(singletonInstance.utils.hex2Dec(t.gasUsed)),
|
||||
t.nonce,
|
||||
t.txStatus,
|
||||
hex2TokenCurrencyAmount(t.value, tokenFormat),
|
||||
t.fromAddress,
|
||||
t.to,
|
||||
t.contract,
|
||||
t.chainId,
|
||||
hex2GweiCurrencyAmount(t.maxFeePerGas, gweiFormat),
|
||||
hex2GweiCurrencyAmount(t.maxPriorityFeePerGas, gweiFormat),
|
||||
t.input,
|
||||
t.txHash,
|
||||
t.multiTransactionID,
|
||||
false,
|
||||
hex2GweiCurrencyAmount(t.baseGasFees, gweiFormat),
|
||||
hex2GweiCurrencyAmount(t.totalFees, gweiFormat),
|
||||
hex2GweiCurrencyAmount(t.maxTotalFees, gweiFormat),
|
||||
resolvedSymbol
|
||||
)
|
|
@ -69,7 +69,7 @@ QtObject:
|
|||
self.setHistoryFetchState(address, true)
|
||||
self.delegate.loadTransactions(address, toBlock, limit, loadMore)
|
||||
|
||||
proc setTrxHistoryResult*(self: View, transactions: seq[TransactionDto], address: string, wasFetchMore: bool) =
|
||||
proc setTrxHistoryResult*(self: View, transactions: seq[Item], address: string, wasFetchMore: bool) =
|
||||
if not self.models.hasKey(address):
|
||||
self.models[address] = newModel()
|
||||
|
||||
|
@ -160,8 +160,9 @@ QtObject:
|
|||
|
||||
proc suggestedRoutesReady*(self: View, suggestedRoutes: string) {.signal.}
|
||||
|
||||
proc setPendingTx*(self: View, pendingTx: seq[TransactionDto]) =
|
||||
proc setPendingTx*(self: View, pendingTx: seq[Item]) =
|
||||
for tx in pendingTx:
|
||||
if not self.models.hasKey(tx.fromAddress):
|
||||
self.models[tx.fromAddress] = newModel()
|
||||
self.models[tx.fromAddress].addNewTransactions(@[tx], false)
|
||||
let fromAddress = tx.getfrom()
|
||||
if not self.models.hasKey(fromAddress):
|
||||
self.models[fromAddress] = newModel()
|
||||
self.models[fromAddress].addNewTransactions(@[tx], false)
|
||||
|
|
|
@ -26,6 +26,9 @@ QtObject:
|
|||
result.displayDecimals = displayDecimals
|
||||
result.stripTrailingZeroes = stripTrailingZeroes
|
||||
|
||||
proc newCurrencyAmount*: CurrencyAmount =
|
||||
result = newCurrencyAmount(0.0, "", 0, true)
|
||||
|
||||
proc `$`*(self: CurrencyAmount): string =
|
||||
result = fmt"""CurrencyAmount(
|
||||
amount: {self.amount},
|
||||
|
|
|
@ -46,7 +46,7 @@ QtObject:
|
|||
)
|
||||
return self.fiatCurrencyFormatCache[symbol]
|
||||
|
||||
proc getTokenCurrencyFormat(self: Service, symbol: string): CurrencyFormatDto =
|
||||
proc getTokenCurrencyFormat(self: Service, symbol: string, allowFetching: bool): CurrencyFormatDto =
|
||||
if self.tokenCurrencyFormatCache.isCached(symbol):
|
||||
return self.tokenCurrencyFormatCache.get(symbol)
|
||||
|
||||
|
@ -61,19 +61,21 @@ QtObject:
|
|||
)
|
||||
updateCache = true
|
||||
else:
|
||||
let price = self.tokenService.getCachedTokenPrice(symbol, DECIMALS_CALCULATION_CURRENCY)
|
||||
let price = (if allowFetching: self.tokenService.getTokenPrice(symbol, DECIMALS_CALCULATION_CURRENCY) else :
|
||||
self.tokenService.getCachedTokenPrice(symbol, DECIMALS_CALCULATION_CURRENCY))
|
||||
result = CurrencyFormatDto(
|
||||
symbol: symbol,
|
||||
displayDecimals: getTokenDisplayDecimals(price),
|
||||
stripTrailingZeroes: true
|
||||
)
|
||||
updateCache = self.tokenService.isCachedTokenPriceRecent(symbol, DECIMALS_CALCULATION_CURRENCY)
|
||||
updateCache = (if allowFetching: true else:
|
||||
self.tokenService.isCachedTokenPriceRecent(symbol, DECIMALS_CALCULATION_CURRENCY))
|
||||
|
||||
if updateCache:
|
||||
self.tokenCurrencyFormatCache.set(symbol, result)
|
||||
|
||||
proc getCurrencyFormat*(self: Service, symbol: string): CurrencyFormatDto =
|
||||
proc getCurrencyFormat*(self: Service, symbol: string, allowFetching: bool = true): CurrencyFormatDto =
|
||||
if self.isCurrencyFiat(symbol):
|
||||
return self.getFiatCurrencyFormat(symbol)
|
||||
else:
|
||||
return self.getTokenCurrencyFormat(symbol)
|
||||
return self.getTokenCurrencyFormat(symbol, allowFetching)
|
||||
|
|
|
@ -50,7 +50,7 @@ SplitView {
|
|||
}
|
||||
|
||||
currencyStore: QtObject {
|
||||
property string currentCurrency: "usd"
|
||||
property string currentCurrency: "USD"
|
||||
property string currentCurrencySymbol: "$"
|
||||
|
||||
readonly property ListModel currenciesModel: ListModel {
|
||||
|
|
|
@ -21,16 +21,15 @@ StatusListItem {
|
|||
property string networkColor
|
||||
property string networkName
|
||||
property string shortTimeStamp
|
||||
property string resolvedSymbol: root.symbol != "" ? root.symbol : "ETH"
|
||||
property string savedAddressName
|
||||
|
||||
state: "normal"
|
||||
asset.isImage: true
|
||||
asset.name: Style.png("tokens/%1".arg(resolvedSymbol))
|
||||
asset.name: root.symbol ? Style.png("tokens/%1".arg(root.symbol)) : ""
|
||||
title: modelData !== undefined && !!modelData ?
|
||||
isIncoming ? qsTr("Receive %1").arg(resolvedSymbol) : !!savedAddressName ?
|
||||
qsTr("Send %1 to %2").arg(resolvedSymbol).arg(savedAddressName) :
|
||||
qsTr("Send %1 to %2").arg(resolvedSymbol).arg(Utils.compactAddress(modelData.to, 4)): ""
|
||||
isIncoming ? qsTr("Receive %1").arg(root.symbol) : !!savedAddressName ?
|
||||
qsTr("Send %1 to %2").arg(root.symbol).arg(savedAddressName) :
|
||||
qsTr("Send %1 to %2").arg(root.symbol).arg(Utils.compactAddress(modelData.to, 4)): ""
|
||||
subTitle: shortTimeStamp
|
||||
inlineTagModel: 1
|
||||
inlineTagDelegate: InformationTag {
|
||||
|
|
|
@ -458,7 +458,7 @@ StatusDialog {
|
|||
maxFiatFees: popup.isLoading ? "..." : LocaleUtils.currencyAmountToLocaleString(d.totalFeesInFiat)
|
||||
totalTimeEstimate: popup.isLoading? "..." : d.totalTimeEstimate
|
||||
pending: d.isPendingTx || popup.isLoading
|
||||
visible: d.recipientReady && amountToSendInput.cryptoValueToSend.amount > 0 && !d.errorMode
|
||||
visible: d.recipientReady && amountToSendInput.cryptoValueToSend && amountToSendInput.cryptoValueToSend.amount > 0 && !d.errorMode
|
||||
onNextButtonClicked: popup.sendTransaction()
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ ModalPopup {
|
|||
property var transaction
|
||||
title: qsTr("Transaction Details")
|
||||
|
||||
readonly property bool isTransactionValid: transaction !== undefined
|
||||
|
||||
Item {
|
||||
id: confirmations
|
||||
anchors.left: parent.left
|
||||
|
@ -26,7 +28,7 @@ ModalPopup {
|
|||
StyledText {
|
||||
id: confirmationsCount
|
||||
text: {
|
||||
if(transaction !== undefined)
|
||||
if(popup.isTransactionValid)
|
||||
return RootStore.getLatestBlockNumber() - RootStore.hex2Dec(transaction.blockNumber) + qsTr(" confirmation(s)")
|
||||
else
|
||||
return ""
|
||||
|
@ -75,7 +77,7 @@ ModalPopup {
|
|||
|
||||
StyledText {
|
||||
id: valueBlock
|
||||
text: transaction !== undefined ? RootStore.hex2Dec(transaction.blockNumber) : ""
|
||||
text: popup.isTransactionValid ? RootStore.hex2Dec(transaction.blockNumber) : ""
|
||||
font.pixelSize: 14
|
||||
anchors.left: labelBlock.right
|
||||
anchors.leftMargin: Style.current.padding
|
||||
|
@ -102,7 +104,7 @@ ModalPopup {
|
|||
|
||||
Address {
|
||||
id: valueHash
|
||||
text: transaction !== undefined ? transaction.id : ""
|
||||
text: popup.isTransactionValid ? transaction.id : ""
|
||||
width: 160
|
||||
maxWidth: parent.width - labelHash.width - Style.current.padding
|
||||
color: Style.current.textColor
|
||||
|
@ -130,7 +132,7 @@ ModalPopup {
|
|||
|
||||
Address {
|
||||
id: valueFrom
|
||||
text: transaction !== undefined ? transaction.from: ""
|
||||
text: popup.isTransactionValid ? transaction.from: ""
|
||||
color: Style.current.textColor
|
||||
width: 160
|
||||
font.pixelSize: 14
|
||||
|
@ -157,7 +159,7 @@ ModalPopup {
|
|||
|
||||
Address {
|
||||
id: valueTo
|
||||
text: transaction !== undefined ? transaction.to: ""
|
||||
text: popup.isTransactionValid ? transaction.to: ""
|
||||
color: Style.current.textColor
|
||||
width: 160
|
||||
font.pixelSize: 14
|
||||
|
@ -184,7 +186,7 @@ ModalPopup {
|
|||
|
||||
StyledText {
|
||||
id: valueGasLimit
|
||||
text: transaction !== undefined ? RootStore.hex2Dec(transaction.gasLimit): ""
|
||||
text: popup.isTransactionValid ? LocaleUtils.currencyAmountToLocaleString(transaction.gasLimit): ""
|
||||
font.pixelSize: 14
|
||||
anchors.left: labelGasLimit.right
|
||||
anchors.leftMargin: Style.current.padding
|
||||
|
@ -209,7 +211,7 @@ ModalPopup {
|
|||
|
||||
StyledText {
|
||||
id: valueGasPrice
|
||||
text: transaction !== undefined ? RootStore.hex2Eth(transaction.gasPrice): ""
|
||||
text: popup.isTransactionValid ? LocaleUtils.currencyAmountToLocaleString(transaction.gasPrice): ""
|
||||
font.pixelSize: 14
|
||||
anchors.left: labelGasPrice.right
|
||||
anchors.leftMargin: Style.current.padding
|
||||
|
@ -234,7 +236,7 @@ ModalPopup {
|
|||
|
||||
StyledText {
|
||||
id: valueGasUsed
|
||||
text: transaction !== undefined ? RootStore.hex2Dec(transaction.gasUsed): ""
|
||||
text: popup.isTransactionValid ? LocaleUtils.currencyAmountToLocaleString(transaction.gasUsed): ""
|
||||
font.pixelSize: 14
|
||||
anchors.left: labelGasUsed.right
|
||||
anchors.leftMargin: Style.current.padding
|
||||
|
@ -259,7 +261,7 @@ ModalPopup {
|
|||
|
||||
StyledText {
|
||||
id: valueNonce
|
||||
text: transaction !== undefined ? RootStore.hex2Dec(transaction.nonce) : ""
|
||||
text: popup.isTransactionValid ? RootStore.hex2Dec(transaction.nonce) : ""
|
||||
font.pixelSize: 14
|
||||
anchors.left: labelNonce.right
|
||||
anchors.leftMargin: Style.current.padding
|
||||
|
|
|
@ -9,16 +9,26 @@ QtObject {
|
|||
// We should probably refactor this and move those functions to some Wallet module.
|
||||
property ProfileSectionStore profileSectionStore: ProfileSectionStore {}
|
||||
|
||||
property string currentCurrency: walletSection.currentCurrency
|
||||
property int currentCurrencyModelIndex: {
|
||||
function getModelIndexForKey(key) {
|
||||
for (var i=0; i<currenciesModel.count; i++) {
|
||||
if (currenciesModel.get(i).key === currentCurrency) {
|
||||
if (currenciesModel.get(i).key === key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getModelIndexForShortName(shortName) {
|
||||
for (var i=0; i<currenciesModel.count; i++) {
|
||||
if (currenciesModel.get(i).shortName === shortName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
property string currentCurrency: walletSection.currentCurrency
|
||||
property int currentCurrencyModelIndex: getModelIndexForShortName(currentCurrency)
|
||||
property string currentCurrencySymbol: currenciesModel.get(currentCurrencyModelIndex).symbol
|
||||
|
||||
property ListModel currenciesModel: ListModel {
|
||||
|
@ -939,7 +949,7 @@ QtObject {
|
|||
function updateCurrenciesModel() {
|
||||
var isSelected = false
|
||||
for(var i = 0; i < currenciesModel.count; i++) {
|
||||
if(root.currentCurrency === root.currenciesModel.get(i).key) {
|
||||
if(root.currentCurrency === root.currenciesModel.get(i).shortName) {
|
||||
root.currenciesModel.get(i).selected = isSelected = true
|
||||
}
|
||||
else {
|
||||
|
@ -952,8 +962,10 @@ QtObject {
|
|||
root.currenciesModel.get(0).selected = true
|
||||
}
|
||||
|
||||
function updateCurrency(newCurrency) {
|
||||
walletSection.updateCurrency(newCurrency)
|
||||
function updateCurrency(newCurrenyKey) {
|
||||
let index = getModelIndexForKey(newCurrenyKey)
|
||||
let shortName = root.currenciesModel.get(index).shortName
|
||||
walletSection.updateCurrency(shortName)
|
||||
}
|
||||
|
||||
function getCurrencyAmount(amount, symbol) {
|
||||
|
|
|
@ -115,12 +115,12 @@ ColumnLayout {
|
|||
TransactionDelegate {
|
||||
property bool modelDataValid: modelData !== undefined && !!modelData
|
||||
isIncoming: modelDataValid ? modelData.to === account.address: false
|
||||
cryptoValue: modelDataValid ? RootStore.getCurrencyAmount(RootStore.hex2Eth(modelData.value), resolvedSymbol) : ""
|
||||
fiatValue: RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency)
|
||||
cryptoValue: modelDataValid ? modelData.value : undefined
|
||||
fiatValue: modelDataValid ? RootStore.getFiatValue(cryptoValue.amount, symbol, RootStore.currentCurrency) : undefined
|
||||
networkIcon: modelDataValid ? RootStore.getNetworkIcon(modelData.chainId) : ""
|
||||
networkColor: modelDataValid ? RootStore.getNetworkColor(modelData.chainId) : ""
|
||||
networkName: modelDataValid ? RootStore.getNetworkShortName(modelData.chainId) : ""
|
||||
symbol: modelDataValid ? !!modelData.symbol ? modelData.symbol : RootStore.findTokenSymbolByAddress(modelData.contract) : ""
|
||||
symbol: modelDataValid ? modelData.symbol : ""
|
||||
transferStatus: modelDataValid ? RootStore.hex2Dec(modelData.txStatus) : ""
|
||||
shortTimeStamp: modelDataValid ? LocaleUtils.formatTime(modelData.timestamp * 1000, Locale.ShortFormat) : ""
|
||||
savedAddressName: modelDataValid ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
|
||||
|
|
|
@ -215,7 +215,7 @@ Item {
|
|||
id: contactsLabel
|
||||
font.pixelSize: 15
|
||||
color: Theme.palette.directColor1
|
||||
text: store.hex2Eth(value)
|
||||
text: LocaleUtils.currencyAmountToLocaleString(value)
|
||||
}
|
||||
]
|
||||
onClicked: contactSelected(title, RecipientSelector.Type.Address)
|
||||
|
|
|
@ -22,15 +22,15 @@ Item {
|
|||
property var contactsStore
|
||||
property var transaction
|
||||
property var sendModal
|
||||
|
||||
readonly property bool isTransactionValid: transaction !== undefined && !!transaction
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property bool isIncoming: root.transaction !== undefined && !!root.transaction ? root.transaction.to === currentAccount.address : false
|
||||
readonly property string savedAddressNameTo: root.transaction !== undefined && !!root.transaction ? d.getNameForSavedWalletAddress(transaction.to) : ""
|
||||
readonly property string savedAddressNameFrom: root.transaction !== undefined && !!root.transaction ? d.getNameForSavedWalletAddress(transaction.from): ""
|
||||
readonly property string from: root.transaction !== undefined && !!root.transaction ? !!savedAddressNameFrom ? savedAddressNameFrom : Utils.compactAddress(transaction.from, 4): ""
|
||||
readonly property string to: root.transaction !== undefined && !!root.transaction ? !!savedAddressNameTo ? savedAddressNameTo : Utils.compactAddress(transaction.to, 4): ""
|
||||
readonly property bool isIncoming: root.isTransactionValid ? root.transaction.to === currentAccount.address : false
|
||||
readonly property string savedAddressNameTo: root.isTransactionValid ? d.getNameForSavedWalletAddress(transaction.to) : ""
|
||||
readonly property string savedAddressNameFrom: root.isTransactionValid ? d.getNameForSavedWalletAddress(transaction.from): ""
|
||||
readonly property string from: root.isTransactionValid ? !!savedAddressNameFrom ? savedAddressNameFrom : Utils.compactAddress(transaction.from, 4): ""
|
||||
readonly property string to: root.isTransactionValid ? !!savedAddressNameTo ? savedAddressNameTo : Utils.compactAddress(transaction.to, 4): ""
|
||||
|
||||
function getNameForSavedWalletAddress(address) {
|
||||
return RootStore.getNameForSavedWalletAddress(address)
|
||||
|
@ -59,18 +59,17 @@ Item {
|
|||
|
||||
modelData: transaction
|
||||
isIncoming: d.isIncoming
|
||||
property bool transactionValid: root.transaction !== undefined && !!root.transaction
|
||||
cryptoValue: transactionValid ? RootStore.getCurrencyAmount(RootStore.hex2Eth(transaction.value), resolvedSymbol): undefined
|
||||
fiatValue: transactionValid ? RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency): ""
|
||||
networkIcon: transactionValid ? RootStore.getNetworkIcon(transaction.chainId): ""
|
||||
networkColor: transactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
|
||||
networkName: transactionValid ? RootStore.getNetworkShortName(transaction.chainId): ""
|
||||
symbol: transactionValid ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
|
||||
transferStatus: transactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
|
||||
shortTimeStamp: transactionValid ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
|
||||
savedAddressName: transactionValid ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
|
||||
title: d.isIncoming ? qsTr("Received %1 %2 from %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.from) :
|
||||
qsTr("Sent %1 %2 to %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.to)
|
||||
cryptoValue: root.isTransactionValid ? transaction.value : undefined
|
||||
fiatValue: root.isTransactionValid ? RootStore.getFiatValue(cryptoValue.amount, symbol, RootStore.currentCurrency): undefined
|
||||
networkIcon: root.isTransactionValid ? RootStore.getNetworkIcon(transaction.chainId): ""
|
||||
networkColor: root.isTransactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
|
||||
networkName: root.isTransactionValid ? RootStore.getNetworkShortName(transaction.chainId): ""
|
||||
symbol: root.isTransactionValid ? transaction.symbol : ""
|
||||
transferStatus: root.isTransactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
|
||||
shortTimeStamp: root.isTransactionValid ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
|
||||
savedAddressName: root.isTransactionValid ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
|
||||
title: d.isIncoming ? qsTr("Received %1 from %2").arg(LocaleUtils.currencyAmountToLocaleString(cryptoValue)).arg(d.from) :
|
||||
qsTr("Sent %1 to %2").arg(LocaleUtils.currencyAmountToLocaleString(cryptoValue)).arg(d.to)
|
||||
sensor.enabled: false
|
||||
color: Theme.palette.statusListItem.backgroundColor
|
||||
state: "big"
|
||||
|
@ -80,9 +79,9 @@ Item {
|
|||
width: parent.width
|
||||
|
||||
name: d.isIncoming ? d.savedAddressNameFrom : d.savedAddressNameTo
|
||||
address: root.transaction !== undefined && !!root.transaction ? d.isIncoming ? transaction.from : transaction.to : ""
|
||||
address: root.isTransactionValid ? d.isIncoming ? transaction.from : transaction.to : ""
|
||||
title: d.isIncoming ? d.from : d.to
|
||||
subTitle: root.transaction !== undefined && !!root.transaction ? d.isIncoming ? !!d.savedAddressNameFrom ? Utils.compactAddress(transaction.from, 4) : "" : !!d.savedAddressNameTo ? Utils.compactAddress(transaction.to, 4) : "": ""
|
||||
subTitle: root.isTransactionValid ? d.isIncoming ? !!d.savedAddressNameFrom ? Utils.compactAddress(transaction.from, 4) : "" : !!d.savedAddressNameTo ? Utils.compactAddress(transaction.to, 4) : "": ""
|
||||
store: RootStore
|
||||
contactsStore: root.contactsStore
|
||||
onOpenSendModal: root.sendModal.open(address);
|
||||
|
@ -129,7 +128,7 @@ Item {
|
|||
statusListItemTitle.color: Theme.palette.baseColor1
|
||||
|
||||
title: qsTr("Data" )
|
||||
subTitle: root.transaction !== undefined && !!root.transaction ? root.transaction.input : ""
|
||||
subTitle: root.isTransactionValid ? root.transaction.input : ""
|
||||
components: [
|
||||
CopyToClipBoardButton {
|
||||
icon.width: 15
|
||||
|
@ -156,18 +155,17 @@ Item {
|
|||
width: parent.width
|
||||
modelData: transaction
|
||||
isIncoming: d.isIncoming
|
||||
property bool transactionValid: root.transaction !== undefined && !!root.transaction
|
||||
cryptoValue: transactionValid ? RootStore.getCurrencyAmount(RootStore.hex2Eth(transaction.value), resolvedSymbol): ""
|
||||
fiatValue: RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency)
|
||||
networkIcon: transactionValid ? RootStore.getNetworkIcon(transaction.chainId) : ""
|
||||
networkColor: transactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
|
||||
networkName: transactionValid ? RootStore.getNetworkShortName(transaction.chainId): ""
|
||||
symbol: transactionValid ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
|
||||
transferStatus: transactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
|
||||
shortTimeStamp: transactionValid ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
|
||||
savedAddressName: transactionValid ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
|
||||
title: d.isIncoming ? qsTr("Received %1 %2 from %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.from) :
|
||||
qsTr("Sent %1 %2 to %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.to)
|
||||
cryptoValue: root.isTransactionValid ? transaction.value: undefined
|
||||
fiatValue: root.isTransactionValid ? RootStore.getFiatValue(cryptoValue.amount, symbol, RootStore.currentCurrency): undefined
|
||||
networkIcon: root.isTransactionValid ? RootStore.getNetworkIcon(transaction.chainId) : ""
|
||||
networkColor: root.isTransactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
|
||||
networkName: root.isTransactionValid ? RootStore.getNetworkShortName(transaction.chainId): ""
|
||||
symbol: root.isTransactionValid ? transaction.symbol : ""
|
||||
transferStatus: root.isTransactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
|
||||
shortTimeStamp: root.isTransactionValid ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
|
||||
savedAddressName: root.isTransactionValid ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
|
||||
title: d.isIncoming ? qsTr("Received %1 from %2").arg(LocaleUtils.currencyAmountToLocaleString(cryptoValue)).arg(d.from) :
|
||||
qsTr("Sent %1 to %2").arg(LocaleUtils.currencyAmountToLocaleString(cryptoValue)).arg(d.to)
|
||||
sensor.enabled: false
|
||||
color: Theme.palette.statusListItem.backgroundColor
|
||||
border.width: 1
|
||||
|
@ -186,7 +184,7 @@ Item {
|
|||
maxWidth: parent.width
|
||||
primaryText: qsTr("Confirmations")
|
||||
secondaryText: {
|
||||
if(root.transaction !== undefined && !!root.transaction )
|
||||
if(root.isTransactionValid)
|
||||
return Math.abs(RootStore.getLatestBlockNumber() - RootStore.hex2Dec(root.transaction.blockNumber))
|
||||
else
|
||||
return ""
|
||||
|
@ -195,7 +193,7 @@ Item {
|
|||
InformationTile {
|
||||
maxWidth: parent.width
|
||||
primaryText: qsTr("Nonce")
|
||||
secondaryText: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Dec(root.transaction.nonce) : ""
|
||||
secondaryText: root.isTransactionValid ? RootStore.hex2Dec(root.transaction.nonce) : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,23 +210,29 @@ Item {
|
|||
id: baseFee
|
||||
maxWidth: parent.width
|
||||
primaryText: qsTr("Base fee")
|
||||
secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 Gwei").arg(RootStore.hex2Gwei(root.transaction.baseGasFees)) : ""
|
||||
secondaryText: root.isTransactionValid ? qsTr("%1").arg(LocaleUtils.currencyAmountToLocaleString(root.transaction.baseGasFees)) : ""
|
||||
}
|
||||
InformationTile {
|
||||
maxWidth: parent.width
|
||||
primaryText: qsTr("Tip")
|
||||
secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 Gwei <font color=\"#939BA1\">• Max: %2 Gwei</font>").
|
||||
arg(RootStore.hex2Gwei(root.transaction.maxPriorityFeePerGas)).
|
||||
arg(RootStore.hex2Gwei(root.transaction.maxFeePerGas)) : ""
|
||||
secondaryText: root.isTransactionValid ? "%1 <font color=\"%2\">• ".
|
||||
arg(LocaleUtils.currencyAmountToLocaleString(root.transaction.maxPriorityFeePerGas)).
|
||||
arg(Theme.palette.baseColor1) +
|
||||
qsTr("Max: %1").
|
||||
arg(LocaleUtils.currencyAmountToLocaleString(root.transaction.maxFeePerGas)) +
|
||||
"</font>" : ""
|
||||
secondaryLabel.textFormat: Text.RichText
|
||||
}
|
||||
}
|
||||
InformationTile {
|
||||
maxWidth: parent.width
|
||||
primaryText: qsTr("Total fee")
|
||||
secondaryText: root.transaction !== undefined && !!root.transaction ? qsTr("%1 Gwei <font color=\"#939BA1\">• Max: %2 Gwei</font>").
|
||||
arg(Utils.stripTrailingZeros(RootStore.hex2Gwei(root.transaction.totalFees))).
|
||||
arg(Utils.stripTrailingZeros(RootStore.hex2Gwei(root.transaction.maxTotalFees))) : ""
|
||||
secondaryText: root.isTransactionValid ? "%1 <font color=\"%2\">• ".
|
||||
arg(LocaleUtils.currencyAmountToLocaleString(root.transaction.totalFees)).
|
||||
arg(Theme.palette.baseColor1) +
|
||||
qsTr("Max: %1").
|
||||
arg(LocaleUtils.currencyAmountToLocaleString(root.transaction.maxTotalFees)) +
|
||||
"</font>" : ""
|
||||
secondaryLabel.textFormat: Text.RichText
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ecbd3a70e9ee36134104e26ce856be0d13f6ae58
|
||||
Subproject commit cedc1a5fd1b2fc29d3e2c5001c27046f541fbcf9
|
Loading…
Reference in New Issue