diff --git a/electrum/gui/qml/components/Addresses.qml b/electrum/gui/qml/components/Addresses.qml index 71d441121f46..6c93c899e09c 100644 --- a/electrum/gui/qml/components/Addresses.qml +++ b/electrum/gui/qml/components/Addresses.qml @@ -88,11 +88,13 @@ Pane { placeholderText: qsTr('search') inputMethodHints: Qt.ImhNoPredictiveText + rightPadding: constants.iconSizeMedium + 2 * constants.paddingSmall onTextChanged: listview.filterModel.filterText = text Image { anchors.right: parent.right + anchors.rightMargin: constants.paddingSmall anchors.verticalCenter: parent.verticalCenter source: Qt.resolvedUrl('../../icons/zoom.png') sourceSize.width: constants.iconSizeMedium @@ -276,6 +278,15 @@ Pane { } } + + MouseArea { // unfocus the search box when clicking elsewhere + anchors.fill: parent + onPressed: function(mouse) { + mouse.accepted = false + searchEdit.focus = false + } + } + property color navigationBarBackgroundColor: constants.highlightBackground Component { diff --git a/electrum/gui/qml/components/Channels.qml b/electrum/gui/qml/components/Channels.qml index ea8c1283a67c..143c43df915c 100644 --- a/electrum/gui/qml/components/Channels.qml +++ b/electrum/gui/qml/components/Channels.qml @@ -46,6 +46,7 @@ Pane { FormattedAmount { amount: Daemon.currentWallet.lightningCanSend + redacted: Config.hideAmounts } Label { @@ -55,6 +56,7 @@ Pane { FormattedAmount { amount: Daemon.currentWallet.lightningCanReceive + redacted: Config.hideAmounts } } diff --git a/electrum/gui/qml/components/Preferences.qml b/electrum/gui/qml/components/Preferences.qml index 8595840875b2..24bfcbe10546 100644 --- a/electrum/gui/qml/components/Preferences.qml +++ b/electrum/gui/qml/components/Preferences.qml @@ -139,6 +139,31 @@ Pane { } } + RowLayout { + Layout.columnSpan: 2 + Layout.fillWidth: true + spacing: 0 + Switch { + id: hideAmounts + checked: Config.hideAmounts + onCheckedChanged: { + if (activeFocus) { + Config.hideAmounts = checked + let hint = app.messageDialog.createObject(app, { + title: qsTr('Did you know?'), + text: qsTr('You can also toggle this by long-pressing the balance on the home screen.'), + }) + hint.open() + } + } + } + Label { + Layout.fillWidth: true + text: qsTr('Hide amounts') + wrapMode: Text.Wrap + } + } + Label { text: qsTr('Exchange rate provider') enabled: Daemon.fx.enabled @@ -499,6 +524,7 @@ Pane { thousands.checked = Config.thousandsSeparator currencies.currentIndex = currencies.indexOfValue(Daemon.fx.fiatCurrency) historicRates.checked = Daemon.fx.historicRates + hideAmounts.checked = Config.hideAmounts rateSources.currentIndex = rateSources.indexOfValue(Daemon.fx.rateSource) fiatEnable.checked = Daemon.fx.enabled spendUnconfirmed.checked = Config.spendUnconfirmed diff --git a/electrum/gui/qml/components/controls/AddressDelegate.qml b/electrum/gui/qml/components/controls/AddressDelegate.qml index ebd88015a00a..4e7d0dfff1d6 100644 --- a/electrum/gui/qml/components/controls/AddressDelegate.qml +++ b/electrum/gui/qml/components/controls/AddressDelegate.qml @@ -67,7 +67,7 @@ ItemDelegate { } Label { font.family: FixedFont - text: Config.formatSats(model.balance, false) + text: Config.formatSats(model.balance, false, Config.hideAmounts) visible: model.balance.satsInt != 0 } Label { diff --git a/electrum/gui/qml/components/controls/BalanceSummary.qml b/electrum/gui/qml/components/controls/BalanceSummary.qml index 103159405936..0acb34c6b5ed 100644 --- a/electrum/gui/qml/components/controls/BalanceSummary.qml +++ b/electrum/gui/qml/components/controls/BalanceSummary.qml @@ -15,9 +15,10 @@ Item { property string formattedLightningBalance function setBalances() { - root.formattedConfirmedBalance = Config.formatSats(Daemon.currentWallet.confirmedBalance) - root.formattedTotalBalance = Config.formatSats(Daemon.currentWallet.totalBalance) - root.formattedLightningBalance = Config.formatSats(Daemon.currentWallet.lightningBalance) + 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) if (Daemon.fx.enabled) { root.formattedTotalBalanceFiat = Daemon.fx.fiatValue(Daemon.currentWallet.totalBalance, false) } @@ -28,127 +29,168 @@ Item { leftPadding: constants.paddingXLarge rightPadding: constants.paddingXLarge - GridLayout { - id: balanceLayout - columns: 3 - opacity: Daemon.currentWallet.synchronizing || !Network.isConnected ? 0 : 1 + Item { + implicitWidth: Math.max( + balanceLayout.implicitWidth, + syncLabel.implicitWidth, + statusLabel.implicitWidth, + ) + implicitHeight: balanceLayout.implicitHeight - Label { - font.pixelSize: constants.fontSizeXLarge - text: qsTr('Balance') + ':' - color: Material.accentColor - } + GridLayout { + id: balanceLayout + anchors.centerIn: parent + columns: 3 + opacity: Daemon.currentWallet.synchronizing || !Network.isConnected ? 0 : 1 - Label { - Layout.alignment: Qt.AlignRight - font.pixelSize: constants.fontSizeXLarge - font.family: FixedFont - text: formattedTotalBalance - } - Label { - font.pixelSize: constants.fontSizeXLarge - color: Material.accentColor - text: Config.baseUnit - } + Label { + Layout.row: 0 + Layout.column: 0 + font.pixelSize: constants.fontSizeXLarge + text: qsTr('Balance') + ':' + color: Material.accentColor + } - Item { - visible: Daemon.fx.enabled - Layout.preferredWidth: 1 - } - Label { - Layout.alignment: Qt.AlignRight - visible: Daemon.fx.enabled - font.pixelSize: constants.fontSizeLarge - font.family: FixedFont - color: constants.mutedForeground - text: formattedTotalBalanceFiat - } - Label { - visible: Daemon.fx.enabled - font.pixelSize: constants.fontSizeLarge - color: constants.mutedForeground - text: Daemon.fx.fiatCurrency - } + Label { + Layout.row: 0 + Layout.column: 1 + Layout.alignment: Qt.AlignRight + font.pixelSize: constants.fontSizeXLarge + font.family: FixedFont + text: formattedTotalBalance + } + Label { + Layout.row: 0 + Layout.column: 2 + font.pixelSize: constants.fontSizeXLarge + visible: !Config.hideAmounts + color: Material.accentColor + text: Config.baseUnit + } - RowLayout { - Layout.alignment: Qt.AlignRight - visible: Daemon.currentWallet.isLightning - Image { - Layout.preferredWidth: constants.iconSizeSmall - Layout.preferredHeight: constants.iconSizeSmall - source: '../../../icons/lightning.png' + Item { + Layout.row: 1 + Layout.column: 0 + visible: Daemon.fx.enabled && !Config.hideAmounts + Layout.preferredWidth: 1 + } + Label { + Layout.row: 1 + Layout.column: 1 + Layout.alignment: Qt.AlignRight + visible: Daemon.fx.enabled && !Config.hideAmounts + font.pixelSize: constants.fontSizeLarge + font.family: FixedFont + color: constants.mutedForeground + text: formattedTotalBalanceFiat } Label { - text: qsTr('Lightning') + ':' + Layout.row: 1 + Layout.column: 2 + visible: Daemon.fx.enabled && !Config.hideAmounts + font.pixelSize: constants.fontSizeLarge + color: constants.mutedForeground + text: Daemon.fx.fiatCurrency + } + + RowLayout { + Layout.row: 2 + Layout.column: 0 + Layout.alignment: Qt.AlignRight + visible: Daemon.currentWallet.isLightning + Image { + Layout.preferredWidth: constants.iconSizeSmall + Layout.preferredHeight: constants.iconSizeSmall + source: '../../../icons/lightning.png' + } + Label { + text: qsTr('Lightning') + ':' + font.pixelSize: constants.fontSizeSmall + color: Material.accentColor + } + } + Label { + Layout.row: 2 + Layout.column: 1 + visible: Daemon.currentWallet.isLightning + Layout.alignment: Qt.AlignRight + text: formattedLightningBalance + font.family: FixedFont + } + Label { + Layout.row: 2 + Layout.column: 2 + visible: Daemon.currentWallet.isLightning && !Config.hideAmounts font.pixelSize: constants.fontSizeSmall color: Material.accentColor + text: Config.baseUnit } - } - Label { - visible: Daemon.currentWallet.isLightning - Layout.alignment: Qt.AlignRight - text: formattedLightningBalance - font.family: FixedFont - } - Label { - visible: Daemon.currentWallet.isLightning - font.pixelSize: constants.fontSizeSmall - color: Material.accentColor - text: Config.baseUnit - } - RowLayout { - Layout.alignment: Qt.AlignRight - visible: Daemon.currentWallet.isLightning - Image { - Layout.preferredWidth: constants.iconSizeSmall - Layout.preferredHeight: constants.iconSizeSmall - source: '../../../icons/bitcoin.png' + RowLayout { + Layout.row: 3 + Layout.column: 0 + Layout.alignment: Qt.AlignRight + visible: Daemon.currentWallet.isLightning + Image { + Layout.preferredWidth: constants.iconSizeSmall + Layout.preferredHeight: constants.iconSizeSmall + source: '../../../icons/bitcoin.png' + } + Label { + text: qsTr('On-chain') + ':' + font.pixelSize: constants.fontSizeSmall + color: Material.accentColor + } } Label { - text: qsTr('On-chain') + ':' + id: formattedConfirmedBalanceLabel + Layout.row: 3 + Layout.column: 1 + visible: Daemon.currentWallet.isLightning + Layout.alignment: Qt.AlignRight + text: formattedConfirmedBalance + font.family: FixedFont + } + Label { + Layout.row: 3 + Layout.column: 2 + visible: Daemon.currentWallet.isLightning && !Config.hideAmounts font.pixelSize: constants.fontSizeSmall color: Material.accentColor + text: Config.baseUnit } } + Label { - id: formattedConfirmedBalanceLabel - visible: Daemon.currentWallet.isLightning - Layout.alignment: Qt.AlignRight - text: formattedConfirmedBalance - font.family: FixedFont + id: syncLabel + opacity: Daemon.currentWallet.synchronizing && Network.isConnected ? 1 : 0 + anchors.centerIn: parent + text: Daemon.currentWallet.synchronizingProgress + color: Material.accentColor + font.pixelSize: constants.fontSizeLarge } + Label { - visible: Daemon.currentWallet.isLightning - font.pixelSize: constants.fontSizeSmall + id: statusLabel + opacity: !Network.isConnected ? 1 : 0 + anchors.centerIn: parent + text: Network.serverStatus color: Material.accentColor - text: Config.baseUnit + font.pixelSize: constants.fontSizeLarge } } } - Label { - opacity: Daemon.currentWallet.synchronizing && Network.isConnected ? 1 : 0 - anchors.centerIn: balancePane - text: Daemon.currentWallet.synchronizingProgress - color: Material.accentColor - font.pixelSize: constants.fontSizeLarge - } - - Label { - opacity: !Network.isConnected ? 1 : 0 - anchors.centerIn: balancePane - text: Network.serverStatus - color: Material.accentColor - font.pixelSize: constants.fontSizeLarge - } - MouseArea { anchors.fill: parent onClicked: { app.stack.push(Qt.resolvedUrl('../BalanceDetails.qml')) } + onPressAndHold: { + Config.hideAmounts = !Config.hideAmounts + AppController.haptic() + } } // instead of all these explicit connections, we should expose @@ -157,6 +199,7 @@ Item { target: Config function onBaseUnitChanged() { setBalances() } function onThousandsSeparatorChanged() { setBalances() } + function onHideAmountsChanged() { setBalances() } } Connections { diff --git a/electrum/gui/qml/components/controls/ChannelDelegate.qml b/electrum/gui/qml/components/controls/ChannelDelegate.qml index 66db0ed3713d..2756cbc98912 100644 --- a/electrum/gui/qml/components/controls/ChannelDelegate.qml +++ b/electrum/gui/qml/components/controls/ChannelDelegate.qml @@ -94,12 +94,13 @@ ItemDelegate { } Label { - text: Config.formatSats(model.capacity) + text: Config.formatSats(model.capacity, false, Config.hideAmounts) font.family: FixedFont color: _closed ? constants.mutedForeground : Material.foreground } Label { + visible: !Config.hideAmounts text: Config.baseUnit color: _closed ? constants.mutedForeground : Material.accentColor } diff --git a/electrum/gui/qml/components/controls/CoinDelegate.qml b/electrum/gui/qml/components/controls/CoinDelegate.qml index 7f823b794dbc..1ead9d1f0ad3 100644 --- a/electrum/gui/qml/components/controls/CoinDelegate.qml +++ b/electrum/gui/qml/components/controls/CoinDelegate.qml @@ -68,7 +68,7 @@ ItemDelegate { Layout.preferredWidth: implicitWidth horizontalAlignment: Text.AlignRight font.family: FixedFont - text: Config.formatSats(model.amount, false) + text: Config.formatSats(model.amount, false, Config.hideAmounts) visible: model.amount.satsInt != 0 } Label { diff --git a/electrum/gui/qml/components/controls/FormattedAmount.qml b/electrum/gui/qml/components/controls/FormattedAmount.qml index 43c57e68cbf0..61e42f30a81a 100644 --- a/electrum/gui/qml/components/controls/FormattedAmount.qml +++ b/electrum/gui/qml/components/controls/FormattedAmount.qml @@ -10,6 +10,7 @@ GridLayout { property bool showAlt: true property bool singleLine: true property bool valid: true + property bool redacted: false property bool historic: Daemon.fx.historicRates property int timestamp: 0 @@ -26,11 +27,11 @@ GridLayout { } Label { visible: valid - text: amount.msatsInt != 0 ? Config.formatMilliSats(amount) : Config.formatSats(amount) + text: amount.msatsInt != 0 ? Config.formatMilliSats(amount, false, redacted) : Config.formatSats(amount, false, redacted) font.family: FixedFont } Label { - visible: valid + visible: valid && !redacted text: Config.baseUnit color: Material.accentColor } @@ -38,7 +39,7 @@ GridLayout { Label { id: fiatLabel Layout.columnSpan: singleLine ? 1 : 2 - visible: showAlt && Daemon.fx.enabled && valid + visible: showAlt && Daemon.fx.enabled && valid && !redacted font.pixelSize: constants.fontSizeSmall } diff --git a/electrum/gui/qml/components/controls/HistoryItemDelegate.qml b/electrum/gui/qml/components/controls/HistoryItemDelegate.qml index 6d57f1f69a7b..50e7194a7e08 100644 --- a/electrum/gui/qml/components/controls/HistoryItemDelegate.qml +++ b/electrum/gui/qml/components/controls/HistoryItemDelegate.qml @@ -109,7 +109,7 @@ Item { color: model.value.satsInt >= 0 ? constants.colorCredit : constants.colorDebit function updateText() { - text = Config.formatSats(model.value) + text = Config.formatSats(model.value, false, Config.hideAmounts) } Component.onCompleted: updateText() } @@ -125,7 +125,7 @@ Item { color: constants.mutedForeground function updateText() { - if (delegate.pooled || delegate.listDragActive || !Daemon.fx.enabled) { + if (delegate.pooled || delegate.listDragActive || !Daemon.fx.enabled || Config.hideAmounts) { text = '' } else if (Daemon.fx.historicRates && model.timestamp) { text = Daemon.fx.fiatValueHistoric(model.value, model.timestamp) + ' ' + Daemon.fx.fiatCurrency @@ -158,6 +158,10 @@ Item { target: Config function onBaseUnitChanged() { valueLabel.updateText() } function onThousandsSeparatorChanged() { valueLabel.updateText() } + function onHideAmountsChanged() { + valueLabel.updateText() + fiatLabel.updateText() + } } Connections { diff --git a/electrum/gui/qml/qeconfig.py b/electrum/gui/qml/qeconfig.py index d4ca6b9d5aa0..2d60d14221b7 100644 --- a/electrum/gui/qml/qeconfig.py +++ b/electrum/gui/qml/qeconfig.py @@ -120,6 +120,17 @@ def thousandsSeparator(self, checked): self.config.amt_add_thousands_sep = checked self.thousandsSeparatorChanged.emit() + hideAmountsChanged = pyqtSignal() + @pyqtProperty(bool, notify=hideAmountsChanged) + def hideAmounts(self): + return self.config.GUI_QML_HIDE_AMOUNTS + + @hideAmounts.setter + def hideAmounts(self, hide: bool): + if hide != self.config.GUI_QML_HIDE_AMOUNTS: + self.config.GUI_QML_HIDE_AMOUNTS = hide + self.hideAmountsChanged.emit() + spendUnconfirmedChanged = pyqtSignal() @pyqtProperty(bool, notify=spendUnconfirmedChanged) def spendUnconfirmed(self): @@ -362,9 +373,13 @@ def formatSatsForEditing(self, satoshis): @pyqtSlot('qint64', result=str) @pyqtSlot('qint64', bool, result=str) + @pyqtSlot('qint64', bool, bool, result=str) @pyqtSlot(QEAmount, result=str) @pyqtSlot(QEAmount, bool, result=str) - def formatSats(self, satoshis, with_unit=False): + @pyqtSlot(QEAmount, bool, bool, result=str) + def formatSats(self, satoshis, with_unit=False, hide_amounts: bool = False): + if hide_amounts: + return '****' if isinstance(satoshis, QEAmount): satoshis = satoshis.satsInt if with_unit: @@ -374,8 +389,11 @@ def formatSats(self, satoshis, with_unit=False): @pyqtSlot(QEAmount, result=str) @pyqtSlot(QEAmount, bool, result=str) - def formatMilliSats(self, amount, with_unit=False): + @pyqtSlot(QEAmount, bool, bool, result=str) + def formatMilliSats(self, amount, with_unit=False, hide_amounts: bool = False): assert isinstance(amount, QEAmount), f"unexpected type for amount: {type(amount)}" + if hide_amounts: + return '****' msats = amount.msatsInt precision = 3 # config.amt_precision_post_satoshi is not exposed in preferences if with_unit: diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 4258cbe125a8..a2fcc366ef96 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -856,6 +856,7 @@ def __setattr__(self, name, value): GUI_QML_ALWAYS_ALLOW_SCREENSHOTS = ConfigVar('android_always_allow_screenshots', default=False, type_=bool) GUI_QML_SET_MAX_BRIGHTNESS_ON_QR_DISPLAY = ConfigVar('android_set_max_brightness_on_qr_display', default=True, type_=bool) GUI_QML_PAYMENT_AUTHENTICATION = ConfigVar('qml_payment_authentication', default=False, type_=bool) + GUI_QML_HIDE_AMOUNTS = ConfigVar('gui_qml_hide_amounts', default=False, type_=bool) BTC_AMOUNTS_DECIMAL_POINT = ConfigVar('decimal_point', default=DECIMAL_POINT_DEFAULT, type_=int) BTC_AMOUNTS_FORCE_NZEROS_AFTER_DECIMAL_POINT = ConfigVar(