fix(@desktop/wallet): Remove the 'Load More' button from the Activity view and replace with automatic loading when the user scrolls down using a skeleton loading state
fixes #8987
This commit is contained in:
parent
e8ed91b3ba
commit
2dbf2d4635
|
@ -82,7 +82,7 @@ proc init*(self: Controller) =
|
||||||
|
|
||||||
self.events.on(SIGNAL_TRANSACTION_LOADING_COMPLETED_FOR_ALL_NETWORKS) do(e:Args):
|
self.events.on(SIGNAL_TRANSACTION_LOADING_COMPLETED_FOR_ALL_NETWORKS) do(e:Args):
|
||||||
let args = TransactionsLoadedArgs(e)
|
let args = TransactionsLoadedArgs(e)
|
||||||
self.delegate.setHistoryFetchState(args.address, isFetching = false)
|
self.delegate.setHistoryFetchState(args.address, args.allTxLoaded, isFetching = false)
|
||||||
|
|
||||||
self.events.on(SIGNAL_CURRENCY_FORMATS_UPDATED) do(e:Args):
|
self.events.on(SIGNAL_CURRENCY_FORMATS_UPDATED) do(e:Args):
|
||||||
# TODO: Rebuild Transaction items
|
# TODO: Rebuild Transaction items
|
||||||
|
|
|
@ -34,7 +34,7 @@ method setTrxHistoryResult*(self: AccessInterface, transactions: seq[Transaction
|
||||||
method setHistoryFetchState*(self: AccessInterface, addresses: seq[string], isFetching: bool) {.base.} =
|
method setHistoryFetchState*(self: AccessInterface, addresses: seq[string], isFetching: bool) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method setHistoryFetchState*(self: AccessInterface, address: string, isFetching: bool) {.base.} =
|
method setHistoryFetchState*(self: AccessInterface, address: string, allTxLoaded: bool, isFetching: bool) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method setIsNonArchivalNode*(self: AccessInterface, isNonArchivalNode: bool) {.base.} =
|
method setIsNonArchivalNode*(self: AccessInterface, isNonArchivalNode: bool) {.base.} =
|
||||||
|
|
|
@ -29,6 +29,7 @@ type
|
||||||
totalFees: CurrencyAmount
|
totalFees: CurrencyAmount
|
||||||
maxTotalFees: CurrencyAmount
|
maxTotalFees: CurrencyAmount
|
||||||
symbol: string
|
symbol: string
|
||||||
|
loadingTransaction: bool
|
||||||
|
|
||||||
proc initItem*(
|
proc initItem*(
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -56,7 +57,8 @@ proc initItem*(
|
||||||
baseGasFees: CurrencyAmount,
|
baseGasFees: CurrencyAmount,
|
||||||
totalFees: CurrencyAmount,
|
totalFees: CurrencyAmount,
|
||||||
maxTotalFees: CurrencyAmount,
|
maxTotalFees: CurrencyAmount,
|
||||||
symbol: string
|
symbol: string,
|
||||||
|
loadingTransaction: bool = false
|
||||||
): Item =
|
): Item =
|
||||||
result.id = id
|
result.id = id
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
@ -84,6 +86,7 @@ proc initItem*(
|
||||||
result.totalFees = totalFees
|
result.totalFees = totalFees
|
||||||
result.maxTotalFees = maxTotalFees
|
result.maxTotalFees = maxTotalFees
|
||||||
result.symbol = symbol
|
result.symbol = symbol
|
||||||
|
result.loadingTransaction = loadingTransaction
|
||||||
|
|
||||||
proc initTimestampItem*(timestamp: int): Item =
|
proc initTimestampItem*(timestamp: int): Item =
|
||||||
result.timestamp = timestamp
|
result.timestamp = timestamp
|
||||||
|
@ -98,6 +101,20 @@ proc initTimestampItem*(timestamp: int): Item =
|
||||||
result.totalFees = newCurrencyAmount()
|
result.totalFees = newCurrencyAmount()
|
||||||
result.maxTotalFees = newCurrencyAmount()
|
result.maxTotalFees = newCurrencyAmount()
|
||||||
|
|
||||||
|
proc initLoadingItem*(): Item =
|
||||||
|
result.timestamp = 0
|
||||||
|
result.gasPrice = newCurrencyAmount()
|
||||||
|
result.value = newCurrencyAmount()
|
||||||
|
result.chainId = 0
|
||||||
|
result.maxFeePerGas = newCurrencyAmount()
|
||||||
|
result.maxPriorityFeePerGas = newCurrencyAmount()
|
||||||
|
result.multiTransactionID = 0
|
||||||
|
result.isTimeStamp = false
|
||||||
|
result.baseGasFees = newCurrencyAmount()
|
||||||
|
result.totalFees = newCurrencyAmount()
|
||||||
|
result.maxTotalFees = newCurrencyAmount()
|
||||||
|
result.loadingTransaction = true
|
||||||
|
|
||||||
proc `$`*(self: Item): string =
|
proc `$`*(self: Item): string =
|
||||||
result = fmt"""AllTokensItem(
|
result = fmt"""AllTokensItem(
|
||||||
id: {self.id},
|
id: {self.id},
|
||||||
|
@ -126,6 +143,7 @@ proc `$`*(self: Item): string =
|
||||||
totalFees: {self.totalFees},
|
totalFees: {self.totalFees},
|
||||||
maxTotalFees: {self.maxTotalFees},
|
maxTotalFees: {self.maxTotalFees},
|
||||||
symbol: {self.symbol},
|
symbol: {self.symbol},
|
||||||
|
loadingTransaction: {self.loadingTransaction},
|
||||||
]"""
|
]"""
|
||||||
|
|
||||||
proc getId*(self: Item): string =
|
proc getId*(self: Item): string =
|
||||||
|
@ -205,3 +223,6 @@ proc getMaxTotalFees*(self: Item): CurrencyAmount =
|
||||||
|
|
||||||
proc getSymbol*(self: Item): string =
|
proc getSymbol*(self: Item): string =
|
||||||
return self.symbol
|
return self.symbol
|
||||||
|
|
||||||
|
proc getLoadingTransaction*(self: Item): bool =
|
||||||
|
return self.loadingTransaction
|
||||||
|
|
|
@ -31,6 +31,7 @@ type
|
||||||
TotalFees
|
TotalFees
|
||||||
MaxTotalFees
|
MaxTotalFees
|
||||||
Symbol
|
Symbol
|
||||||
|
LoadingTransaction
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -95,7 +96,8 @@ QtObject:
|
||||||
ModelRole.BaseGasFees.int: "baseGasFees",
|
ModelRole.BaseGasFees.int: "baseGasFees",
|
||||||
ModelRole.TotalFees.int: "totalFees",
|
ModelRole.TotalFees.int: "totalFees",
|
||||||
ModelRole.MaxTotalFees.int: "maxTotalFees",
|
ModelRole.MaxTotalFees.int: "maxTotalFees",
|
||||||
ModelRole.Symbol.int: "symbol"
|
ModelRole.Symbol.int: "symbol",
|
||||||
|
ModelRole.LoadingTransaction.int: "loadingTransaction"
|
||||||
}.toTable
|
}.toTable
|
||||||
|
|
||||||
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
||||||
|
@ -161,6 +163,8 @@ QtObject:
|
||||||
result = newQVariant(item.getMaxTotalFees())
|
result = newQVariant(item.getMaxTotalFees())
|
||||||
of ModelRole.Symbol:
|
of ModelRole.Symbol:
|
||||||
result = newQVariant(item.getSymbol())
|
result = newQVariant(item.getSymbol())
|
||||||
|
of ModelRole.LoadingTransaction:
|
||||||
|
result = newQVariant(item.getLoadingTransaction())
|
||||||
|
|
||||||
proc setItems*(self: Model, items: seq[Item]) =
|
proc setItems*(self: Model, items: seq[Item]) =
|
||||||
self.beginResetModel()
|
self.beginResetModel()
|
||||||
|
@ -185,7 +189,7 @@ QtObject:
|
||||||
QtProperty[bool] hasMore:
|
QtProperty[bool] hasMore:
|
||||||
read = getHasMore
|
read = getHasMore
|
||||||
write = setHasMore
|
write = setHasMore
|
||||||
notify = currentTransactionsChanged
|
notify = hasMoreChanged
|
||||||
|
|
||||||
proc cmpTransactions*(x, y: Item): int =
|
proc cmpTransactions*(x, y: Item): int =
|
||||||
# Sort proc to compare transactions from a single account.
|
# Sort proc to compare transactions from a single account.
|
||||||
|
@ -218,3 +222,22 @@ QtObject:
|
||||||
self.items = allTxs
|
self.items = allTxs
|
||||||
self.setItems(itemsWithDateHeaders)
|
self.setItems(itemsWithDateHeaders)
|
||||||
self.setHasMore(true)
|
self.setHasMore(true)
|
||||||
|
|
||||||
|
proc addPageSizeBuffer*(self: Model, pageSize: int) =
|
||||||
|
if pageSize > 0:
|
||||||
|
var itemsWithDateHeaders: seq[Item] = @[]
|
||||||
|
itemsWithDateHeaders.add(initTimestampItem(0))
|
||||||
|
for i in 0 ..< pageSize:
|
||||||
|
self.beginInsertRows(newQModelIndex(), self.itemsWithDateHeaders.len, self.itemsWithDateHeaders.len)
|
||||||
|
self.itemsWithDateHeaders.add(initLoadingItem())
|
||||||
|
self.endInsertRows()
|
||||||
|
self.countChanged()
|
||||||
|
|
||||||
|
proc removePageSizeBuffer*(self: Model) =
|
||||||
|
for i in 0 ..< self.itemsWithDateHeaders.len:
|
||||||
|
if self.itemsWithDateHeaders[i].getLoadingTransaction():
|
||||||
|
self.beginRemoveRows(newQModelIndex(), i, self.itemsWithDateHeaders.len-1)
|
||||||
|
self.itemsWithDateHeaders.delete(i, self.itemsWithDateHeaders.len-1)
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.countChanged()
|
||||||
|
return
|
||||||
|
|
|
@ -115,8 +115,8 @@ method setTrxHistoryResult*(self: Module, transactions: seq[TransactionDto], add
|
||||||
method setHistoryFetchState*(self: Module, addresses: seq[string], isFetching: bool) =
|
method setHistoryFetchState*(self: Module, addresses: seq[string], isFetching: bool) =
|
||||||
self.view.setHistoryFetchStateForAccounts(addresses, isFetching)
|
self.view.setHistoryFetchStateForAccounts(addresses, isFetching)
|
||||||
|
|
||||||
method setHistoryFetchState*(self: Module, address: string, isFetching: bool) =
|
method setHistoryFetchState*(self: Module, address: string, allTxLoaded: bool, isFetching: bool) =
|
||||||
self.view.setHistoryFetchState(address, isFetching)
|
self.view.setHistoryFetchState(address, allTxLoaded, isFetching)
|
||||||
|
|
||||||
method setIsNonArchivalNode*(self: Module, isNonArchivalNode: bool) =
|
method setIsNonArchivalNode*(self: Module, isNonArchivalNode: bool) =
|
||||||
self.view.setIsNonArchivalNode(isNonArchivalNode)
|
self.view.setIsNonArchivalNode(isNonArchivalNode)
|
||||||
|
|
|
@ -48,15 +48,16 @@ QtObject:
|
||||||
|
|
||||||
proc loadingTrxHistoryChanged*(self: View, isLoading: bool, address: string) {.signal.}
|
proc loadingTrxHistoryChanged*(self: View, isLoading: bool, address: string) {.signal.}
|
||||||
|
|
||||||
proc setHistoryFetchState*(self: View, address: string, isFetching: bool) =
|
proc setHistoryFetchState*(self: View, address: string, allTxLoaded: bool, isFetching: bool) =
|
||||||
|
if self.models.hasKey(address):
|
||||||
|
if not isFetching:
|
||||||
|
self.models[address].removePageSizeBuffer()
|
||||||
|
elif isFetching and self.models[address].getCount() == 0:
|
||||||
|
self.models[address].addPageSizeBuffer(20)
|
||||||
|
self.models[address].setHasMore(not allTxLoaded)
|
||||||
self.fetchingHistoryState[address] = isFetching
|
self.fetchingHistoryState[address] = isFetching
|
||||||
self.loadingTrxHistoryChanged(isFetching, address)
|
self.loadingTrxHistoryChanged(isFetching, address)
|
||||||
|
|
||||||
proc setHistoryFetchState*(self: View, accounts: seq[string], isFetching: bool) =
|
|
||||||
for acc in accounts:
|
|
||||||
self.fetchingHistoryState[acc] = isFetching
|
|
||||||
self.loadingTrxHistoryChanged(isFetching, acc)
|
|
||||||
|
|
||||||
proc isFetchingHistory*(self: View, address: string): bool {.slot.} =
|
proc isFetchingHistory*(self: View, address: string): bool {.slot.} =
|
||||||
if self.fetchingHistoryState.hasKey(address):
|
if self.fetchingHistoryState.hasKey(address):
|
||||||
return self.fetchingHistoryState[address]
|
return self.fetchingHistoryState[address]
|
||||||
|
@ -66,7 +67,9 @@ QtObject:
|
||||||
return self.model.getCount() > 0
|
return self.model.getCount() > 0
|
||||||
|
|
||||||
proc loadTransactionsForAccount*(self: View, address: string, toBlock: string = "0x0", limit: int = 20, loadMore: bool = false) {.slot.} =
|
proc loadTransactionsForAccount*(self: View, address: string, toBlock: string = "0x0", limit: int = 20, loadMore: bool = false) {.slot.} =
|
||||||
self.setHistoryFetchState(address, true)
|
if self.models.hasKey(address):
|
||||||
|
self.setHistoryFetchState(address, allTxLoaded=not self.models[address].getHasMore(), isFetching=true)
|
||||||
|
self.models[address].addPageSizeBuffer(limit)
|
||||||
self.delegate.loadTransactions(address, toBlock, limit, loadMore)
|
self.delegate.loadTransactions(address, toBlock, limit, loadMore)
|
||||||
|
|
||||||
proc setTrxHistoryResult*(self: View, transactions: seq[Item], address: string, wasFetchMore: bool) =
|
proc setTrxHistoryResult*(self: View, transactions: seq[Item], address: string, wasFetchMore: bool) =
|
||||||
|
@ -74,10 +77,15 @@ QtObject:
|
||||||
self.models[address] = newModel()
|
self.models[address] = newModel()
|
||||||
|
|
||||||
self.models[address].addNewTransactions(transactions, wasFetchMore)
|
self.models[address].addNewTransactions(transactions, wasFetchMore)
|
||||||
|
if self.fetchingHistoryState.hasKey(address) and self.fetchingHistoryState[address] and wasFetchMore:
|
||||||
|
self.models[address].addPageSizeBuffer(transactions.len)
|
||||||
|
|
||||||
proc setHistoryFetchStateForAccounts*(self: View, addresses: seq[string], isFetching: bool) =
|
proc setHistoryFetchStateForAccounts*(self: View, addresses: seq[string], isFetching: bool) =
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
self.setHistoryFetchState(address, isFetching)
|
if self.models.hasKey(address):
|
||||||
|
self.setHistoryFetchState(address, allTxLoaded = not self.models[address].getHasMore(), isFetching)
|
||||||
|
else:
|
||||||
|
self.setHistoryFetchState(address, allTxLoaded = false, isFetching)
|
||||||
|
|
||||||
proc setModel*(self: View, address: string) {.slot.} =
|
proc setModel*(self: View, address: string) {.slot.} =
|
||||||
if not self.models.hasKey(address):
|
if not self.models.hasKey(address):
|
||||||
|
@ -165,4 +173,4 @@ QtObject:
|
||||||
let fromAddress = tx.getfrom()
|
let fromAddress = tx.getfrom()
|
||||||
if not self.models.hasKey(fromAddress):
|
if not self.models.hasKey(fromAddress):
|
||||||
self.models[fromAddress] = newModel()
|
self.models[fromAddress] = newModel()
|
||||||
self.models[fromAddress].addNewTransactions(@[tx], false)
|
self.models[fromAddress].addNewTransactions(@[tx], wasFetchMore=false)
|
||||||
|
|
|
@ -17,16 +17,19 @@ type
|
||||||
toBlock: Uint256
|
toBlock: Uint256
|
||||||
limit: int
|
limit: int
|
||||||
loadMore: bool
|
loadMore: bool
|
||||||
|
allTxLoaded: bool
|
||||||
|
|
||||||
const loadTransactionsTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
const loadTransactionsTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
let
|
let
|
||||||
arg = decode[LoadTransactionsTaskArg](argEncoded)
|
arg = decode[LoadTransactionsTaskArg](argEncoded)
|
||||||
limitAsHex = "0x" & eth_utils.stripLeadingZeros(arg.limit.toHex)
|
limitAsHex = "0x" & eth_utils.stripLeadingZeros(arg.limit.toHex)
|
||||||
|
response = transactions.getTransfersByAddress(arg.chainId, arg.address, arg.toBlock, limitAsHex, arg.loadMore).result
|
||||||
output = %*{
|
output = %*{
|
||||||
"address": arg.address,
|
"address": arg.address,
|
||||||
"chainId": arg.chainId,
|
"chainId": arg.chainId,
|
||||||
"history": transactions.getTransfersByAddress(arg.chainId, arg.address, arg.toBlock, limitAsHex, arg.loadMore),
|
"history": response,
|
||||||
"loadMore": arg.loadMore,
|
"loadMore": arg.loadMore,
|
||||||
|
"allTxLoaded": response.getElems().len < arg.limit
|
||||||
}
|
}
|
||||||
arg.finish(output)
|
arg.finish(output)
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,8 @@ type
|
||||||
transactions*: seq[TransactionDto]
|
transactions*: seq[TransactionDto]
|
||||||
address*: string
|
address*: string
|
||||||
wasFetchMore*: bool
|
wasFetchMore*: bool
|
||||||
|
allTxLoaded*: bool
|
||||||
|
tempLoadingTx*: int
|
||||||
|
|
||||||
type
|
type
|
||||||
TransactionSentArgs* = ref object of Args
|
TransactionSentArgs* = ref object of Args
|
||||||
|
@ -96,6 +98,7 @@ QtObject:
|
||||||
settingsService: settings_service.Service
|
settingsService: settings_service.Service
|
||||||
tokenService: token_service.Service
|
tokenService: token_service.Service
|
||||||
txCounter: Table[string, seq[int]]
|
txCounter: Table[string, seq[int]]
|
||||||
|
allTxLoaded: Table[string, bool]
|
||||||
|
|
||||||
# Forward declaration
|
# Forward declaration
|
||||||
proc loadTransactions*(self: Service, address: string, toBlock: Uint256, limit: int = 20, loadMore: bool = false)
|
proc loadTransactions*(self: Service, address: string, toBlock: Uint256, limit: int = 20, loadMore: bool = false)
|
||||||
|
@ -118,6 +121,7 @@ QtObject:
|
||||||
result.settingsService = settingsService
|
result.settingsService = settingsService
|
||||||
result.tokenService = tokenService
|
result.tokenService = tokenService
|
||||||
result.txCounter = initTable[string, seq[int]]()
|
result.txCounter = initTable[string, seq[int]]()
|
||||||
|
result.allTxLoaded = initTable[string, bool]()
|
||||||
|
|
||||||
proc init*(self: Service) =
|
proc init*(self: Service) =
|
||||||
signalConnect(singletonInstance.localAccountSensitiveSettings, "isWalletEnabledChanged()", self, "onIsWalletEnabledChanged()", 2)
|
signalConnect(singletonInstance.localAccountSensitiveSettings, "isWalletEnabledChanged()", self, "onIsWalletEnabledChanged()", 2)
|
||||||
|
@ -202,10 +206,16 @@ QtObject:
|
||||||
let address = historyData["address"].getStr
|
let address = historyData["address"].getStr
|
||||||
let chainID = historyData["chainId"].getInt
|
let chainID = historyData["chainId"].getInt
|
||||||
let wasFetchMore = historyData["loadMore"].getBool
|
let wasFetchMore = historyData["loadMore"].getBool
|
||||||
|
let allTxLoaded = historyData["allTxLoaded"].getBool
|
||||||
var transactions: seq[TransactionDto] = @[]
|
var transactions: seq[TransactionDto] = @[]
|
||||||
for tx in historyData["history"]["result"].getElems():
|
for tx in historyData["history"].getElems():
|
||||||
transactions.add(tx.toTransactionDto())
|
transactions.add(tx.toTransactionDto())
|
||||||
|
|
||||||
|
if self.allTxLoaded.hasKey(address):
|
||||||
|
self.allTxLoaded[address] = self.allTxLoaded[address] and allTxLoaded
|
||||||
|
else:
|
||||||
|
self.allTxLoaded[address] = allTxLoaded
|
||||||
|
|
||||||
# emit event
|
# emit event
|
||||||
self.events.emit(SIGNAL_TRANSACTIONS_LOADED, TransactionsLoadedArgs(
|
self.events.emit(SIGNAL_TRANSACTIONS_LOADED, TransactionsLoadedArgs(
|
||||||
transactions: transactions,
|
transactions: transactions,
|
||||||
|
@ -214,16 +224,18 @@ QtObject:
|
||||||
))
|
))
|
||||||
|
|
||||||
# when requests for all networks are completed then set loading state as completed
|
# when requests for all networks are completed then set loading state as completed
|
||||||
if self.txCounter.hasKey(address):
|
if self.txCounter.hasKey(address) and self.allTxLoaded.hasKey(address) :
|
||||||
var chainIDs = self.txCounter[address]
|
var chainIDs = self.txCounter[address]
|
||||||
chainIDs.del(chainIDs.find(chainID))
|
chainIDs.del(chainIDs.find(chainID))
|
||||||
self.txCounter[address] = chainIDs
|
self.txCounter[address] = chainIDs
|
||||||
if self.txCounter[address].len == 0:
|
if self.txCounter[address].len == 0:
|
||||||
self.txCounter.del(address)
|
self.txCounter.del(address)
|
||||||
self.events.emit(SIGNAL_TRANSACTION_LOADING_COMPLETED_FOR_ALL_NETWORKS, TransactionsLoadedArgs(address: address))
|
self.events.emit(SIGNAL_TRANSACTION_LOADING_COMPLETED_FOR_ALL_NETWORKS, TransactionsLoadedArgs(address: address, allTxLoaded: self.allTxLoaded[address]))
|
||||||
|
|
||||||
proc loadTransactions*(self: Service, address: string, toBlock: Uint256, limit: int = 20, loadMore: bool = false) =
|
proc loadTransactions*(self: Service, address: string, toBlock: Uint256, limit: int = 20, loadMore: bool = false) =
|
||||||
let networks = self.networkService.getNetworks()
|
let networks = self.networkService.getNetworks()
|
||||||
|
self.allTxLoaded.del(address)
|
||||||
|
|
||||||
if not self.txCounter.hasKey(address):
|
if not self.txCounter.hasKey(address):
|
||||||
var networkChains: seq[int] = @[]
|
var networkChains: seq[int] = @[]
|
||||||
self.txCounter[address] = networkChains
|
self.txCounter[address] = networkChains
|
||||||
|
|
|
@ -281,7 +281,6 @@ Rectangle {
|
||||||
lineHeight: 24
|
lineHeight: 24
|
||||||
|
|
||||||
visible: inlineTagModelRepeater.count > 0
|
visible: inlineTagModelRepeater.count > 0
|
||||||
loading: statusListItem.loading
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusScrollView {
|
StatusScrollView {
|
||||||
|
|
|
@ -369,9 +369,15 @@ Item {
|
||||||
Layout.alignment: detailsFlow.isOverflowing ? Qt.AlignLeft : Qt.AlignRight
|
Layout.alignment: detailsFlow.isOverflowing ? Qt.AlignLeft : Qt.AlignRight
|
||||||
iconAsset.icon: "browser"
|
iconAsset.icon: "browser"
|
||||||
tagPrimaryLabel.text: qsTr("Website")
|
tagPrimaryLabel.text: qsTr("Website")
|
||||||
controlBackground.color: Theme.palette.baseColor2
|
|
||||||
controlBackground.border.color: "transparent"
|
|
||||||
visible: typeof token != "undefined" && token && token.assetWebsiteUrl !== ""
|
visible: typeof token != "undefined" && token && token.assetWebsiteUrl !== ""
|
||||||
|
customBackground: Component {
|
||||||
|
Rectangle {
|
||||||
|
color: Theme.palette.baseColor2
|
||||||
|
border.width: 1
|
||||||
|
border.color: "transparent"
|
||||||
|
radius: 36
|
||||||
|
}
|
||||||
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
@ -385,9 +391,15 @@ Item {
|
||||||
image.source: token && token.builtOn !== "" ? Style.svg("tiny/" + RootStore.getNetworkIconUrl(token.builtOn)) : ""
|
image.source: token && token.builtOn !== "" ? Style.svg("tiny/" + RootStore.getNetworkIconUrl(token.builtOn)) : ""
|
||||||
tagPrimaryLabel.text: token && token.builtOn !== "" ? RootStore.getNetworkName(token.builtOn) : "---"
|
tagPrimaryLabel.text: token && token.builtOn !== "" ? RootStore.getNetworkName(token.builtOn) : "---"
|
||||||
tagSecondaryLabel.text: token && token.address !== "" ? token.address : "---"
|
tagSecondaryLabel.text: token && token.address !== "" ? token.address : "---"
|
||||||
controlBackground.color: Theme.palette.baseColor2
|
|
||||||
controlBackground.border.color: "transparent"
|
|
||||||
visible: typeof token != "undefined" && token && token.builtOn !== "" && token.address !== ""
|
visible: typeof token != "undefined" && token && token.builtOn !== "" && token.address !== ""
|
||||||
|
customBackground: Component {
|
||||||
|
Rectangle {
|
||||||
|
color: Theme.palette.baseColor2
|
||||||
|
border.width: 1
|
||||||
|
border.color: "transparent"
|
||||||
|
radius: 36
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,30 +4,44 @@ import QtQuick.Controls 2.14
|
||||||
|
|
||||||
import StatusQ.Core 0.1
|
import StatusQ.Core 0.1
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
|
|
||||||
Control {
|
Control {
|
||||||
|
id: root
|
||||||
|
|
||||||
property alias image : image
|
property alias image : image
|
||||||
property alias iconAsset : iconAsset
|
property alias iconAsset : iconAsset
|
||||||
property alias tagPrimaryLabel: tagPrimaryLabel
|
property alias tagPrimaryLabel: tagPrimaryLabel
|
||||||
property alias tagSecondaryLabel: tagSecondaryLabel
|
property alias tagSecondaryLabel: tagSecondaryLabel
|
||||||
property alias controlBackground: controlBackground
|
|
||||||
property alias rightComponent: rightComponent.sourceComponent
|
property alias rightComponent: rightComponent.sourceComponent
|
||||||
|
property bool loading: false
|
||||||
|
|
||||||
horizontalPadding: Style.current.halfPadding
|
property Component customBackground: Component {
|
||||||
verticalPadding: 5
|
Rectangle {
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
id: controlBackground
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: Theme.palette.baseColor2
|
border.color: Theme.palette.baseColor2
|
||||||
radius: 36
|
radius: 36
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
property var loadingComponent: Component { LoadingComponent {}}
|
||||||
|
}
|
||||||
|
|
||||||
|
horizontalPadding: Style.current.halfPadding
|
||||||
|
verticalPadding: 5
|
||||||
|
|
||||||
|
background: Loader {
|
||||||
|
sourceComponent: root.loading ? d.loadingComponent : root.customBackground
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
visible: !root.loading
|
||||||
// FIXME this could be StatusIcon but it can't load images from an arbitrary URL
|
// FIXME this could be StatusIcon but it can't load images from an arbitrary URL
|
||||||
Image {
|
Image {
|
||||||
id: image
|
id: image
|
||||||
|
|
|
@ -4,6 +4,7 @@ import QtQuick.Layouts 1.3
|
||||||
import StatusQ.Components 0.1
|
import StatusQ.Components 0.1
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
import StatusQ.Core 0.1
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
import shared 1.0
|
import shared 1.0
|
||||||
|
@ -11,6 +12,9 @@ import shared 1.0
|
||||||
StatusListItem {
|
StatusListItem {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property alias cryptoValueText: cryptoValueText
|
||||||
|
property alias fiatValueText: fiatValueText
|
||||||
|
|
||||||
property var modelData
|
property var modelData
|
||||||
property string symbol
|
property string symbol
|
||||||
property bool isIncoming
|
property bool isIncoming
|
||||||
|
@ -24,8 +28,9 @@ StatusListItem {
|
||||||
property string savedAddressName
|
property string savedAddressName
|
||||||
|
|
||||||
state: "normal"
|
state: "normal"
|
||||||
asset.isImage: true
|
asset.isImage: !loading
|
||||||
asset.name: root.symbol ? Style.png("tokens/%1".arg(root.symbol)) : ""
|
asset.name: root.symbol ? Style.png("tokens/%1".arg(root.symbol)) : ""
|
||||||
|
asset.isLetterIdenticon: loading
|
||||||
title: modelData !== undefined && !!modelData ?
|
title: modelData !== undefined && !!modelData ?
|
||||||
isIncoming ? qsTr("Receive %1").arg(root.symbol) : !!savedAddressName ?
|
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(savedAddressName) :
|
||||||
|
@ -36,16 +41,23 @@ StatusListItem {
|
||||||
tagPrimaryLabel.text: networkName
|
tagPrimaryLabel.text: networkName
|
||||||
tagPrimaryLabel.color: networkColor
|
tagPrimaryLabel.color: networkColor
|
||||||
image.source: !!networkIcon ? Style.svg("tiny/%1".arg(networkIcon)) : ""
|
image.source: !!networkIcon ? Style.svg("tiny/%1".arg(networkIcon)) : ""
|
||||||
background: Rectangle {
|
customBackground: Component {
|
||||||
id: controlBackground
|
Rectangle {
|
||||||
implicitWidth: 51
|
|
||||||
implicitHeight: 24
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: Theme.palette.baseColor2
|
border.color: Theme.palette.baseColor2
|
||||||
radius: 36
|
radius: 36
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
width: 51
|
||||||
|
height: root.loading ? textMetrics.tightBoundingRect.height : 24
|
||||||
rightComponent: transferStatus === Constants.TransactionStatus.Success ? completedIcon : loadingIndicator
|
rightComponent: transferStatus === Constants.TransactionStatus.Success ? completedIcon : loadingIndicator
|
||||||
|
loading: root.loading
|
||||||
|
}
|
||||||
|
TextMetrics {
|
||||||
|
id: textMetrics
|
||||||
|
font: statusListItemSubTitle.font
|
||||||
|
text: statusListItemSubTitle.text
|
||||||
}
|
}
|
||||||
components: [
|
components: [
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
@ -57,18 +69,23 @@ StatusListItem {
|
||||||
icon: "arrow-up"
|
icon: "arrow-up"
|
||||||
rotation: isIncoming ? 135 : 45
|
rotation: isIncoming ? 135 : 45
|
||||||
height: 18
|
height: 18
|
||||||
|
visible: !root.loading
|
||||||
}
|
}
|
||||||
StatusBaseText {
|
StatusTextWithLoadingState {
|
||||||
id: cryptoValueText
|
id: cryptoValueText
|
||||||
text: LocaleUtils.currencyAmountToLocaleString(cryptoValue)
|
text: LocaleUtils.currencyAmountToLocaleString(cryptoValue)
|
||||||
color: Theme.palette.directColor1
|
customColor: Theme.palette.directColor1
|
||||||
|
loading: root.loading
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
StatusBaseText {
|
StatusTextWithLoadingState {
|
||||||
|
id: fiatValueText
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: LocaleUtils.currencyAmountToLocaleString(fiatValue)
|
text: LocaleUtils.currencyAmountToLocaleString(fiatValue)
|
||||||
font.pixelSize: 15
|
font.pixelSize: 15
|
||||||
color: Theme.palette.baseColor1
|
customColor: Theme.palette.baseColor1
|
||||||
|
loading: root.loading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -15,39 +15,34 @@ import "../stores"
|
||||||
import "../controls"
|
import "../controls"
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: historyView
|
id: root
|
||||||
|
|
||||||
property var account
|
property var account
|
||||||
property int pageSize: 20 // number of transactions per page
|
property int pageSize: 20 // number of transactions per page
|
||||||
property bool isLoading: false
|
|
||||||
|
|
||||||
signal launchTransactionDetail(var transaction)
|
signal launchTransactionDetail(var transaction)
|
||||||
|
|
||||||
function fetchHistory() {
|
function fetchHistory() {
|
||||||
if (RootStore.isFetchingHistory(historyView.account.address)) {
|
if (!RootStore.isFetchingHistory(root.account.address)) {
|
||||||
isLoading = true
|
d.isLoading = true
|
||||||
} else {
|
RootStore.loadTransactionsForAccount(root.account.address, pageSize)
|
||||||
RootStore.loadTransactionsForAccount(historyView.account.address, pageSize)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
property bool isLoading: false
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: RootStore.history
|
target: RootStore.history
|
||||||
function onLoadingTrxHistoryChanged(isLoading: bool, address: string) {
|
function onLoadingTrxHistoryChanged(isLoading: bool, address: string) {
|
||||||
if (historyView.account.address.toLowerCase() === address.toLowerCase()) {
|
if (root.account.address.toLowerCase() === address.toLowerCase()) {
|
||||||
historyView.isLoading = isLoading
|
d.isLoading = isLoading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: loadingImg
|
|
||||||
active: isLoading
|
|
||||||
sourceComponent: loadingImageComponent
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
||||||
Layout.rightMargin: Style.current.padding
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: nonArchivalNodeError
|
id: nonArchivalNodeError
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
|
@ -60,7 +55,7 @@ ColumnLayout {
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: noTxs
|
id: noTxs
|
||||||
visible: !isLoading && transactionListRoot.count === 0
|
visible: !d.isLoading && transactionListRoot.count === 0
|
||||||
text: qsTr("No transactions found")
|
text: qsTr("No transactions found")
|
||||||
font.pixelSize: Style.current.primaryTextFontSize
|
font.pixelSize: Style.current.primaryTextFontSize
|
||||||
}
|
}
|
||||||
|
@ -76,26 +71,17 @@ ColumnLayout {
|
||||||
|
|
||||||
model: RootStore.historyTransactions
|
model: RootStore.historyTransactions
|
||||||
delegate: Loader {
|
delegate: Loader {
|
||||||
width: parent.width
|
width: ListView.view.width
|
||||||
sourceComponent: isTimeStamp ? dateHeader : transactionDelegate
|
sourceComponent: isTimeStamp ? dateHeader : transactionDelegate
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
item.modelData = model
|
item.modelData = model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
footer: footerComp
|
||||||
|
|
||||||
ScrollBar.vertical: StatusScrollBar {}
|
ScrollBar.vertical: StatusScrollBar {}
|
||||||
|
|
||||||
footer: StatusButton {
|
onAtYEndChanged: if(atYEnd && RootStore.historyTransactions.hasMore) fetchHistory()
|
||||||
id: loadMoreButton
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
text: qsTr("Load More")
|
|
||||||
// TODO: handle case when requested limit === transaction count -- there
|
|
||||||
// is currently no way to know that there are no more results
|
|
||||||
enabled: !isLoading && RootStore.historyTransactions.hasMore
|
|
||||||
onClicked: fetchHistory()
|
|
||||||
loading: isLoading
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
@ -113,23 +99,51 @@ ColumnLayout {
|
||||||
Component {
|
Component {
|
||||||
id: transactionDelegate
|
id: transactionDelegate
|
||||||
TransactionDelegate {
|
TransactionDelegate {
|
||||||
property bool modelDataValid: modelData !== undefined && !!modelData
|
property bool modelDataValid: !!modelData
|
||||||
isIncoming: modelDataValid ? modelData.to === account.address: false
|
isIncoming: modelDataValid ? modelData.to === account.address: false
|
||||||
cryptoValue: modelDataValid ? modelData.value : undefined
|
cryptoValue: modelDataValid ? modelData.value : undefined
|
||||||
fiatValue: modelDataValid ? RootStore.getFiatValue(cryptoValue.amount, symbol, RootStore.currentCurrency) : undefined
|
fiatValue: modelDataValid && !!cryptoValue ? RootStore.getFiatValue(cryptoValue.amount, symbol, RootStore.currentCurrency) : undefined
|
||||||
networkIcon: modelDataValid ? RootStore.getNetworkIcon(modelData.chainId) : ""
|
networkIcon: modelDataValid ? RootStore.getNetworkIcon(modelData.chainId) : ""
|
||||||
networkColor: modelDataValid ? RootStore.getNetworkColor(modelData.chainId) : ""
|
networkColor: modelDataValid ? RootStore.getNetworkColor(modelData.chainId) : ""
|
||||||
networkName: modelDataValid ? RootStore.getNetworkShortName(modelData.chainId) : ""
|
networkName: modelDataValid ? RootStore.getNetworkShortName(modelData.chainId) : ""
|
||||||
symbol: modelDataValid ? modelData.symbol : ""
|
symbol: modelDataValid && !!modelData.symbol ? modelData.symbol : ""
|
||||||
transferStatus: modelDataValid ? RootStore.hex2Dec(modelData.txStatus) : ""
|
transferStatus: modelDataValid ? RootStore.hex2Dec(modelData.txStatus) : ""
|
||||||
shortTimeStamp: modelDataValid ? LocaleUtils.formatTime(modelData.timestamp * 1000, Locale.ShortFormat) : ""
|
shortTimeStamp: modelDataValid ? LocaleUtils.formatTime(modelData.timestamp * 1000, Locale.ShortFormat) : ""
|
||||||
savedAddressName: modelDataValid ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
|
savedAddressName: modelDataValid ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
|
||||||
onClicked: launchTransactionDetail(modelData)
|
onClicked: launchTransactionDetail(modelData)
|
||||||
|
loading: modelDataValid ? modelData.loadingTransaction : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: loadingImageComponent
|
id: footerComp
|
||||||
StatusLoadingIndicator {}
|
ColumnLayout {
|
||||||
|
width: root.width
|
||||||
|
visible: !RootStore.historyTransactions.hasMore && transactionListRoot.count !== 0
|
||||||
|
spacing: 12
|
||||||
|
Rectangle {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Style.curent.padding
|
||||||
|
Layout.preferredWidth: parent.width - 100
|
||||||
|
Layout.preferredHeight: 1
|
||||||
|
color: Theme.palette.directColor8
|
||||||
|
visible: !RootStore.historyTransactions.hasMore
|
||||||
|
}
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("You have reached the beginning of the activity for this account")
|
||||||
|
font.pixelSize: 13
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
visible: !RootStore.historyTransactions.hasMore
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
StatusButton {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Back to most recent transaction")
|
||||||
|
visible: !RootStore.historyTransactions.hasMore
|
||||||
|
onClicked: transactionListRoot.positionViewAtBeginning()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue