1
0

Merge pull request #9820 from f321x/qml_terms_of_use

qml: add terms of use to setup wizard
This commit is contained in:
accumulator
2025-05-13 15:54:34 +02:00
committed by GitHub
9 changed files with 185 additions and 50 deletions

View File

@@ -0,0 +1,24 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import "wizard"
Wizard {
id: termsofusewizard
wizardTitle: ""
iconSource: ""
header: null
enter: null // disable transition
wiz: Daemon.termsOfUseWizard
finishButtonText: qsTr('Next')
Component.onCompleted: {
var view = wiz.startWizard()
_loadNextComponent(view)
}
}

View File

@@ -360,6 +360,14 @@ ApplicationWindow
} }
} }
property alias termsOfUseWizard: _termsOfUseWizard
Component {
id: _termsOfUseWizard
TermsOfUseWizard {
onClosed: destroy()
}
}
property alias serverConnectWizard: _serverConnectWizard property alias serverConnectWizard: _serverConnectWizard
Component { Component {
id: _serverConnectWizard id: _serverConnectWizard
@@ -517,38 +525,57 @@ ApplicationWindow
app.scanDialog = _qtScanDialog app.scanDialog = _qtScanDialog
} }
if (!Config.autoConnectDefined) { function continueWithServerConnection() {
var dialog = serverConnectWizard.createObject(app) if (!Config.autoConnectDefined) {
// without completed serverConnectWizard we can't start var dialog = serverConnectWizard.createObject(app)
// without completed serverConnectWizard we can't start
dialog.rejected.connect(function() {
app.visible = false
AppController.wantClose = true
Qt.callLater(Qt.quit)
})
dialog.accepted.connect(function() {
Daemon.startNetwork()
var newww = app.newWalletWizard.createObject(app)
newww.walletCreated.connect(function() {
Daemon.availableWallets.reload()
// and load the new wallet
Daemon.loadWallet(newww.path, newww.wizard_data['password'])
})
newww.open()
})
dialog.open()
} else {
Daemon.startNetwork()
if (Daemon.availableWallets.rowCount() > 0) {
Daemon.loadWallet()
} else {
var newww = app.newWalletWizard.createObject(app)
newww.walletCreated.connect(function() {
Daemon.availableWallets.reload()
// and load the new wallet
Daemon.loadWallet(newww.path, newww.wizard_data['password'])
})
newww.open()
}
}
}
if (!Config.termsOfUseAccepted) {
var dialog = termsOfUseWizard.createObject(app)
dialog.rejected.connect(function() { dialog.rejected.connect(function() {
app.visible = false app.visible = false
AppController.wantClose = true AppController.wantClose = true
Qt.callLater(Qt.quit) Qt.callLater(Qt.quit)
}) })
dialog.accepted.connect(function() { dialog.accepted.connect(function() {
Daemon.startNetwork() Config.termsOfUseAccepted = true
var newww = app.newWalletWizard.createObject(app) continueWithServerConnection()
newww.walletCreated.connect(function() {
Daemon.availableWallets.reload()
// and load the new wallet
Daemon.loadWallet(newww.path, newww.wizard_data['password'])
})
newww.open()
}) })
dialog.open() dialog.open()
} else { } else {
Daemon.startNetwork() continueWithServerConnection()
if (Daemon.availableWallets.rowCount() > 0) {
Daemon.loadWallet()
} else {
var newww = app.newWalletWizard.createObject(app)
newww.walletCreated.connect(function() {
Daemon.availableWallets.reload()
// and load the new wallet
Daemon.loadWallet(newww.path, newww.wizard_data['password'])
})
newww.open()
}
} }
} }

View File

@@ -19,7 +19,7 @@ WizardComponent {
ProxyConfig { ProxyConfig {
id: pc id: pc
Layout.fillWidth: true Layout.fillWidth: true
proxy_enabled: true proxy_enabled: false
} }
} }
} }

View File

@@ -0,0 +1,48 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import "../controls"
WizardComponent {
valid: true
last: true
Flickable {
anchors.fill: parent
contentHeight: mainLayout.height
clip: true
interactive: height < contentHeight
ColumnLayout {
id: mainLayout
width: parent.width
spacing: constants.paddingLarge
Image {
Layout.fillWidth: true
fillMode: Image.PreserveAspectFit
source: Qt.resolvedUrl('../../../icons/electrum_presplash.png')
// reduce spacing a bit
Layout.topMargin: -100
Layout.bottomMargin: -200
}
Label {
Layout.fillWidth: true
text: qsTr("Terms of Use")
font.pixelSize: constants.fontSizeLarge
font.bold: true
horizontalAlignment: Text.AlignHCenter
}
Label {
Layout.fillWidth: true
text: wiz.termsOfUseText
wrapMode: Text.WordWrap
font.pixelSize: constants.fontSizeMedium
padding: constants.paddingSmall
}
}
}
}

View File

@@ -6,41 +6,29 @@ import "../controls"
WizardComponent { WizardComponent {
valid: true valid: true
wizard_title: qsTr('Electrum Bitcoin Wallet') wizard_title: qsTr('Network Configuration')
function apply() { function apply() {
wizard_data['use_defaults'] = !config_advanced.checked wizard_data['use_defaults'] = !config_proxy.checked && !config_server.checked
wizard_data['want_proxy'] = config_advanced.checked && config_proxy.checked wizard_data['want_proxy'] = config_proxy.checked
wizard_data['autoconnect'] = !config_server.checked || !config_advanced.checked wizard_data['autoconnect'] = !config_server.checked
} }
ColumnLayout { ColumnLayout {
width: parent.width width: parent.width
Image { Label {
Layout.fillWidth: true
fillMode: Image.PreserveAspectFit
source: Qt.resolvedUrl('../../../icons/electrum_presplash.png')
// reduce spacing a bit
Layout.topMargin: -50
Layout.bottomMargin: -120
}
CheckBox {
id: config_advanced
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: qsTr('Advanced network settings') Layout.preferredWidth: parent.width
checked: false text: qsTr("Optional settings to customize your network connection") + ":"
onCheckedChanged: checkIsLast() wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHLeft
font.pixelSize: constants.fontSizeLarge
} }
ColumnLayout { ColumnLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 2*constants.paddingXLarge; Layout.bottomMargin: 2*constants.paddingXLarge
opacity: config_advanced.checked ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: 300 }
}
CheckBox { CheckBox {
id: config_proxy id: config_proxy
@@ -55,5 +43,14 @@ WizardComponent {
onCheckedChanged: checkIsLast() onCheckedChanged: checkIsLast()
} }
} }
Label {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width
text: qsTr("If you are unsure what this is, leave them unchecked and Electrum will automatically select servers.")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHLeft
font.pixelSize: constants.fontSizeMedium
}
} }
} }

View File

@@ -41,7 +41,7 @@ from .qechannelopener import QEChannelOpener
from .qelnpaymentdetails import QELnPaymentDetails from .qelnpaymentdetails import QELnPaymentDetails
from .qechanneldetails import QEChannelDetails from .qechanneldetails import QEChannelDetails
from .qeswaphelper import QESwapHelper from .qeswaphelper import QESwapHelper
from .qewizard import QENewWalletWizard, QEServerConnectWizard from .qewizard import QENewWalletWizard, QEServerConnectWizard, QETermsOfUseWizard
from .qemodelfilter import QEFilterProxyModel from .qemodelfilter import QEFilterProxyModel
from .qebip39recovery import QEBip39RecoveryListModel from .qebip39recovery import QEBip39RecoveryListModel
@@ -428,6 +428,7 @@ class ElectrumQmlApplication(QGuiApplication):
# TODO QT6 order of declaration is important now? # TODO QT6 order of declaration is important now?
qmlRegisterType(QEAmount, 'org.electrum', 1, 0, 'Amount') qmlRegisterType(QEAmount, 'org.electrum', 1, 0, 'Amount')
qmlRegisterType(QENewWalletWizard, 'org.electrum', 1, 0, 'QNewWalletWizard') qmlRegisterType(QENewWalletWizard, 'org.electrum', 1, 0, 'QNewWalletWizard')
qmlRegisterType(QETermsOfUseWizard, 'org.electrum', 1, 0, 'QTermsOfUseWizard')
qmlRegisterType(QEServerConnectWizard, 'org.electrum', 1, 0, 'QServerConnectWizard') qmlRegisterType(QEServerConnectWizard, 'org.electrum', 1, 0, 'QServerConnectWizard')
qmlRegisterType(QEFilterProxyModel, 'org.electrum', 1, 0, 'FilterProxyModel') qmlRegisterType(QEFilterProxyModel, 'org.electrum', 1, 0, 'FilterProxyModel')
qmlRegisterType(QSortFilterProxyModel, 'org.electrum', 1, 0, 'QSortFilterProxyModel') qmlRegisterType(QSortFilterProxyModel, 'org.electrum', 1, 0, 'QSortFilterProxyModel')

View File

@@ -66,6 +66,19 @@ class QEConfig(AuthMixin, QObject):
langs_sorted.insert(0, {'value': '', 'text': default}) langs_sorted.insert(0, {'value': '', 'text': default})
return langs_sorted return langs_sorted
termsOfUseChanged = pyqtSignal()
@pyqtProperty(bool, notify=termsOfUseChanged)
def termsOfUseAccepted(self) -> bool:
return self.config.TERMS_OF_USE_ACCEPTED >= messages.TERMS_OF_USE_LATEST_VERSION
@termsOfUseAccepted.setter
def termsOfUseAccepted(self, accepted: bool) -> None:
if accepted:
self.config.TERMS_OF_USE_ACCEPTED = messages.TERMS_OF_USE_LATEST_VERSION
else:
self.config.TERMS_OF_USE_ACCEPTED = 0
self.termsOfUseChanged.emit()
autoConnectChanged = pyqtSignal() autoConnectChanged = pyqtSignal()
@pyqtProperty(bool, notify=autoConnectChanged) @pyqtProperty(bool, notify=autoConnectChanged)
def autoConnect(self): def autoConnect(self):

View File

@@ -18,7 +18,7 @@ from electrum.storage import StorageReadWriteError
from .auth import AuthMixin, auth_protect from .auth import AuthMixin, auth_protect
from .qefx import QEFX from .qefx import QEFX
from .qewallet import QEWallet from .qewallet import QEWallet
from .qewizard import QENewWalletWizard, QEServerConnectWizard from .qewizard import QENewWalletWizard, QEServerConnectWizard, QETermsOfUseWizard
if TYPE_CHECKING: if TYPE_CHECKING:
from electrum.daemon import Daemon from electrum.daemon import Daemon
@@ -128,6 +128,7 @@ class QEDaemon(AuthMixin, QObject):
_available_wallets = None _available_wallets = None
_current_wallet = None _current_wallet = None
_new_wallet_wizard = None _new_wallet_wizard = None
_terms_of_use_wizard = None
_server_connect_wizard = None _server_connect_wizard = None
_path = None _path = None
_name = None _name = None
@@ -140,6 +141,7 @@ class QEDaemon(AuthMixin, QObject):
availableWalletsChanged = pyqtSignal() availableWalletsChanged = pyqtSignal()
fxChanged = pyqtSignal() fxChanged = pyqtSignal()
newWalletWizardChanged = pyqtSignal() newWalletWizardChanged = pyqtSignal()
termsOfUseWizardChanged = pyqtSignal()
serverConnectWizardChanged = pyqtSignal() serverConnectWizardChanged = pyqtSignal()
loadingChanged = pyqtSignal() loadingChanged = pyqtSignal()
requestNewPassword = pyqtSignal() requestNewPassword = pyqtSignal()
@@ -365,6 +367,12 @@ class QEDaemon(AuthMixin, QObject):
return self._server_connect_wizard return self._server_connect_wizard
@pyqtProperty(QETermsOfUseWizard, notify=termsOfUseWizardChanged)
def termsOfUseWizard(self):
if not self._terms_of_use_wizard:
self._terms_of_use_wizard = QETermsOfUseWizard(self)
return self._terms_of_use_wizard
@pyqtSlot() @pyqtSlot()
def startNetwork(self): def startNetwork(self):
self.daemon.start_network() self.daemon.start_network()

View File

@@ -5,9 +5,10 @@ from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum import mnemonic from electrum import mnemonic
from electrum.wizard import NewWalletWizard, ServerConnectWizard from electrum.wizard import NewWalletWizard, ServerConnectWizard, TermsOfUseWizard
from electrum.storage import WalletStorage, StorageReadWriteError from electrum.storage import WalletStorage, StorageReadWriteError
from electrum.util import WalletFileException from electrum.util import WalletFileException
from electrum.gui import messages
if TYPE_CHECKING: if TYPE_CHECKING:
from electrum.gui.qml.qedaemon import QEDaemon from electrum.gui.qml.qedaemon import QEDaemon
@@ -183,3 +184,19 @@ class QEServerConnectWizard(ServerConnectWizard, QEAbstractWizard):
'proxy_config': {'gui': 'WCProxyConfig'}, 'proxy_config': {'gui': 'WCProxyConfig'},
'server_config': {'gui': 'WCServerConfig'}, 'server_config': {'gui': 'WCServerConfig'},
}) })
class QETermsOfUseWizard(TermsOfUseWizard, QEAbstractWizard):
def __init__(self, daemon: 'QEDaemon', parent=None):
TermsOfUseWizard.__init__(self, daemon.daemon.config)
QEAbstractWizard.__init__(self, parent)
# attach gui classes
self.navmap_merge({
'terms_of_use': {'gui': 'WCTermsOfUseRequest'},
})
termsOfUseChanged = pyqtSignal()
@pyqtProperty(str, notify=termsOfUseChanged)
def termsOfUseText(self):
return messages.MSG_TERMS_OF_USE