Updated Protocol Page / Update Flow / Connection Type
This commit is contained in:
parent
f0fadbdd3a
commit
9b6deffa61
3 changed files with 296 additions and 237 deletions
505
gui/__main__.py
505
gui/__main__.py
|
@ -1,5 +1,5 @@
|
|||
from PyQt6.QtWidgets import QComboBox,QButtonGroup, QLineEdit,QMainWindow, QLabel, QWidget, QVBoxLayout, QStackedWidget, QApplication, QPushButton, QTextEdit, QFrame, QHBoxLayout, QVBoxLayout, QScrollArea, QSystemTrayIcon, QMessageBox, QGridLayout, QCheckBox, QStackedLayout, QGroupBox
|
||||
from PyQt6.QtGui import QIcon, QPixmap,QIcon, QPixmap, QTransform, QPainter, QColor, QFont
|
||||
from PyQt6.QtGui import QIcon, QPixmap,QIcon, QPixmap, QTransform, QPainter, QColor, QFont, QPen
|
||||
from PyQt6 import QtGui
|
||||
from PyQt6 import QtCore
|
||||
from PyQt6.QtCore import Qt,QSize,QThread,pyqtSignal, QTimer, QPointF, QRect, QMutex, QMutexLocker, QObject
|
||||
|
@ -12,7 +12,7 @@ import traceback
|
|||
import random
|
||||
import subprocess
|
||||
from typing import Union
|
||||
from core.Errors import CommandNotFoundError, MissingSubscriptionError, InvalidSubscriptionError, ProfileActivationError, UnsupportedApplicationVersionError, FileIntegrityError, ProfileModificationError, ProfileStateConflictError
|
||||
from core.Errors import UnknownConnectionTypeError, CommandNotFoundError, MissingSubscriptionError, InvalidSubscriptionError, ProfileActivationError, UnsupportedApplicationVersionError, FileIntegrityError, ProfileModificationError, ProfileStateConflictError
|
||||
from core.controllers.ApplicationVersionController import ApplicationVersionController
|
||||
from core.controllers.ApplicationController import ApplicationController
|
||||
from core.controllers.ClientController import ClientController
|
||||
|
@ -77,10 +77,8 @@ class WorkerThread(QThread):
|
|||
self.get_subscription()
|
||||
elif self.action == 'DISABLE_PROFILE':
|
||||
self.disable_profile()
|
||||
elif self.action == 'SYNC':
|
||||
elif self.action == 'SYNC' or self.action == 'SYNC_TOR':
|
||||
self.sync()
|
||||
elif self.action == 'SYNC_TOR':
|
||||
self.tor_sync()
|
||||
elif self.action == 'GET_CONNECTION':
|
||||
self.get_connection()
|
||||
elif self.action == 'SET_CONNECTION':
|
||||
|
@ -116,7 +114,7 @@ class WorkerThread(QThread):
|
|||
|
||||
def download_update(self):
|
||||
self.text_output.emit("Starting update process...")
|
||||
ClientController.__update(client_observer=client_observer)
|
||||
ClientController.update(client_observer=client_observer)
|
||||
client_observer.subscribe('update_progressing', lambda event: self.text_output.emit(f"Downloading: {event.meta.get('progress'):.1f}%"))
|
||||
client_observer.subscribe('updated', lambda event: self.text_output.emit("Update process completed"))
|
||||
|
||||
|
@ -230,6 +228,9 @@ class WorkerThread(QThread):
|
|||
|
||||
def sync(self):
|
||||
try:
|
||||
if self.action == 'SYNC_TOR':
|
||||
ConfigurationController.set_connection('tor')
|
||||
else:
|
||||
ConfigurationController.set_connection('system')
|
||||
ClientController.sync(client_observer=client_observer, connection_observer=connection_observer)
|
||||
locations = LocationController.get_all()
|
||||
|
@ -240,18 +241,6 @@ class WorkerThread(QThread):
|
|||
print(e)
|
||||
self.sync_output.emit([], False, False, [], False)
|
||||
|
||||
def tor_sync(self):
|
||||
try:
|
||||
ConfigurationController.set_connection('tor')
|
||||
self.text_output.emit('Syncing in progress...')
|
||||
ClientController.sync(client_observer=client_observer, connection_observer=connection_observer)
|
||||
locations = LocationController.get_all()
|
||||
all_location_codes = [location.country_name for location in locations]
|
||||
self.sync_output.emit(all_location_codes, True, True, locations, False)
|
||||
except ConnectionError:
|
||||
self.sync_output.emit([], False, False, [], False)
|
||||
except CommandNotFoundError:
|
||||
self.sync_output.emit([], False, False, [], True)
|
||||
|
||||
|
||||
def get_connection(self):
|
||||
|
@ -337,7 +326,10 @@ class CustomWindow(QMainWindow):
|
|||
self.current_profile_id = None
|
||||
self.connection_manager = ConnectionManager()
|
||||
|
||||
current_connection = ConfigurationController.get_connection()
|
||||
current_connection = self.get_current_connection()
|
||||
if current_connection is None:
|
||||
ConfigurationController.set_connection('system')
|
||||
current_connection = 'system'
|
||||
self.is_tor_mode = current_connection == 'tor'
|
||||
self.is_animating = False
|
||||
self.animation_step = 0
|
||||
|
@ -416,6 +408,13 @@ class CustomWindow(QMainWindow):
|
|||
self.check_logging()
|
||||
self.init_ui()
|
||||
|
||||
|
||||
def get_current_connection(self):
|
||||
try:
|
||||
return ConfigurationController.get_connection()
|
||||
except UnknownConnectionTypeError:
|
||||
return None
|
||||
|
||||
def _setup_gui_directory(self):
|
||||
os.makedirs(self.gui_dir, exist_ok=True)
|
||||
|
||||
|
@ -740,25 +739,23 @@ class CustomWindow(QMainWindow):
|
|||
self.editor_page = EditorPage(self.page_stack, self)
|
||||
self.pages = [MenuPage(self.page_stack, self),
|
||||
ProtocolPage(self.page_stack, self),
|
||||
WireGuardPage(self.page_stack, self),
|
||||
ResidentialPage(self.page_stack, self),
|
||||
HidetorPage(self.page_stack, self),
|
||||
lokinetPage(self.page_stack, self),
|
||||
OpenPage(self.page_stack, self),
|
||||
TorPage(self.page_stack, self),
|
||||
TorLocationPage(self.page_stack, self),
|
||||
PaymentPage(self.page_stack, self),
|
||||
LocationPage(self.page_stack, self),
|
||||
BrowserPage(self.page_stack, self),
|
||||
ScreenPage(self.page_stack, self),
|
||||
ResumePage(self.page_stack, self),
|
||||
IdPage(self.page_stack, self),
|
||||
WireGuardPage(self.page_stack, self),
|
||||
ResidentialPage(self.page_stack, self),
|
||||
HidetorPage(self.page_stack, self),
|
||||
InstallSystemPackage(self.page_stack, self),
|
||||
WelcomePage(self.page_stack, self),
|
||||
PaymentPage(self.page_stack, self),
|
||||
PaymentConfirmed(self.page_stack, self),
|
||||
IdPage(self.page_stack, self),
|
||||
TorPage(self.page_stack, self),
|
||||
EditorPage(self.page_stack, self),
|
||||
Settings(self.page_stack, self),
|
||||
ConnectionPage(self.page_stack, self)]
|
||||
ConnectionPage(self.page_stack, self),
|
||||
SyncScreen(self.page_stack, self)]
|
||||
for page in self.pages:
|
||||
self.page_stack.addWidget(page)
|
||||
# Conectar la señal currentChanged al método page_changed
|
||||
|
@ -801,7 +798,7 @@ class CustomWindow(QMainWindow):
|
|||
self.disable_marquee()
|
||||
|
||||
def check_first_launch(self):
|
||||
config_file = os.path.join(Constants.HV_CONFIG_HOME, '.first_launch')
|
||||
config_file = os.path.join(self.gui_dir, "first_launch.txt")
|
||||
|
||||
os.makedirs(Constants.HV_CONFIG_HOME, exist_ok=True)
|
||||
|
||||
|
@ -875,9 +872,7 @@ class CustomWindow(QMainWindow):
|
|||
elif isinstance(current_page, ResumePage):
|
||||
self.update_status('Choose a name for your profile')
|
||||
current_page.eliminacion()
|
||||
elif isinstance(current_page, ProtocolPage):
|
||||
if not self.connection_manager.is_synced():
|
||||
self.update_status('Choose a sync method')
|
||||
|
||||
elif isinstance(current_page, IdPage):
|
||||
pass
|
||||
elif isinstance(current_page, LocationPage):
|
||||
|
@ -1026,8 +1021,6 @@ class Worker(QObject):
|
|||
self.update_signal.emit("Application version file integrity could not be verified.", False, None, None, None)
|
||||
except ProfileModificationError:
|
||||
self.update_signal.emit("WireGuard configuration could not be attached.", False, None, None, None)
|
||||
#except OSError:
|
||||
# self.update_signal.emit("Connection could not be established.", False, None, None, None)
|
||||
except ProfileStateConflictError:
|
||||
self.update_signal.emit("The profile is already being enabled...", False, None, None, None)
|
||||
except CommandNotFoundError as e :
|
||||
|
@ -1111,79 +1104,23 @@ class MenuPage(Page):
|
|||
self.is_system_connected = False
|
||||
self.profile_button_map = {}
|
||||
|
||||
self.update_button = QPushButton(self)
|
||||
self.update_button.setGeometry(750, 530, 25, 25)
|
||||
self.update_button.setObjectName("update_button")
|
||||
update_icon = QtGui.QIcon(os.path.join(self.btn_path, "available-updates.png"))
|
||||
self.update_button.setIcon(update_icon)
|
||||
self.update_button.setIconSize(self.update_button.size())
|
||||
self.update_button.clicked.connect(self.check_updates)
|
||||
|
||||
#self.label.setStyleSheet("background-color: rgba(0, 255, 0, 51);")
|
||||
self.create_interface_elements() # Establecer el color de fondo y el color del texto utilizando hojas de estilo
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def check_updates(self):
|
||||
self.update_status.update_status("Checking for updates...")
|
||||
self.worker = WorkerThread('CHECK_FOR_UPDATE')
|
||||
self.worker.text_output.connect(self.update_status.update_status)
|
||||
self.worker.finished.connect(self.on_update_check_finished)
|
||||
self.worker.start()
|
||||
|
||||
def on_update_check_finished(self, result):
|
||||
if result:
|
||||
def on_update_check_finished(self):
|
||||
reply = QMessageBox.question(self, 'Update Available',
|
||||
'An update is available. Would you like to download it?',
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||
if reply == QMessageBox.StandardButton.Yes:
|
||||
self.worker = WorkerThread('DOWNLOAD_UPDATE')
|
||||
self.worker.text_output.connect(self.update_status.update_status)
|
||||
self.worker.update_finished.connect(self.on_update_download_finished)
|
||||
self.worker.start()
|
||||
else:
|
||||
self.update_status.update_status("Update cancelled by user.")
|
||||
else:
|
||||
self.update_status.update_status("No updates available.")
|
||||
|
||||
def on_update_download_finished(self, result: dict):
|
||||
if result["status"] and result["path"]:
|
||||
self.countdown_timer = QTimer()
|
||||
self.countdown_timer.setInterval(1000)
|
||||
self.countdown_seconds = 3
|
||||
self.new_app_path = result["path"]
|
||||
|
||||
def update_countdown():
|
||||
if self.countdown_seconds > 0:
|
||||
self.update_status.update_status(f"New version downloaded. Restarting in {self.countdown_seconds} second{'s' if self.countdown_seconds > 1 else ''}...")
|
||||
self.countdown_seconds -= 1
|
||||
else:
|
||||
self.countdown_timer.stop()
|
||||
self.restart_application()
|
||||
|
||||
def restart_application():
|
||||
QApplication.quit()
|
||||
current_app = Constants.APPIMAGE_PATH
|
||||
|
||||
if os.path.exists(self.new_app_path):
|
||||
try:
|
||||
os.remove(current_app)
|
||||
os.execv(self.new_app_path, [self.new_app_path] + sys.argv[1:])
|
||||
except PermissionError:
|
||||
self.update_status.update_status(f"Permission denied: Unable to remove {current_app}")
|
||||
else:
|
||||
self.update_status.update_status(f"Error: New application not found at {self.new_app_path}")
|
||||
|
||||
self.restart_application = restart_application
|
||||
self.countdown_timer.timeout.connect(update_countdown)
|
||||
self.countdown_timer.start()
|
||||
|
||||
atexit.register(restart_application)
|
||||
else:
|
||||
self.update_status.update_status("Failed to download update.")
|
||||
|
||||
def create_interface_elements(self):
|
||||
for icon_name, function, position in [
|
||||
|
@ -1580,11 +1517,6 @@ class MenuPage(Page):
|
|||
self.page_stack.currentWidget().add_selected_profile(editar_profile)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def launch(self):
|
||||
pass
|
||||
|
||||
|
@ -1648,6 +1580,9 @@ class MenuPage(Page):
|
|||
if len(self.profile_info) == 6:
|
||||
self.update_status.update_status('Maximum number of profiles reached!')
|
||||
return
|
||||
if not self.connection_manager.is_synced():
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(SyncScreen)))
|
||||
else:
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage)))
|
||||
|
||||
|
||||
|
@ -2517,138 +2452,12 @@ class ProtocolPage(Page):
|
|||
self.coming_soon_label.setGeometry(210, 50, 200, 40)
|
||||
self.coming_soon_label.setStyleSheet("font-size: 22px;")
|
||||
|
||||
self.sync_label = QLabel("Sync finds out what plans, countries, \n& browsers are available", self)
|
||||
self.sync_label.setGeometry(100, 120,500,60)
|
||||
self.sync_label.setStyleSheet("font-size: 20px;")
|
||||
|
||||
self.button_sync = QPushButton(self)
|
||||
self.button_sync.setObjectName("sync_button")
|
||||
self.button_sync.setGeometry(100, 250,150,60)
|
||||
self.button_sync.setIconSize(self.button_sync.size())
|
||||
icon = QIcon(os.path.join(self.btn_path, "sync_button.png"))
|
||||
self.button_sync.setIcon(icon)
|
||||
self.button_sync.clicked.connect(self.handle_core_action_sync_button)
|
||||
|
||||
self.tor_button_sync = QPushButton(self)
|
||||
self.tor_button_sync.setObjectName("tor_sync")
|
||||
self.tor_button_sync.setGeometry(300, 250,150,60)
|
||||
self.tor_button_sync.setIconSize(self.tor_button_sync.size())
|
||||
tor_icon = QIcon(os.path.join(self.btn_path, "tor_sync.png"))
|
||||
self.tor_button_sync.setIcon(tor_icon)
|
||||
self.tor_button_sync.clicked.connect(lambda: self.handle_core_action_sync_button(True))
|
||||
|
||||
self.button_sync.setVisible(True)
|
||||
self.tor_button_sync.setVisible(True)
|
||||
|
||||
|
||||
self.coming_soon_label.setVisible(False)
|
||||
self.title.setGeometry(585, 40, 185, 40); self.title.setText("Pick a Protocol")
|
||||
self.display.setGeometry(QtCore.QRect(0, 50, 580, 435))#relacion 4:3
|
||||
self.create_interface_elements()
|
||||
|
||||
|
||||
def sync_button(self, toggle: bool, sync_complete: bool=False):
|
||||
self.button_sync.setDisabled(toggle)
|
||||
self.tor_button_sync.setDisabled(toggle)
|
||||
|
||||
|
||||
if sync_complete:
|
||||
for button in self.buttons:
|
||||
button.setDisabled(toggle)
|
||||
self.button_sync.setVisible(False)
|
||||
self.tor_button_sync.setVisible(False)
|
||||
self.sync_label.setVisible(False)
|
||||
|
||||
def handle_core_action_sync_button(self, tor: bool = False):
|
||||
self.sync_button(True)
|
||||
|
||||
if tor:
|
||||
self.main_window.set_toggle_state(True)
|
||||
self.sync_button(True)
|
||||
self.update_status.update_status('Syncing through Tor in progress...')
|
||||
self.worker_thread = WorkerThread('SYNC_TOR')
|
||||
self.worker_thread.sync_output.connect(self.update_output)
|
||||
self.worker_thread.text_output.connect(self.update_text_output)
|
||||
self.worker_thread.start()
|
||||
return
|
||||
|
||||
self.update_status.update_status('Syncing in progress...')
|
||||
self.worker_thread = WorkerThread('SYNC')
|
||||
self.worker_thread.sync_output.connect(self.update_output)
|
||||
self.worker_thread.start()
|
||||
|
||||
|
||||
def update_text_output(self, text):
|
||||
self.update_status.update_status(text)
|
||||
|
||||
def update_output(self, available_locations, status, is_tor, locations, is_os_error):
|
||||
if is_os_error:
|
||||
install_page = self.page_stack.findChild(InstallSystemPackage)
|
||||
install_page.configure(package_name='tor', distro='debian', is_sync=True)
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(install_page))
|
||||
self.sync_button(False)
|
||||
return
|
||||
|
||||
if status is False:
|
||||
self.sync_button(False)
|
||||
self.update_status.update_status('An error occurred during sync')
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
self.update_status.update_status('Sync complete')
|
||||
self.connection_manager.set_synced(True)
|
||||
|
||||
available_locations_list = []
|
||||
self.connection_manager.store_locations(locations)
|
||||
|
||||
grid_positions = [
|
||||
(395, 90, 185, 75),
|
||||
(585, 90, 185, 75),
|
||||
(395, 195, 185, 75),
|
||||
(585, 195, 185, 75),
|
||||
(395, 300, 185, 75),
|
||||
(585, 300, 185, 75),
|
||||
(395, 405, 185, 75),
|
||||
(585, 405, 185, 75)
|
||||
]
|
||||
|
||||
list1 = []
|
||||
for i, location in enumerate(available_locations):
|
||||
position_index = i % len(grid_positions)
|
||||
list1.append((QPushButton, location, grid_positions[position_index]))
|
||||
|
||||
for item in list1:
|
||||
available_locations_list.append(item)
|
||||
|
||||
self.sync_button(False, True)
|
||||
location_page = self.find_location_page()
|
||||
hidetor_page = self.find_hidetor_page()
|
||||
print(f' the available locations list is {available_locations_list}')
|
||||
|
||||
if location_page:
|
||||
location_page.create_interface_elements(available_locations_list)
|
||||
if hidetor_page:
|
||||
hidetor_page.create_interface_elements(available_locations_list)
|
||||
|
||||
|
||||
|
||||
def find_location_page(self):
|
||||
for i in range(self.page_stack.count()):
|
||||
page = self.page_stack.widget(i)
|
||||
if isinstance(page, LocationPage):
|
||||
return page
|
||||
return None
|
||||
|
||||
def find_hidetor_page(self):
|
||||
for i in range(self.page_stack.count()):
|
||||
page = self.page_stack.widget(i)
|
||||
if isinstance(page, HidetorPage):
|
||||
return page
|
||||
return None
|
||||
|
||||
|
||||
def create_interface_elements(self):
|
||||
self.buttonGroup = QButtonGroup(self)
|
||||
self.buttons = []
|
||||
|
@ -2668,6 +2477,10 @@ class ProtocolPage(Page):
|
|||
self.buttonGroup.addButton(boton, j)
|
||||
boton.clicked.connect(lambda _, page=page_class, protocol=icon_name: self.show_protocol(page, protocol))
|
||||
|
||||
def enable_protocol_buttons(self):
|
||||
for button in self.buttons:
|
||||
button.setDisabled(False)
|
||||
|
||||
def update_swarp_json(self):
|
||||
self.update_status.write_data({"protocol": self.selected_protocol_icon})
|
||||
|
||||
|
@ -5724,6 +5537,252 @@ class ClickableValueLabel(QLabel):
|
|||
self.setStyleSheet(self.default_style)
|
||||
|
||||
|
||||
class SyncScreen(Page):
|
||||
def __init__(self, page_stack, main_window=None, parent=None):
|
||||
super().__init__("SyncScreen", page_stack, main_window, parent)
|
||||
self.main_window = main_window
|
||||
self.btn_path = main_window.btn_path
|
||||
self.update_status = main_window
|
||||
self.connection_manager = main_window.connection_manager
|
||||
self.is_tor_mode = main_window.is_tor_mode
|
||||
|
||||
|
||||
|
||||
self.heading_label = QLabel("You're about to fetch data from\nSimplified Privacy.", self)
|
||||
self.heading_label.setGeometry(15, 80, 750, 80)
|
||||
self.heading_label.setStyleSheet("font-size: 36px; font-weight: bold; color: white;")
|
||||
|
||||
self.data_description = QLabel("This data includes what plans, countries,\nbrowsers, and version upgrades are\navailable. As well as coordinating billing.", self)
|
||||
self.data_description.setGeometry(22, 190, 750, 90)
|
||||
self.data_description.setStyleSheet("font-size: 26px; font-weight: bold; color: #ffff00;")
|
||||
|
||||
self.instructions = QLabel("Use the toggle in the bottom right to\ndecide if you want to use Tor or not.\nThen hit \"Next\"", self)
|
||||
self.instructions.setGeometry(22, 345, 750, 100)
|
||||
self.instructions.setStyleSheet("font-size: 30px; font-weight: bold; color: white;")
|
||||
|
||||
self.arrow_label = QLabel(self)
|
||||
self.arrow_label.setGeometry(520, 400, 180, 130)
|
||||
arrow_pixmap = QPixmap(os.path.join(self.btn_path, "arrow-down.png"))
|
||||
|
||||
self.arrow_label.setPixmap(arrow_pixmap)
|
||||
self.arrow_label.raise_()
|
||||
|
||||
self.button_go.setVisible(True)
|
||||
self.button_back.setVisible(True)
|
||||
self.button_go.clicked.connect(self.perform_sync)
|
||||
self.button_back.clicked.connect(self.go_back)
|
||||
|
||||
def go_back(self):
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage)))
|
||||
|
||||
def perform_sync(self):
|
||||
self.button_go.setEnabled(False)
|
||||
self.button_back.setEnabled(False)
|
||||
self.update_status.update_status('Syncing in progress...')
|
||||
if self.main_window.get_current_connection() == 'tor':
|
||||
self.worker_thread = WorkerThread('SYNC_TOR')
|
||||
else:
|
||||
self.worker_thread = WorkerThread('SYNC')
|
||||
|
||||
self.worker_thread.sync_output.connect(self.update_output)
|
||||
self.worker_thread.start()
|
||||
|
||||
def update_output(self, available_locations, status, is_tor, locations, is_os_error):
|
||||
if is_os_error:
|
||||
install_page = self.page_stack.findChild(InstallSystemPackage)
|
||||
install_page.configure(package_name='tor', distro='debian', is_sync=True)
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(install_page))
|
||||
self.button_go.setEnabled(True)
|
||||
self.button_back.setEnabled(True)
|
||||
return
|
||||
|
||||
if status is False:
|
||||
self.button_go.setEnabled(True)
|
||||
self.button_back.setEnabled(True)
|
||||
self.update_status.update_status('An error occurred during sync')
|
||||
return
|
||||
|
||||
self.update_status.update_status('Sync complete')
|
||||
self.connection_manager.set_synced(True)
|
||||
|
||||
update_available = ClientController.can_be_updated()
|
||||
|
||||
if not update_available:
|
||||
menu_page = self.page_stack.findChild(MenuPage)
|
||||
menu_page.on_update_check_finished()
|
||||
|
||||
|
||||
available_locations_list = []
|
||||
self.connection_manager.store_locations(locations)
|
||||
|
||||
grid_positions = [
|
||||
(395, 90, 185, 75),
|
||||
(585, 90, 185, 75),
|
||||
(395, 195, 185, 75),
|
||||
(585, 195, 185, 75),
|
||||
(395, 300, 185, 75),
|
||||
(585, 300, 185, 75),
|
||||
(395, 405, 185, 75),
|
||||
(585, 405, 185, 75)
|
||||
]
|
||||
|
||||
list1 = []
|
||||
for i, location in enumerate(available_locations):
|
||||
position_index = i % len(grid_positions)
|
||||
list1.append((QPushButton, location, grid_positions[position_index]))
|
||||
|
||||
for item in list1:
|
||||
available_locations_list.append(item)
|
||||
|
||||
location_page = self.find_location_page()
|
||||
hidetor_page = self.find_hidetor_page()
|
||||
protocol_page = self.find_protocol_page()
|
||||
|
||||
if location_page:
|
||||
location_page.create_interface_elements(available_locations_list)
|
||||
if hidetor_page:
|
||||
hidetor_page.create_interface_elements(available_locations_list)
|
||||
if protocol_page:
|
||||
protocol_page.enable_protocol_buttons()
|
||||
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(ProtocolPage)))
|
||||
|
||||
def find_location_page(self):
|
||||
for i in range(self.page_stack.count()):
|
||||
page = self.page_stack.widget(i)
|
||||
if isinstance(page, LocationPage):
|
||||
return page
|
||||
return None
|
||||
|
||||
def find_hidetor_page(self):
|
||||
for i in range(self.page_stack.count()):
|
||||
page = self.page_stack.widget(i)
|
||||
if isinstance(page, HidetorPage):
|
||||
return page
|
||||
return None
|
||||
|
||||
def find_protocol_page(self):
|
||||
for i in range(self.page_stack.count()):
|
||||
page = self.page_stack.widget(i)
|
||||
if isinstance(page, ProtocolPage):
|
||||
return page
|
||||
return None
|
||||
|
||||
class WelcomePage(Page):
|
||||
def __init__(self, page_stack, main_window=None, parent=None):
|
||||
super().__init__("Welcome", page_stack, main_window, parent)
|
||||
self.btn_path = main_window.btn_path
|
||||
self.update_status = main_window
|
||||
self.ui_elements = []
|
||||
self.button_next.clicked.connect(self.go_to_install)
|
||||
self.button_next.setVisible(True)
|
||||
self._setup_welcome_ui()
|
||||
self._setup_stats_display()
|
||||
|
||||
def _setup_welcome_ui(self):
|
||||
welcome_title = QLabel("Welcome to HydraVeilVPN", self)
|
||||
welcome_title.setGeometry(20, 45, 760, 60)
|
||||
welcome_title.setStyleSheet("""
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: cyan;
|
||||
""")
|
||||
welcome_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
welcome_msg = QLabel(
|
||||
"Before we begin your journey, we need to set up a few essential components. "
|
||||
"Click 'Next' to take you to the installation page.", self)
|
||||
welcome_msg.setGeometry(40, 100, 720, 80)
|
||||
welcome_msg.setWordWrap(True)
|
||||
welcome_msg.setStyleSheet("""
|
||||
font-size: 16px;
|
||||
color: cyan;
|
||||
""")
|
||||
welcome_msg.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
def _setup_stats_display(self):
|
||||
stats_container = QWidget(self)
|
||||
stats_container.setGeometry(70, 200, 730, 240)
|
||||
|
||||
stats_title = QLabel(stats_container)
|
||||
stats_title.setText("Features & Services")
|
||||
stats_title.setGeometry(190, 10, 300, 30)
|
||||
stats_title.setStyleSheet("""
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: cyan;
|
||||
""")
|
||||
|
||||
grid_widget = QWidget(stats_container)
|
||||
grid_widget.setGeometry(0, 70, 700, 190)
|
||||
grid_layout = QGridLayout(grid_widget)
|
||||
grid_layout.setSpacing(30)
|
||||
|
||||
stats = [
|
||||
("Browsers", "browsers_mini.png", "10 Supported Browsers", True),
|
||||
("WireGuard", "wireguard_mini.png", "6 Global Locations", True),
|
||||
("Proxy", "just proxy_mini.png", "5 Proxy Locations", True),
|
||||
("Tor", "toricon_mini.png", "Tor Network Access", True)
|
||||
]
|
||||
|
||||
for i, (title, icon_name, count, available) in enumerate(stats):
|
||||
row = i // 2
|
||||
col = i % 2
|
||||
|
||||
stat_widget = QWidget()
|
||||
stat_layout = QHBoxLayout(stat_widget)
|
||||
stat_layout.setContentsMargins(20, 10, 2, 10)
|
||||
stat_layout.setSpacing(15)
|
||||
|
||||
icon_label = QLabel()
|
||||
icon_path = os.path.join(self.btn_path, icon_name)
|
||||
icon_label.setPixmap(QPixmap(icon_path).scaled(30, 30, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation))
|
||||
icon_label.setFixedSize(30, 30)
|
||||
stat_layout.addWidget(icon_label)
|
||||
|
||||
text_widget = QWidget()
|
||||
text_layout = QVBoxLayout(text_widget)
|
||||
text_layout.setSpacing(5)
|
||||
text_layout.setContentsMargins(0, 0, 30, 0)
|
||||
|
||||
title_widget = QWidget()
|
||||
title_layout = QHBoxLayout(title_widget)
|
||||
title_layout.setContentsMargins(0, 0, 0, 0)
|
||||
title_layout.setSpacing(10)
|
||||
|
||||
title_label = QLabel(title)
|
||||
title_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #2c3e50;")
|
||||
title_layout.addWidget(title_label)
|
||||
|
||||
status_indicator = QLabel("●")
|
||||
status_indicator.setStyleSheet("color: #2ecc71; font-size: 16px;")
|
||||
title_layout.addWidget(status_indicator)
|
||||
|
||||
title_layout.addStretch()
|
||||
text_layout.addWidget(title_widget)
|
||||
|
||||
count_label = QLabel(count)
|
||||
count_label.setStyleSheet("color: #34495e;")
|
||||
text_layout.addWidget(count_label)
|
||||
|
||||
stat_layout.addWidget(text_widget, stretch=1)
|
||||
|
||||
stat_widget.setStyleSheet("""
|
||||
QWidget {
|
||||
background-color: transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
""")
|
||||
|
||||
grid_layout.addWidget(stat_widget, row, col)
|
||||
|
||||
|
||||
def go_to_install(self):
|
||||
install_page = self.page_stack.findChild(InstallSystemPackage)
|
||||
install_page.configure(package_name='all', distro='debian')
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(install_page))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
window = CustomWindow()
|
||||
|
|
BIN
gui/resources/images/arrow-down.png
Normal file
BIN
gui/resources/images/arrow-down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 32 KiB |
Loading…
Reference in a new issue