feat(wallet) reload on new transaction downloaded quick win
Show a reload hint button for user to refresh the filter Updates #11233
This commit is contained in:
parent
d17f2c70f1
commit
7a9c76966d
|
@ -181,6 +181,8 @@ QtObject:
|
|||
proc updateFilter*(self: Controller) {.slot.} =
|
||||
self.status.setLoadingData(true)
|
||||
self.model.resetModel(@[])
|
||||
self.eventsHandler.updateSubscribedAddresses(self.addresses)
|
||||
self.status.setNewDataAvailable(false)
|
||||
|
||||
let response = backend_activity.filterActivityAsync(self.addresses, seq[backend_activity.ChainId](self.chainIds), self.currentActivityFilter, 0, FETCH_BATCH_COUNT_DEFAULT)
|
||||
if response.error != nil:
|
||||
|
@ -250,6 +252,10 @@ QtObject:
|
|||
self.status.setStartTimestamp(res.timestamp)
|
||||
)
|
||||
|
||||
self.eventsHandler.onNewDataAvailable(proc () =
|
||||
self.status.setNewDataAvailable(true)
|
||||
)
|
||||
|
||||
proc newController*(transactionsModule: transactions_module.AccessInterface,
|
||||
currencyService: currency_service.Service,
|
||||
tokenService: token_service.Service,
|
||||
|
|
|
@ -11,16 +11,21 @@ import app/core/eventemitter
|
|||
import app/core/signals/types
|
||||
|
||||
import backend/activity as backend_activity
|
||||
import backend/transactions
|
||||
|
||||
type EventCallbackProc = proc (eventObject: JsonNode)
|
||||
type WalletEventCallbackProc = proc (data: WalletSignal)
|
||||
|
||||
# EventsHandler responsible for catching activity related backend events and reporting them
|
||||
QtObject:
|
||||
type
|
||||
EventsHandler* = ref object of QObject
|
||||
events: EventEmitter
|
||||
# Event name and handler pairs
|
||||
eventHandlers: Table[string, EventCallbackProc]
|
||||
walletEventHandlers: Table[string, WalletEventCallbackProc]
|
||||
|
||||
subscribedAddresses: HashSet[string]
|
||||
newDataAvailableFn: proc()
|
||||
|
||||
proc setup(self: EventsHandler) =
|
||||
self.QObject.setup
|
||||
|
@ -37,10 +42,16 @@ QtObject:
|
|||
proc onGetOldestTimestampDone*(self: EventsHandler, handler: EventCallbackProc) =
|
||||
self.eventHandlers[backend_activity.eventActivityGetOldestTimestampDone] = handler
|
||||
|
||||
proc onNewDataAvailable*(self: EventsHandler, handler: proc()) =
|
||||
self.newDataAvailableFn = handler
|
||||
|
||||
proc handleApiEvents(self: EventsHandler, e: Args) =
|
||||
var data = WalletSignal(e)
|
||||
|
||||
if self.eventHandlers.hasKey(data.eventType):
|
||||
if self.walletEventHandlers.hasKey(data.eventType):
|
||||
let callback = self.walletEventHandlers[data.eventType]
|
||||
callback(data)
|
||||
elif self.eventHandlers.hasKey(data.eventType):
|
||||
var responseJson: JsonNode
|
||||
responseJson = parseJson(data.message)
|
||||
|
||||
|
@ -52,14 +63,40 @@ QtObject:
|
|||
else:
|
||||
discard
|
||||
|
||||
proc setupWalletEventHandlers(self: EventsHandler) =
|
||||
self.walletEventHandlers[EventNewTransfers] = proc (data: WalletSignal) =
|
||||
if self.newDataAvailableFn == nil:
|
||||
return
|
||||
|
||||
var contains = false
|
||||
for address in data.accounts:
|
||||
if address in self.subscribedAddresses:
|
||||
contains = true
|
||||
break
|
||||
|
||||
if contains:
|
||||
# TODO: throttle down the number of events to one per 1 seconds until the backend supports subscription
|
||||
|
||||
self.newDataAvailableFn()
|
||||
|
||||
proc newEventsHandler*(events: EventEmitter): EventsHandler =
|
||||
new(result, delete)
|
||||
result.events = events
|
||||
result.eventHandlers = initTable[string, EventCallbackProc]()
|
||||
|
||||
result.subscribedAddresses = initHashSet[string]()
|
||||
|
||||
result.setup()
|
||||
|
||||
result.setupWalletEventHandlers()
|
||||
|
||||
# Register for wallet events
|
||||
let eventsHandler = result
|
||||
result.events.on(SignalType.Wallet.event, proc(e: Args) =
|
||||
eventsHandler.handleApiEvents(e)
|
||||
)
|
||||
)
|
||||
|
||||
proc updateSubscribedAddresses*(self: EventsHandler, addresses: seq[string]) =
|
||||
self.subscribedAddresses.clear()
|
||||
for address in addresses:
|
||||
self.subscribedAddresses.incl(address)
|
|
@ -19,6 +19,8 @@ QtObject:
|
|||
|
||||
startTimestamp: int
|
||||
|
||||
newDataAvailable: bool
|
||||
|
||||
proc setup(self: Status) =
|
||||
self.QObject.setup
|
||||
|
||||
|
@ -96,4 +98,17 @@ QtObject:
|
|||
|
||||
QtProperty[int] startTimestamp:
|
||||
read = getStartTimestamp
|
||||
notify = startTimestampChanged
|
||||
notify = startTimestampChanged
|
||||
|
||||
proc newDataAvailableChanged*(self: Status) {.signal.}
|
||||
|
||||
proc setNewDataAvailable*(self: Status, newDataAvailable: bool) =
|
||||
self.newDataAvailable = newDataAvailable
|
||||
self.newDataAvailableChanged()
|
||||
|
||||
proc getNewDataAvailable*(self: Status): bool {.slot.} =
|
||||
return self.newDataAvailable
|
||||
|
||||
QtProperty[bool] newDataAvailable:
|
||||
read = getNewDataAvailable
|
||||
notify = newDataAvailableChanged
|
|
@ -42,6 +42,7 @@ const SIGNAL_TRANSACTIONS_LOADED* = "transactionsLoaded"
|
|||
const SIGNAL_TRANSACTION_SENT* = "transactionSent"
|
||||
const SIGNAL_SUGGESTED_ROUTES_READY* = "suggestedRoutesReady"
|
||||
const SIGNAL_TRANSACTION_LOADING_COMPLETED_FOR_ALL_NETWORKS* = "transactionsLoadingCompleteForAllNetworks"
|
||||
# TODO: soon to be removed with old transactions module
|
||||
const SIGNAL_HISTORY_FETCHING* = "historyFetching"
|
||||
const SIGNAL_HISTORY_READY* = "historyReady"
|
||||
const SIGNAL_HISTORY_NON_ARCHIVAL_NODE* = "historyNonArchivalNode"
|
||||
|
@ -148,15 +149,13 @@ QtObject:
|
|||
self.events.on(SignalType.Wallet.event) do(e:Args):
|
||||
var data = WalletSignal(e)
|
||||
case data.eventType:
|
||||
of "recent-history-fetching":
|
||||
self.events.emit(SIGNAL_HISTORY_FETCHING, HistoryArgs(addresses: data.accounts))
|
||||
of "recent-history-ready":
|
||||
of transactions.EventRecentHistoryReady:
|
||||
for account in data.accounts:
|
||||
self.loadTransactions(account, stint.fromHex(Uint256, "0x0"))
|
||||
self.events.emit(SIGNAL_HISTORY_READY, HistoryArgs(addresses: data.accounts))
|
||||
of "non-archival-node-detected":
|
||||
of transactions.EventNonArchivalNodeDetected:
|
||||
self.events.emit(SIGNAL_HISTORY_NON_ARCHIVAL_NODE, Args())
|
||||
of "fetching-history-error":
|
||||
of transactions.EventFetchingHistoryError:
|
||||
self.events.emit(SIGNAL_HISTORY_ERROR, Args())
|
||||
|
||||
proc getPendingTransactions*(self: Service): seq[TransactionDto] =
|
||||
|
|
|
@ -7,7 +7,9 @@ import ../app_service/common/utils
|
|||
# mirrors the MultiTransactionType from status-go, services/wallet/transfer/transaction.go
|
||||
type
|
||||
MultiTransactionType* = enum
|
||||
MultiTransactionSend = 0, MultiTransactionSwap = 1, MultiTransactionBridge = 2
|
||||
MultiTransactionSend = 0,
|
||||
MultiTransactionSwap = 1,
|
||||
MultiTransactionBridge = 2
|
||||
|
||||
MultiTransactionCommandDto* = ref object of RootObj
|
||||
fromAddress* {.serializedFieldName("fromAddress").}: string
|
||||
|
@ -28,6 +30,13 @@ type
|
|||
toAmount* {.serializedFieldName("toAmount").}: string
|
||||
multiTxType* {.serializedFieldName("type").}: MultiTransactionType
|
||||
|
||||
# Mirrors the transfer events from status-go, services/wallet/transfer/commands.go
|
||||
const EventNewTransfers*: string = "new-transfers"
|
||||
const EventFetchingRecentHistory*: string = "recent-history-fetching"
|
||||
const EventRecentHistoryReady*: string = "recent-history-ready"
|
||||
const EventFetchingHistoryError*: string = "fetching-history-error"
|
||||
const EventNonArchivalNodeDetected*: string = "non-archival-node-detected"
|
||||
|
||||
proc getTransactionByHash*(chainId: int, hash: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
core.callPrivateRPCWithChainId("eth_getTransactionByHash", chainId, %* [hash])
|
||||
|
||||
|
|
|
@ -104,6 +104,9 @@ QtObject {
|
|||
property color white: getColor('white')
|
||||
property color transparent: "#00000000"
|
||||
|
||||
property color blue: getColor('blue')
|
||||
property color darkBlue: getColor('blue2')
|
||||
|
||||
property color dropShadow: getColor('black', 0.12)
|
||||
property color dropShadow2
|
||||
property color backdropColor: getColor('black', 0.4)
|
||||
|
|
|
@ -39,10 +39,15 @@ QtObject {
|
|||
: null
|
||||
property var historyTransactions: Global.appIsReady? walletSection.activityController.model : null
|
||||
readonly property bool loadingHistoryTransactions: Global.appIsReady && walletSection.activityController.status.loadingData
|
||||
readonly property bool newDataAvailable: Global.appIsReady && walletSection.activityController.status.newDataAvailable
|
||||
property bool isNonArchivalNode: history ? history.isNonArchivalNode
|
||||
: false
|
||||
property var marketValueStore: TokenMarketValuesStore{}
|
||||
|
||||
function resetFilter() {
|
||||
walletSection.activityController.updateFilter()
|
||||
}
|
||||
|
||||
function getNetworkColor(chainId) {
|
||||
return networksModule.all.getChainColor(chainId)
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ ColumnLayout {
|
|||
readonly property bool isInitialLoading: RootStore.loadingHistoryTransactions && transactionListRoot.count === 0
|
||||
property var activityFiltersStore: WalletStores.ActivityFiltersStore{}
|
||||
readonly property int loadingSectionWidth: 56
|
||||
readonly property int topSectionMargin: 20
|
||||
}
|
||||
|
||||
StyledText {
|
||||
|
@ -124,12 +125,16 @@ ColumnLayout {
|
|||
|
||||
delegate: transactionDelegate
|
||||
|
||||
headerPositioning: ListView.OverlayHeader
|
||||
header: headerComp
|
||||
footer: footerComp
|
||||
|
||||
ScrollBar.vertical: StatusScrollBar {}
|
||||
|
||||
section.property: "date"
|
||||
topMargin: d.isInitialLoading ? 0 : -20 // Top margin for first section. Section cannot have different sizes
|
||||
// Adding some magic number to align the top headerComp with the top of the list.
|
||||
// TODO: have to be fixed properly and match the design
|
||||
topMargin: d.isInitialLoading ? 0 : -(2 * d.topSectionMargin + 9) // Top margin for first section. Section cannot have different sizes
|
||||
section.delegate: ColumnLayout {
|
||||
id: sectionDelegate
|
||||
|
||||
|
@ -141,7 +146,7 @@ ColumnLayout {
|
|||
|
||||
Separator {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.topMargin: d.topSectionMargin
|
||||
implicitHeight: 1
|
||||
}
|
||||
|
||||
|
@ -329,4 +334,34 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: headerComp
|
||||
|
||||
Item {
|
||||
width: root.width
|
||||
height: dataUpdatedButton.implicitHeight
|
||||
|
||||
StatusButton {
|
||||
id: dataUpdatedButton
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
text: qsTr("New transactions")
|
||||
|
||||
visible: RootStore.newDataAvailable
|
||||
onClicked: RootStore.resetFilter()
|
||||
|
||||
icon.name: "arrow-up"
|
||||
|
||||
radius: 36
|
||||
textColor: Theme.palette.indirectColor1
|
||||
normalColor: Theme.palette.primaryColor1
|
||||
hoverColor: Theme.palette.miscColor1
|
||||
|
||||
size: StatusBaseButton.Size.Tiny
|
||||
}
|
||||
z: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue