Activity: advanced filters, edited request labels, and used-address requests - #817
Open
epicleafies wants to merge 7 commits into
Open
Activity: advanced filters, edited request labels, and used-address requests#817epicleafies wants to merge 7 commits into
epicleafies wants to merge 7 commits into
Conversation
Editing a saved payment request updated its label everywhere except the pending request row in Activity, which kept showing the old label. The Activity list refreshes a row's label on every read by looking the row's address up in the wallet address book. For a pending receive request that overwrote the label the request itself carries (set when the request is saved and updated when it is edited) with the older stored address book label, so an edited label was lost on the next render. Skip the address book lookup for pending requests so they keep their own label, mirroring how the status refresh already skips pending requests.
Qt Widgets distinguishes a dedicated Other transaction type and a Last month date preset in its transaction filters. The QML Activity filters folded Transaction::Other into Sent and had no Last month preset, so those rows could not be isolated. Classify Transaction::Other (and any unrecognized type) as its own Other filter rather than Sent, matching the label already used for CSV export, and add a Last month date bucket spanning the previous calendar month. Both are surfaced in the Activity type and date filter menus. The minimum amount and custom date range filters Qt Widgets also offers are left for a follow-up, as they need filter input controls that the Activity design does not yet define.
Qt Widgets offers a minimum amount filter and a custom date range in its transaction filters; the QML Activity filters had neither. Add a minimum amount filter: a new Amount button opens a popup with an amount field in the active display unit plus Apply and Reset. The button and the field show the unit the same way as the rest of the app (the BitcoinAmount unit label: a bitcoin sign or sat/sats). The proxy filters on absolute satoshi value, so a send and a receive of the same size both pass a threshold, matching the Qt Widgets behaviour. Add a custom date range: the date menu gains a Custom range entry that switches the popup to a calendar. Qt has no stock date picker, so the day grid is built from ItemDelegate cells in a Grid positioner (never a Repeater inside a Quick Layout, which would hit a Qt 6.4 use-after-free). The first click sets the start and the next sets the end (reordered if earlier); the range then locks until Reset clears it. Endpoints, the days between, and today are marked, with today carrying weight as well as a ring so the state is not conveyed by color alone. Month and year steppers use caret icons from the Bitcoin Icons set (the set has no double-caret, so the year jump composes two carets); the week starts on the locale's first day. The day cells, steppers, and the presets link carry Accessible names and roles. The proxy gains a CustomRange bucket whose bounds include both endpoints. Moving dates across the QML/C++ boundary needs care in both directions because a JavaScript Date and a QDate disagree on the day across time zones: the range is applied through an ISO-string invokable rather than by assigning the QDate properties from QML, and when the popup reopens on an applied range the QDate read back (a UTC-midnight JavaScript Date) is rebuilt at local midnight before it reseeds the calendar, so a reopen does not shift the applied range west of UTC. With a fourth control added, the search field moves to its own row and the date, type, and amount buttons sit in a row beneath it, so they no longer compete with the search field for one row's width. Both apply to the visible list and the CSV export and clear with the existing reset path. The new minAmount, rangeStart and rangeEnd proxy properties are covered by C++ unit tests, the apply paths by QML tests driving the amount field and the calendar (including a reopen round-trip that guards the timezone reseed), and the whole flow by the Activity filter functional test; the filtered-empty hint now mentions the amount filter.
A saved receive request whose address already had a real transaction was skipped by ActivityListModel::addPendingReceiveRequests(), so it never became an Activity row. The Payment request filter could therefore not surface it, even though the transaction details for that address already list the matching requests. Materialize those used-address requests as rows as well, flagged with a new isUsedAddressRequest marker. The proxy shows a used-address request only when the Payment request filter is selected, and hides it in every other view so it does not duplicate the address's real transaction row. Apply the same rule live: when a payment arrives for a pending request, keep the request as a used-address request and add the received transaction as its own row, rather than consuming the request in place. Without this, a fulfilled request dropped out of the Payment request filter until the wallet was reloaded; now the filter is consistent whether the payment just arrived or the wallet was restarted. Used-address requests are not tracked for pending-request fulfillment, since they have no unfulfilled payment left to wait for. The visibility rule is covered by a proxy unit test (hidden by default and under other type filters, shown under the Payment request filter), the used-address flag by a WalletQmlModel unit test, and the live fulfillment path by a WalletQmlModel test that drives a received transaction and asserts the request stays a used-address request while the transaction appears as its own row.
Editing a payment request updated the request record and the Activity row, but not the address's address book label, so the Addresses page kept showing the label the address was created with. Creating a request already labels its address (getNewDestination writes the address book), so the two only diverged on an edit. Write the request label back to the address book whenever a request is saved, so the Addresses page and any other address-book reader reflect an edited request rather than a stale label.
The previous commit made request label edits flow to the address book, but the reverse still diverged: editing a label on the Addresses page wrote only the address book, leaving the payment request and its Activity row showing the old label. Propagate the edit the other way too. When setAddressLabel writes an address book label, update any payment request saved for that address to match: rewrite the stored request, its receive-request history entry, and its Activity row. setAddressLabel is the shared path both the Addresses page and the request-save sync go through, so both edits now converge on one label. The guard skips a request already carrying the new label, so the request-save sync (which calls setAddressLabel) does not redundantly rewrite what it just stored. Covered by a WalletQmlModel unit test that edits an address label and asserts the request record and Activity row follow, and a functional test that renames a request's address on the Addresses page and checks both the address row and the Activity row show the new label.
Editing an address label on the Addresses page rewrites the stored payment request, its history entry, and its Activity row, but a request already open in the Activity detail page or in the locked Receive editor kept showing the old label until it was closed and reopened. The wallet tabs live in a StackLayout that keeps every page alive, so those views hold the shared detailPaymentRequest and currentPaymentRequest objects that were filled when the view loaded, and the reverse sync never touched them. Refresh the held objects from syncPaymentRequestLabelToAddress. The editor object is skipped while a request is being edited so the sync cannot clobber an unsaved draft; the label the user saves wins in that case. The detail page follows automatically through its label bindings. The editor name field does not: any assignment to a TextField text property (typing, or the isEditing re-sync handler) replaces its declarative binding, so the field re-syncs from the labelChanged signal instead, again only while the form is locked. Covered by a unit test asserting both held objects follow an address label edit and that a draft survives one, a QML test asserting the locked editor field follows an external label change, and a functional assertion that the held-open editor shows the edited label after the address is renamed on the Addresses page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR closes three related gaps in the Activity page. The list filters now reach parity with the Qt Widgets transaction view and payment request labels and used-address requests behave correctly. Fixes #707. Fixes #725. Fixes #726.
Added unit, QML and functional tests.