forked from Support/sp-hydra-veil-gui
update: updated billing page, pagedataworker, forced_sync
This commit is contained in:
parent
7910586e1a
commit
91e657a06d
11 changed files with 168 additions and 123 deletions
Binary file not shown.
|
|
@ -10,7 +10,7 @@ import traceback
|
|||
|
||||
from PyQt6.QtWidgets import (
|
||||
QApplication, QMainWindow, QStackedWidget, QLabel, QPushButton,
|
||||
QDialog, QVBoxLayout, QHBoxLayout
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QMessageBox
|
||||
)
|
||||
from PyQt6.QtGui import QPixmap, QFont, QFontDatabase
|
||||
from PyQt6 import QtGui
|
||||
|
|
@ -61,6 +61,7 @@ from gui.v2.actions.ticket_failure import (
|
|||
clear_ticket_verification_failure,
|
||||
)
|
||||
from gui.v2.actions.should_be_synchronized import should_be_synchronized
|
||||
from gui.v2.ui.popups.message_box import style_message_box, mark_confirm_button
|
||||
|
||||
|
||||
class CustomWindow(QMainWindow):
|
||||
|
|
@ -192,6 +193,23 @@ class CustomWindow(QMainWindow):
|
|||
else:
|
||||
self.navigator.navigate("menu")
|
||||
self.navigator.start_preload()
|
||||
if self.force_sync:
|
||||
QTimer.singleShot(0, self._prompt_force_sync)
|
||||
|
||||
def _prompt_force_sync(self):
|
||||
connection = ConfigurationController.get_connection()
|
||||
box = QMessageBox(self)
|
||||
box.setWindowTitle("Data Update Needed")
|
||||
box.setText(
|
||||
"Please download the new data to avoid errors. You have profiles that need the data to function.\n\n"
|
||||
f"Connection type: {connection}")
|
||||
style_message_box(box)
|
||||
sync_button = box.addButton("Sync", QMessageBox.ButtonRole.AcceptRole)
|
||||
mark_confirm_button(sync_button)
|
||||
box.addButton("Cancel", QMessageBox.ButtonRole.RejectRole)
|
||||
box.exec()
|
||||
if box.clickedButton() == sync_button:
|
||||
self.sync()
|
||||
|
||||
def perform_update_check(self):
|
||||
from core.controllers.ClientController import ClientController
|
||||
|
|
|
|||
|
|
@ -157,10 +157,16 @@ class Navigator(QObject):
|
|||
else:
|
||||
self._maybe_emit_preload_summary()
|
||||
|
||||
def _prepare_page_data(self, name):
|
||||
module_path, class_name = PAGE_REGISTRY[name]
|
||||
module = importlib.import_module(module_path)
|
||||
cls = getattr(module, class_name)
|
||||
return cls.prepare_data(self.custom_window)
|
||||
|
||||
def _dispatch_async_preload(self, name):
|
||||
module_path, class_name = PAGE_REGISTRY[name]
|
||||
print(f"[preload] {name:30s} ASYNC {module_path}.{class_name}", flush=True)
|
||||
worker = PageDataWorker(name, module_path, class_name, self.custom_window)
|
||||
worker = PageDataWorker(name, self._prepare_page_data, name)
|
||||
worker.data_ready.connect(self._on_preload_data_ready)
|
||||
worker.failed.connect(self._on_preload_failed)
|
||||
worker.finished.connect(lambda n=name: self._cleanup_preload_worker(n))
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from gui.v2.ui.pages.browser_page import BrowserPage
|
|||
from gui.v2.ui.pages.location_page import LocationPage
|
||||
from gui.v2.ui.pages.screen_page import ScreenPage
|
||||
from gui.v2.ui.popups.confirmation_popup import ConfirmationPopup
|
||||
from gui.v2.workers.page_data_worker import PageDataWorker
|
||||
|
||||
|
||||
class EditorPage(Page):
|
||||
|
|
@ -80,6 +81,13 @@ class EditorPage(Page):
|
|||
self.brow_disp.hide()
|
||||
self.brow_disp.lower()
|
||||
|
||||
self._prefetched_profiles = None
|
||||
self._editor_workers = set()
|
||||
|
||||
@staticmethod
|
||||
def prepare_data(custom_window):
|
||||
return ProfileController.get_all()
|
||||
|
||||
def _selected_profiles_str(self):
|
||||
menu_page = self.find_menu_page()
|
||||
if menu_page is not None and menu_page.selected_profiles:
|
||||
|
|
@ -117,8 +125,28 @@ class EditorPage(Page):
|
|||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
self.res_hint_shown = False
|
||||
worker = PageDataWorker("editor", EditorPage.prepare_data, self.custom_window)
|
||||
worker.data_ready.connect(
|
||||
lambda name, profiles: self._on_editor_data_ready(profiles))
|
||||
worker.failed.connect(
|
||||
lambda name, error: self._on_editor_data_failed(error))
|
||||
worker.finished.connect(
|
||||
lambda w=worker: self._cleanup_editor_worker(w))
|
||||
self._editor_workers.add(worker)
|
||||
worker.start()
|
||||
|
||||
def _on_editor_data_ready(self, profiles):
|
||||
self._prefetched_profiles = profiles
|
||||
self.extraccion()
|
||||
|
||||
def _on_editor_data_failed(self, error):
|
||||
self.update_status.update_status(f"Editor data load failed: {error}")
|
||||
self.extraccion()
|
||||
|
||||
def _cleanup_editor_worker(self, worker):
|
||||
self._editor_workers.discard(worker)
|
||||
worker.deleteLater()
|
||||
|
||||
def extraccion(self):
|
||||
self.data_profile = {}
|
||||
for label in self.labels:
|
||||
|
|
@ -131,6 +159,10 @@ class EditorPage(Page):
|
|||
selected_profiles_str = self._selected_profiles_str()
|
||||
menu_page = self.find_menu_page()
|
||||
if menu_page:
|
||||
if self._prefetched_profiles is not None:
|
||||
new_profiles = self._prefetched_profiles
|
||||
self._prefetched_profiles = None
|
||||
else:
|
||||
new_profiles = ProfileController.get_all()
|
||||
self.profiles_data = menu_page.match_core_profiles(
|
||||
profiles_dict=new_profiles)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from gui.v2.ui.pages.Page import Page
|
|||
from gui.v2.ui.pages.browser_page import BrowserPage
|
||||
from gui.v2.ui.pages.location_page import LocationPage
|
||||
from gui.v2.ui.pages.location_verification_page import LocationVerificationPage
|
||||
from gui.v2.workers.page_data_worker import PageDataWorker
|
||||
from gui.v2.workers.worker_thread import WorkerThread
|
||||
|
||||
|
||||
|
|
@ -73,9 +74,15 @@ class FastRegistrationPage(Page):
|
|||
'resolution': '1024x760'
|
||||
}
|
||||
self.res_index = 1
|
||||
self._prefetched_profiles = None
|
||||
self._fast_reg_workers = set()
|
||||
|
||||
self.initialize_default_selections()
|
||||
|
||||
@staticmethod
|
||||
def prepare_data(custom_window):
|
||||
return ProfileController.get_all()
|
||||
|
||||
def initialize_default_selections(self):
|
||||
if not self.selected_values['location']:
|
||||
locations = self.connection_manager.get_location_list()
|
||||
|
|
@ -107,6 +114,24 @@ class FastRegistrationPage(Page):
|
|||
super().showEvent(event)
|
||||
self.initialize_default_selections()
|
||||
self.create_interface_elements()
|
||||
self._start_profiles_prefetch()
|
||||
|
||||
def _start_profiles_prefetch(self):
|
||||
worker = PageDataWorker(
|
||||
"fast_registration", FastRegistrationPage.prepare_data, self.custom_window)
|
||||
worker.data_ready.connect(
|
||||
lambda name, profiles: self._on_profiles_prefetched(profiles))
|
||||
worker.finished.connect(
|
||||
lambda w=worker: self._cleanup_fast_reg_worker(w))
|
||||
self._fast_reg_workers.add(worker)
|
||||
worker.start()
|
||||
|
||||
def _on_profiles_prefetched(self, profiles):
|
||||
self._prefetched_profiles = profiles
|
||||
|
||||
def _cleanup_fast_reg_worker(self, worker):
|
||||
self._fast_reg_workers.discard(worker)
|
||||
worker.deleteLater()
|
||||
|
||||
def create_interface_elements(self):
|
||||
for label in self.labels:
|
||||
|
|
@ -728,7 +753,7 @@ class FastRegistrationPage(Page):
|
|||
self.update_status.update_status('Invalid location selected')
|
||||
return
|
||||
|
||||
profiles = ProfileController.get_all()
|
||||
profiles = self._prefetched_profiles if self._prefetched_profiles is not None else ProfileController.get_all()
|
||||
profile_id = self.get_next_available_profile_id(profiles)
|
||||
profile_data_for_resume = {
|
||||
'id': profile_id,
|
||||
|
|
@ -762,7 +787,7 @@ class FastRegistrationPage(Page):
|
|||
|
||||
connection_type = 'tor' if profile_data['connection'] == 'tor' else 'system'
|
||||
|
||||
profiles = ProfileController.get_all()
|
||||
profiles = self._prefetched_profiles if self._prefetched_profiles is not None else ProfileController.get_all()
|
||||
profile_id = self.get_next_available_profile_id(profiles)
|
||||
profile_data_for_resume = {
|
||||
'id': profile_id,
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@ import os
|
|||
import re
|
||||
|
||||
from PyQt6.QtWidgets import (
|
||||
QButtonGroup, QFrame, QLabel, QPushButton, QTextEdit,
|
||||
QButtonGroup, QFrame, QLabel, QMessageBox, QPushButton, QTextEdit,
|
||||
)
|
||||
from PyQt6.QtGui import QIcon, QPixmap
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6 import QtCore
|
||||
|
||||
from core.services.payment_phase.do_we_have_billing_id import do_we_have_billing_id
|
||||
|
||||
from gui.v2.ui.pages.Page import Page
|
||||
from gui.v2.ui.popups.message_box import style_message_box, mark_confirm_button
|
||||
|
||||
|
||||
HOW_MANY_PROFILES_DEFAULT = 6
|
||||
|
|
@ -150,11 +153,44 @@ class IdPage(Page):
|
|||
self.custom_window.navigator.navigate("duration_selection")
|
||||
|
||||
def go_multiple_profiles(self):
|
||||
billing_id = do_we_have_billing_id()
|
||||
if billing_id:
|
||||
self._prompt_existing_tickets(billing_id)
|
||||
else:
|
||||
self._continue_multiple_flow()
|
||||
|
||||
def _continue_multiple_flow(self):
|
||||
self.custom_window.navigator.navigate("plan_picker")
|
||||
plan_page = self.custom_window.navigator.get_cached("plan_picker")
|
||||
if plan_page is not None:
|
||||
plan_page.start_sync()
|
||||
|
||||
def _prompt_existing_tickets(self, billing_id):
|
||||
box = QMessageBox(self)
|
||||
box.setWindowTitle("Existing ticket purchase found")
|
||||
box.setText(
|
||||
"You already have a pending ticket purchase. Continue to check if it's paid, "
|
||||
"or wipe it and start over?")
|
||||
style_message_box(box)
|
||||
check_button = box.addButton(
|
||||
"Check payment", QMessageBox.ButtonRole.AcceptRole)
|
||||
mark_confirm_button(check_button)
|
||||
wipe_button = box.addButton(
|
||||
"Wipe and start over", QMessageBox.ButtonRole.DestructiveRole)
|
||||
box.exec()
|
||||
clicked = box.clickedButton()
|
||||
if clicked == check_button:
|
||||
self._resume_existing_ticket(billing_id)
|
||||
elif clicked == wipe_button:
|
||||
self._continue_multiple_flow()
|
||||
|
||||
def _resume_existing_ticket(self, billing_id):
|
||||
self.update_status.update_status("Checking existing ticket payment...")
|
||||
self.custom_window.navigator.navigate("payment_details")
|
||||
payment_page = self.custom_window.navigator.get_cached("payment_details")
|
||||
if payment_page is not None:
|
||||
payment_page.resume_ticket_billing(billing_id)
|
||||
|
||||
def toggle_button_state(self):
|
||||
text = self.text_edit.toPlainText()
|
||||
if text.strip():
|
||||
|
|
|
|||
|
|
@ -351,6 +351,16 @@ class PaymentDetailsPage(Page):
|
|||
self.ticket_poll_timer.start(3000)
|
||||
self.update_status.update_status('Awaiting ticket payment...')
|
||||
|
||||
def resume_ticket_billing(self, temp_billing_code):
|
||||
self.ticketing = True
|
||||
self.temp_billing_code = temp_billing_code
|
||||
self.selected_currency = None
|
||||
self.text_fields[0].setText(str(temp_billing_code or ''))
|
||||
if self.ticket_poll_timer.isActive():
|
||||
self.ticket_poll_timer.stop()
|
||||
self.ticket_poll_timer.start(3000)
|
||||
self.update_status.update_status('Checking existing ticket payment...')
|
||||
|
||||
def _populate_ticket_fields(self, invoice):
|
||||
self.text_fields[0].setText(str(getattr(invoice, 'temp_billing_code', '') or ''))
|
||||
self.text_fields[1].setText(self.selected_duration)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ from core.errors.logger import logger as core_logger
|
|||
from gui.v2.actions import settings_data
|
||||
from gui.v2.actions.key_interpretation import interpret_key_results
|
||||
from gui.v2.actions.profile_order import normalize_profile_order
|
||||
from gui.v2.infrastructure.page_registry import PAGE_REGISTRY
|
||||
from gui.v2.infrastructure.setup_observers import ticket_observer
|
||||
from gui.v2.ui.pages.Page import Page
|
||||
from gui.v2.ui.popups.confirmation_popup import ConfirmationPopup
|
||||
|
|
@ -103,7 +102,6 @@ class Settings(Page):
|
|||
("Create/Edit", self.show_registrations_page),
|
||||
("Verification", self.show_verification_page),
|
||||
("Legacy-Version", self.show_systemwide_page),
|
||||
("Bwrap Permission", self.show_bwrap_page),
|
||||
("Delete Profile", self.show_delete_page),
|
||||
("Error Logs", self.show_logs_page),
|
||||
("Debug Help", self.show_debug_page)
|
||||
|
|
@ -1176,9 +1174,8 @@ class Settings(Page):
|
|||
super().showEvent(event)
|
||||
self._settings_refresh_seq += 1
|
||||
seq = self._settings_refresh_seq
|
||||
module_path, class_name = PAGE_REGISTRY["settings"]
|
||||
worker = PageDataWorker(
|
||||
"settings", module_path, class_name, self.custom_window)
|
||||
"settings", settings_data.prepare, self.custom_window.gui_config_file)
|
||||
worker.data_ready.connect(
|
||||
lambda name, payload, s=seq: self._on_settings_data_ready(payload, s))
|
||||
worker.failed.connect(
|
||||
|
|
@ -1226,10 +1223,6 @@ class Settings(Page):
|
|||
self.systemwide_page = self.create_systemwide_page()
|
||||
self.content_layout.addWidget(self.systemwide_page)
|
||||
|
||||
self.content_layout.removeWidget(self.bwrap_page)
|
||||
self.bwrap_page = self.create_bwrap_page()
|
||||
self.content_layout.addWidget(self.bwrap_page)
|
||||
|
||||
self.content_layout.removeWidget(self.delete_page)
|
||||
self.delete_page = self.create_delete_page()
|
||||
self.content_layout.addWidget(self.delete_page)
|
||||
|
|
@ -1443,7 +1436,6 @@ class Settings(Page):
|
|||
self.registrations_page = self.create_registrations_page()
|
||||
self.verification_page = self.create_verification_page()
|
||||
self.systemwide_page = self.create_systemwide_page()
|
||||
self.bwrap_page = self.create_bwrap_page()
|
||||
self.logs_page = self.create_logs_page()
|
||||
self.delete_page = self.create_delete_page()
|
||||
self.debug_page = self.create_debug_page()
|
||||
|
|
@ -1454,7 +1446,6 @@ class Settings(Page):
|
|||
self.content_layout.addWidget(self.registrations_page)
|
||||
self.content_layout.addWidget(self.verification_page)
|
||||
self.content_layout.addWidget(self.systemwide_page)
|
||||
self.content_layout.addWidget(self.bwrap_page)
|
||||
self.content_layout.addWidget(self.logs_page)
|
||||
self.content_layout.addWidget(self.delete_page)
|
||||
self.content_layout.addWidget(self.debug_page)
|
||||
|
|
@ -1508,11 +1499,6 @@ class Settings(Page):
|
|||
self.content_layout.setCurrentWidget(self.systemwide_page)
|
||||
self._select_menu_button("Legacy-Version")
|
||||
|
||||
def show_bwrap_page(self):
|
||||
core_logger.info("User navigated to Settings -> Bwrap Permission")
|
||||
self.content_layout.setCurrentWidget(self.bwrap_page)
|
||||
self._select_menu_button("Bwrap Permission")
|
||||
|
||||
def show_logs_page(self):
|
||||
core_logger.info("User navigated to Settings -> Error Logs")
|
||||
self.content_layout.setCurrentWidget(self.logs_page)
|
||||
|
|
@ -1995,59 +1981,6 @@ class Settings(Page):
|
|||
self._prepared_value("systemwide_enabled", settings_data.read_systemwide_enabled))
|
||||
return page
|
||||
|
||||
def create_bwrap_page(self):
|
||||
page = QWidget()
|
||||
layout = QVBoxLayout(page)
|
||||
layout.setSpacing(20)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
|
||||
title = QLabel("BWRAP PERMISSION")
|
||||
title.setStyleSheet(
|
||||
f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
layout.addWidget(title)
|
||||
|
||||
description = QLabel(
|
||||
"Control whether HydraVeil configures a capability policy so bwrap can be used without requiring additional permissions.")
|
||||
description.setWordWrap(True)
|
||||
description.setStyleSheet(
|
||||
f"color: white; font-size: 14px; {self.font_style}")
|
||||
layout.addWidget(description)
|
||||
|
||||
status_layout = QHBoxLayout()
|
||||
status_label = QLabel("Current status:")
|
||||
status_label.setStyleSheet(
|
||||
f"color: white; font-size: 14px; {self.font_style}")
|
||||
self.bwrap_status_value = QLabel("")
|
||||
self.bwrap_status_value.setStyleSheet(
|
||||
f"color: #e67e22; font-size: 14px; {self.font_style}")
|
||||
status_layout.addWidget(status_label)
|
||||
status_layout.addWidget(self.bwrap_status_value)
|
||||
status_layout.addStretch()
|
||||
layout.addLayout(status_layout)
|
||||
|
||||
toggle_layout = QHBoxLayout()
|
||||
self.bwrap_toggle = QCheckBox("Enable capability policy")
|
||||
self.bwrap_toggle.setStyleSheet(self.get_checkbox_style())
|
||||
toggle_layout.addWidget(self.bwrap_toggle)
|
||||
toggle_layout.addStretch()
|
||||
layout.addLayout(toggle_layout)
|
||||
|
||||
save_button = QPushButton()
|
||||
save_button.setFixedSize(75, 46)
|
||||
save_button.setIcon(QIcon(os.path.join(self.btn_path, "save.png")))
|
||||
save_button.setIconSize(QSize(75, 46))
|
||||
save_button.clicked.connect(self.save_bwrap_settings)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.addWidget(save_button)
|
||||
button_layout.addStretch()
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
layout.addStretch()
|
||||
self.load_bwrap_settings(
|
||||
self._prepared_value("bwrap_enabled", settings_data.read_bwrap_enabled))
|
||||
return page
|
||||
|
||||
def load_systemwide_settings(self, enabled=None):
|
||||
if enabled is None:
|
||||
enabled = settings_data.read_systemwide_enabled()
|
||||
|
|
@ -2087,45 +2020,6 @@ class Settings(Page):
|
|||
self.systemwide_status_value.setStyleSheet(
|
||||
f"color: red; font-size: 14px; {self.font_style}")
|
||||
|
||||
def load_bwrap_settings(self, enabled=None):
|
||||
if enabled is None:
|
||||
enabled = settings_data.read_bwrap_enabled()
|
||||
self.bwrap_toggle.setChecked(enabled)
|
||||
if enabled:
|
||||
self.bwrap_status_value.setText("Enabled")
|
||||
self.bwrap_status_value.setStyleSheet(
|
||||
f"color: #2ecc71; font-size: 14px; {self.font_style}")
|
||||
else:
|
||||
self.bwrap_status_value.setText("Disabled")
|
||||
self.bwrap_status_value.setStyleSheet(
|
||||
f"color: #e67e22; font-size: 14px; {self.font_style}")
|
||||
|
||||
def save_bwrap_settings(self):
|
||||
enable = self.bwrap_toggle.isChecked()
|
||||
try:
|
||||
capability_policy = PolicyController.get('capability')
|
||||
if capability_policy is not None:
|
||||
if enable:
|
||||
PolicyController.instate(capability_policy)
|
||||
else:
|
||||
if PolicyController.is_instated(capability_policy):
|
||||
PolicyController.revoke(capability_policy)
|
||||
self.load_bwrap_settings()
|
||||
self.update_status.update_status(
|
||||
"Capability policy settings updated")
|
||||
except CommandNotFoundError as e:
|
||||
self.bwrap_status_value.setText(str(e))
|
||||
self.bwrap_status_value.setStyleSheet(
|
||||
f"color: red; font-size: 14px; {self.font_style}")
|
||||
except (PolicyAssignmentError, PolicyInstatementError, PolicyRevocationError) as e:
|
||||
self.bwrap_status_value.setText(str(e))
|
||||
self.bwrap_status_value.setStyleSheet(
|
||||
f"color: red; font-size: 14px; {self.font_style}")
|
||||
except Exception:
|
||||
self.bwrap_status_value.setText("Failed to update policy")
|
||||
self.bwrap_status_value.setStyleSheet(
|
||||
f"color: red; font-size: 14px; {self.font_style}")
|
||||
|
||||
def load_registrations_settings(self) -> None:
|
||||
try:
|
||||
config = self._prepared_value(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from core.controllers.tickets.TicketPayController import check_if_paid
|
|||
|
||||
from gui.v2.infrastructure.setup_observers import connection_observer, ticket_observer
|
||||
from gui.v2.ui.pages.Page import Page
|
||||
from gui.v2.ui.popups.message_box import style_message_box, mark_confirm_button
|
||||
from gui.v2.workers.ticketing_worker_thread import TicketingWorkerThread
|
||||
|
||||
|
||||
|
|
@ -77,7 +78,13 @@ class TicketCryptoPickerPage(Page):
|
|||
clipboard = QApplication.clipboard()
|
||||
clipboard.setText(temp_billing_code)
|
||||
not_paid_msg = f"The billing code is not yet showing paid for {temp_billing_code}. Right now, your clipboard has the billing code, to paste it in any text editor. If you did pay, either wait longer for blockchain confirmation, or contact customer support with the code in your clipboard now."
|
||||
QMessageBox.information(None, "Not Paid", not_paid_msg)
|
||||
info = QMessageBox(self)
|
||||
info.setWindowTitle("Not Paid")
|
||||
info.setText(not_paid_msg)
|
||||
info.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||
style_message_box(info)
|
||||
mark_confirm_button(info.button(QMessageBox.StandardButton.Ok))
|
||||
info.exec()
|
||||
|
||||
def start_initiate_payment(self, currency):
|
||||
self.update_status.update_status("Initiating payment...")
|
||||
|
|
@ -121,6 +128,8 @@ class TicketCryptoPickerPage(Page):
|
|||
msg.setWindowTitle("Existing tickets found")
|
||||
msg.setText("You already have ticket data. Wipe it and start over?")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||
style_message_box(msg)
|
||||
mark_confirm_button(msg.button(QMessageBox.StandardButton.Yes))
|
||||
result = msg.exec()
|
||||
if result == QMessageBox.StandardButton.Yes:
|
||||
self.bypass_existing = True
|
||||
|
|
@ -135,6 +144,8 @@ class TicketCryptoPickerPage(Page):
|
|||
msg.setWindowTitle("Existing billing code found")
|
||||
msg.setText("You already have a ticket billing code. Do you want to use it? Only hit YES if you ALREADY paid.")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||
style_message_box(msg)
|
||||
mark_confirm_button(msg.button(QMessageBox.StandardButton.Yes))
|
||||
result = msg.exec()
|
||||
if result == QMessageBox.StandardButton.Yes:
|
||||
self.update_status.update_status("Reusing same code")
|
||||
|
|
|
|||
18
gui/v2/ui/popups/message_box.py
Executable file
18
gui/v2/ui/popups/message_box.py
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
MESSAGE_BOX_QSS = (
|
||||
"QMessageBox { background-color: white; }"
|
||||
"QMessageBox QLabel { color: black; }"
|
||||
"QMessageBox QPushButton { color: black; padding: 5px 14px; }"
|
||||
)
|
||||
|
||||
CONFIRM_BUTTON_QSS = "color: #2e7d32; font-weight: bold; padding: 5px 14px;"
|
||||
|
||||
|
||||
def style_message_box(box):
|
||||
box.setStyleSheet(MESSAGE_BOX_QSS)
|
||||
|
||||
|
||||
def mark_confirm_button(button):
|
||||
if button is None:
|
||||
return
|
||||
button.setText(f"✓ {button.text()}")
|
||||
button.setStyleSheet(CONFIRM_BUTTON_QSS)
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
import importlib
|
||||
|
||||
from PyQt6.QtCore import QThread, pyqtSignal
|
||||
|
||||
|
||||
|
|
@ -7,18 +5,15 @@ class PageDataWorker(QThread):
|
|||
data_ready = pyqtSignal(str, object)
|
||||
failed = pyqtSignal(str, str)
|
||||
|
||||
def __init__(self, name, module_path, class_name, custom_window):
|
||||
def __init__(self, name, fn, *args):
|
||||
super().__init__()
|
||||
self.name = name
|
||||
self.module_path = module_path
|
||||
self.class_name = class_name
|
||||
self.custom_window = custom_window
|
||||
self.fn = fn
|
||||
self.args = args
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
module = importlib.import_module(self.module_path)
|
||||
cls = getattr(module, self.class_name)
|
||||
payload = cls.prepare_data(self.custom_window)
|
||||
payload = self.fn(*self.args)
|
||||
self.data_ready.emit(self.name, payload)
|
||||
except Exception as error:
|
||||
self.failed.emit(self.name, f"{type(error).__name__}: {error}")
|
||||
|
|
|
|||
Loading…
Reference in a new issue