qt: show terms of use as first window on setup
This commit is contained in:
@@ -78,3 +78,13 @@ MSG_LN_UTXO_RESERVE = (
|
||||
_("You do not have enough on-chain funds to protect your Lightning channels.") + ' ' +
|
||||
_("You should have at least {} on-chain in order to be able to sweep channel outputs.")
|
||||
)
|
||||
|
||||
# not to be translated
|
||||
MSG_TERMS_OF_USE = """
|
||||
1. Electrum is distributed under the MIT licence by Electrum Technologies GmbH. Most notably, this means that the Electrum software is provided as is, and that it comes without warranty.
|
||||
|
||||
2. We are neither a bank nor a financial service provider. In addition, we do not not store user account data, and we are not an intermediary in the interaction between our software and the Bitcoin blockchain. Therefore, we do not have the possibility to freeze funds or to undo a fraudulent transaction.
|
||||
|
||||
3. We do not provide private user support. All issue resolutions are public, and take place on Github or public forums. If someone posing as 'Electrum support' proposes to help you via a private channel, this person is most likely an imposter trying to steal your bitcoins.
|
||||
"""
|
||||
|
||||
|
||||
@@ -500,6 +500,19 @@ class ElectrumGui(BaseElectrumGui, Logger):
|
||||
window.close()
|
||||
self._create_window_for_wallet(wallet)
|
||||
|
||||
def ask_terms_of_use(self):
|
||||
"""Ask the user to accept the terms of use.
|
||||
This is only shown if the user has not accepted them yet.
|
||||
"""
|
||||
if self.config.TERMS_OF_USE_ACCEPTED:
|
||||
return
|
||||
from electrum.gui.qt.wizard.terms_of_use import QETermsOfUseWizard
|
||||
dialog = QETermsOfUseWizard(self.config, self.app)
|
||||
result = dialog.exec()
|
||||
if result == QDialog.DialogCode.Rejected:
|
||||
self.logger.info('terms of use not accepted by user')
|
||||
raise UserCancelled()
|
||||
|
||||
def init_network(self):
|
||||
"""Start the network, including showing a first-start network dialog if config does not exist."""
|
||||
if self.daemon.network:
|
||||
@@ -524,6 +537,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
|
||||
Exception_Hook.maybe_setup(config=self.config)
|
||||
# start network, and maybe show first-start network-setup
|
||||
try:
|
||||
self.ask_terms_of_use()
|
||||
self.init_network()
|
||||
except UserCancelled:
|
||||
return
|
||||
|
||||
@@ -27,7 +27,7 @@ class QEServerConnectWizard(ServerConnectWizard, QEAbstractWizard):
|
||||
|
||||
# attach gui classes
|
||||
self.navmap_merge({
|
||||
'welcome': {'gui': WCWelcome, 'params': {'icon': ''}},
|
||||
'welcome': {'gui': WCWelcome},
|
||||
'proxy_config': {'gui': WCProxyConfig},
|
||||
'server_config': {'gui': WCServerConfig},
|
||||
})
|
||||
@@ -35,31 +35,22 @@ class QEServerConnectWizard(ServerConnectWizard, QEAbstractWizard):
|
||||
|
||||
class WCWelcome(WizardComponent):
|
||||
def __init__(self, parent, wizard):
|
||||
WizardComponent.__init__(self, parent, wizard, title='')
|
||||
WizardComponent.__init__(self, parent, wizard, title='Network Configuration')
|
||||
self.wizard_title = _('Electrum Bitcoin Wallet')
|
||||
self.use_advanced_w = QCheckBox(_('Advanced network settings'))
|
||||
self.use_advanced_w.setChecked(False)
|
||||
self.use_advanced_w.stateChanged.connect(self.on_advanced_changed)
|
||||
|
||||
self.img_label = QLabel()
|
||||
pixmap = QPixmap(icon_path('electrum_darkblue_1.png'))
|
||||
self.img_label.setPixmap(pixmap)
|
||||
self.img_label2 = QLabel()
|
||||
pixmap = QPixmap(icon_path('electrum_text.png'))
|
||||
self.img_label2.setPixmap(pixmap)
|
||||
hbox_img = QHBoxLayout()
|
||||
hbox_img.addStretch(1)
|
||||
hbox_img.addWidget(self.img_label)
|
||||
hbox_img.addWidget(self.img_label2)
|
||||
hbox_img.addStretch(1)
|
||||
self.help_label = QLabel()
|
||||
self.help_label.setText("\n".join([
|
||||
_("Optional settings to customize your network connection."),
|
||||
_("If you are unsure what this is, leave them unchecked and Electrum will automatically "
|
||||
"select servers."),
|
||||
]))
|
||||
self.help_label.setWordWrap(True)
|
||||
|
||||
self.config_proxy_w = QCheckBox(_('Configure Proxy'))
|
||||
self.config_proxy_w.setChecked(False)
|
||||
self.config_proxy_w.setVisible(False)
|
||||
self.config_proxy_w.stateChanged.connect(self.on_updated)
|
||||
self.config_server_w = QCheckBox(_('Select Server'))
|
||||
self.config_server_w.setChecked(False)
|
||||
self.config_server_w.setVisible(False)
|
||||
self.config_server_w.stateChanged.connect(self.on_updated)
|
||||
options_w = QWidget()
|
||||
vbox = QVBoxLayout()
|
||||
@@ -68,21 +59,15 @@ class WCWelcome(WizardComponent):
|
||||
vbox.addStretch(1)
|
||||
options_w.setLayout(vbox)
|
||||
|
||||
self.layout().addLayout(hbox_img)
|
||||
self.layout().addSpacing(50)
|
||||
self.layout().addWidget(self.use_advanced_w, False, Qt.AlignmentFlag.AlignHCenter)
|
||||
self.layout().addWidget(options_w, False, Qt.AlignmentFlag.AlignHCenter)
|
||||
self.layout().addWidget(self.help_label)
|
||||
self.layout().addSpacing(30)
|
||||
self.layout().addWidget(options_w, False, Qt.AlignmentFlag.AlignLeft)
|
||||
self._valid = True
|
||||
|
||||
def on_advanced_changed(self):
|
||||
self.config_proxy_w.setVisible(self.use_advanced_w.isChecked())
|
||||
self.config_server_w.setVisible(self.use_advanced_w.isChecked())
|
||||
self.on_updated()
|
||||
|
||||
def apply(self):
|
||||
self.wizard_data['use_defaults'] = not self.use_advanced_w.isChecked()
|
||||
self.wizard_data['want_proxy'] = self.use_advanced_w.isChecked() and self.config_proxy_w.isChecked()
|
||||
self.wizard_data['autoconnect'] = not self.use_advanced_w.isChecked() or not self.config_server_w.isChecked()
|
||||
self.wizard_data['use_defaults'] = not (self.config_server_w.isChecked() or self.config_proxy_w.isChecked())
|
||||
self.wizard_data['want_proxy'] = self.config_proxy_w.isChecked()
|
||||
self.wizard_data['autoconnect'] = not self.config_server_w.isChecked()
|
||||
|
||||
|
||||
class WCProxyConfig(WizardComponent):
|
||||
|
||||
76
electrum/gui/qt/wizard/terms_of_use.py
Normal file
76
electrum/gui/qt/wizard/terms_of_use.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtCore import QTimer
|
||||
from PyQt6.QtGui import QPixmap
|
||||
from PyQt6.QtWidgets import QLabel, QHBoxLayout, QScrollArea
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.wizard import TermsOfUseWizard
|
||||
from electrum.gui.qt.util import icon_path
|
||||
from electrum.gui import messages
|
||||
from .wizard import QEAbstractWizard, WizardComponent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from electrum.simple_config import SimpleConfig
|
||||
from electrum.gui.qt import QElectrumApplication
|
||||
|
||||
|
||||
class QETermsOfUseWizard(TermsOfUseWizard, QEAbstractWizard):
|
||||
def __init__(self, config: 'SimpleConfig', app: 'QElectrumApplication'):
|
||||
TermsOfUseWizard.__init__(self, config)
|
||||
QEAbstractWizard.__init__(self, config, app)
|
||||
self.window_title = _('Terms of Use')
|
||||
self.finish_label = _('I Accept')
|
||||
self.title.setVisible(False)
|
||||
# self.window().setMinimumHeight(565) # Enough to show the whole text without scrolling
|
||||
self.next_button.setToolTip("You accept the Terms of Use by clicking this button.")
|
||||
|
||||
# attach gui classes
|
||||
self.navmap_merge({
|
||||
'terms_of_use': {'gui': WCTermsOfUseScreen, 'params': {'icon': ''}},
|
||||
})
|
||||
|
||||
class WCTermsOfUseScreen(WizardComponent):
|
||||
def __init__(self, parent, wizard):
|
||||
WizardComponent.__init__(self, parent, wizard, title='')
|
||||
self.wizard_title = _('Electrum Terms of Use')
|
||||
self.img_label = QLabel()
|
||||
pixmap = QPixmap(icon_path('electrum_darkblue_1.png'))
|
||||
self.img_label.setPixmap(pixmap)
|
||||
self.img_label2 = QLabel()
|
||||
pixmap = QPixmap(icon_path('electrum_text.png'))
|
||||
self.img_label2.setPixmap(pixmap)
|
||||
hbox_img = QHBoxLayout()
|
||||
hbox_img.addStretch(1)
|
||||
hbox_img.addWidget(self.img_label)
|
||||
hbox_img.addWidget(self.img_label2)
|
||||
hbox_img.addStretch(1)
|
||||
|
||||
self.layout().addLayout(hbox_img)
|
||||
|
||||
self.tos_label = QLabel()
|
||||
self.tos_label.setText(messages.MSG_TERMS_OF_USE)
|
||||
self.tos_label.setWordWrap(True)
|
||||
self.layout().addWidget(self.tos_label)
|
||||
self._valid = False
|
||||
|
||||
# Find the scroll area and connect to its scrollbar
|
||||
QTimer.singleShot(0, self.check_scroll_position)
|
||||
|
||||
def check_scroll_position(self):
|
||||
# Find the scroll area
|
||||
scroll_area = self.window().findChild(QScrollArea)
|
||||
if scroll_area and scroll_area.verticalScrollBar():
|
||||
scrollbar = scroll_area.verticalScrollBar()
|
||||
def on_scroll_change(value):
|
||||
if value >= scrollbar.maximum() - 5: # Allow 5 pixel margin
|
||||
self._valid = True
|
||||
self.on_updated()
|
||||
scrollbar.valueChanged.connect(on_scroll_change)
|
||||
else:
|
||||
# Fallback if the scroll area is not detected
|
||||
self._valid = True
|
||||
self.on_updated()
|
||||
|
||||
def apply(self):
|
||||
pass
|
||||
@@ -847,6 +847,7 @@ Warning: setting this to too low will result in lots of payment failures."""),
|
||||
QR_READER_FLIP_X = ConfigVar('qrreader_flip_x', default=True, type_=bool)
|
||||
WIZARD_DONT_CREATE_SEGWIT = ConfigVar('nosegwit', default=False, type_=bool)
|
||||
CONFIG_FORGET_CHANGES = ConfigVar('forget_config', default=False, type_=bool)
|
||||
TERMS_OF_USE_ACCEPTED = ConfigVar('terms_of_use_accepted', default=False, type_=bool)
|
||||
|
||||
# connect to remote submarine swap server
|
||||
SWAPSERVER_URL = ConfigVar('swapserver_url', default='', type_=str)
|
||||
|
||||
@@ -20,6 +20,7 @@ if TYPE_CHECKING:
|
||||
from electrum.daemon import Daemon
|
||||
from electrum.plugin import Plugins
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
from electrum.simple_config import SimpleConfig
|
||||
|
||||
|
||||
class WizardViewState(NamedTuple):
|
||||
@@ -766,3 +767,31 @@ class ServerConnectWizard(AbstractWizard):
|
||||
params = self.navmap[start_view].get('params', {})
|
||||
self._current = WizardViewState(start_view, initial_data, params)
|
||||
return self._current
|
||||
|
||||
|
||||
class TermsOfUseWizard(AbstractWizard):
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def __init__(self, config: 'SimpleConfig'):
|
||||
AbstractWizard.__init__(self)
|
||||
self._config = config
|
||||
self.navmap = {
|
||||
'terms_of_use': {
|
||||
'accept': self.accept_terms_of_use,
|
||||
'last': True,
|
||||
},
|
||||
}
|
||||
|
||||
def accept_terms_of_use(self, _):
|
||||
self._config.TERMS_OF_USE_ACCEPTED = True
|
||||
|
||||
def start(self, initial_data: dict = None) -> WizardViewState:
|
||||
if initial_data is None:
|
||||
initial_data = {}
|
||||
self.reset()
|
||||
start_view = 'terms_of_use'
|
||||
params = self.navmap[start_view].get('params', {})
|
||||
self._current = WizardViewState(start_view, initial_data, params)
|
||||
return self._current
|
||||
|
||||
|
||||
Reference in New Issue
Block a user