qml: allow hiding balances and amounts#10636
Conversation
| def redact_amount_string(s: str) -> str: | ||
| """Replace ASCII digits in a formatted-amount string with '*'.""" | ||
| return re.sub(r'[0-9]', '*', s) | ||
|
|
There was a problem hiding this comment.
The length of the amount still exposes some information (*** sat vs ** *** *** sat), but i think that's a good tradeoff between usability and privacy.
I disagree. What is the goal of the feature? If someone has a thousand coins, it does not gain them much that a shoulder-surfer does not see whether it is 1000 or 9999, does it?
Just make it always be (say) four stars, both for shorter and longer "true" values.
That way you can still keep displaying the units (e.g. BTC vs sat) - I imagine hiding the unit would add more complexity.
So e.g.:
36.204 84 mBTC --> **** mBTC
3 620 484 sat --> **** sat
but if it is simple, we could also hide the units, so e.g.:
36.204 84 mBTC --> ****
3 620 484 sat --> ****
btw, I just tested and this last example seems to align with what phoenix is doing
There was a problem hiding this comment.
My thinking was that showing the exact amount of digits provides the benefit of being able to at least roughly estimate the balance as a user, improving the usability of the wallet with the mode enabled.
So e.g. when standing in line to pay for a drink in public you're still able to infer if it you'll be able to pay for the drink instead of having a.) deactivate the obfuscation in public or b.) attempt the payment and then awkwardly fail because the balance was too low. In the end the feature is only beneficial if it doesn't break the main usecase of a wallet, making transactions.
On the other hand I assumed the human mind is optimized to parse digits/numbers very quickly, but has a hard time counting * quickly, so a quick shoulder surfer likely isn't able to get much information as they are not used to the UI and counting * characters from distance.
But OTOH this mostly affects the "sat" unit, if set to "BTC" it will anyways most of the time be *.*** *** ** BTC, so we might as well just show **** uniformly.
What is the goal of the feature?
My motivation was actually not preventing shoulder surfers (though this is probably what the majority of users would benefit from through this feature), but instead being able to demonstrate the app and its features to others without having to use a dummy wallet or reveal my exact balance. For this i agree showing the exact digits is not sufficient but i found it better than not having the obfuscation at all and considered the tradeoffs above for the shoulder surfer usecase.
I'll change it to just use ****.
There was a problem hiding this comment.
Changed it to show **** without unit in relevant places (main view, channels and utxo list), while still showing amounts in the other views (e.g. when confirming a payment or doing a swap).
5061a8a to
9b1a1c8
Compare
Implement hiding the wallet balance and transaction amounts when the user long presses the balance details field in the wallet history view.
Wrap the balanceLayout, syncLabel and statusLabel in an Item
which adjusts its width based on the contents width.
Previously when loading a wallet with a small balanceLayout
the syncLabel ("Synchronizing (X/Y)" string) would exceed the width
of the balancePane and it looks broken.
Un-focuses the search box when clicking elsewhere, moves the zoom icon correctly into the search box instead of overlapping with the search box border.
Adds a toggle for setting the hideAmounts config to the Preferences so users don't have to discover that long pressing the balance toggles it. Also shows an hint to guide the user to the more conveniant way of toggling it by long pressing the balance.
| @pyqtSlot(QEAmount, bool, bool, result=str) | ||
| def formatSats(self, satoshis, with_unit=False, hide_amounts: bool = False): | ||
| if hide_amounts: | ||
| return '****' |
There was a problem hiding this comment.
Instead of passing Config.hideAmounts if you want the configured setting, you could define hide_amounts as a tri-state bool|None and fall back to Config.hideAmounts if it is None. This allows to only specify hide_amounts if it deviates from the configured setting.
There was a problem hiding this comment.
This would work but I think the default case we want, is showing the amounts. If the default case (not passing Config.hideAmounts) would be to read the config, we would actually have to pass False as argument in a lot of places simply to not hide the amounts. This would change more lines than the current approach I think?
Also not passing Config.hideAmounts from QML would remove the QML binding to the config, so if the config changes and the label doesn't get reloaded otherwise it wouldn't update when changing the config.
There was a problem hiding this comment.
This would work but I think the default case we want, is showing the amounts. If the default case (not passing
Config.hideAmounts) would be to read the config, we would actually have to passFalseas argument in a lot of places simply to not hide the amounts. This would change more lines than the current approach I think?
You might be right, it depends what % of amount occurrences we want to hide by config. In the most extreme case, we might only want to force-show amounts for requests and invoices (those not in listviews).
Also not passing
Config.hideAmountsfrom QML would remove the QML binding to the config, so if the config changes and the label doesn't get reloaded otherwise it wouldn't update when changing the config.
I'm quite sure binding doesn't work for Config.formatSats(..., Config.hideAmounts) . Using a property as a parameter in a slot-call is not a binding and doesn't update. This is probably not apparent in the Delegates as they are rerendered often (?) by the ListViews, and in places where updates are triggered using a Connections block + update function (e.g. BalanceSummary).
| let hide = Config.hideAmounts | ||
| root.formattedConfirmedBalance = Config.formatSats(Daemon.currentWallet.confirmedBalance, false, hide) | ||
| root.formattedTotalBalance = Config.formatSats(Daemon.currentWallet.totalBalance, false, hide) | ||
| root.formattedLightningBalance = Config.formatSats(Daemon.currentWallet.lightningBalance, false, hide) |
| Label { | ||
| font.family: FixedFont | ||
| text: Config.formatSats(model.balance, false) | ||
| text: Config.formatSats(model.balance, false, Config.hideAmounts) |
This allows hiding the wallet balance and transaction amounts by long-pressing the balance summary of the main view in QML (or toggling the config in the Preferences).
When enabled the amounts will be replaced by a fixed
****string and the units and fiat are hidden.Screencast_20260512_165512.webm