added new wg debugging tool
This commit is contained in:
parent
94050228f3
commit
52a4fd8be7
1 changed files with 565 additions and 26 deletions
585
gui/__main__.py
Normal file → Executable file
585
gui/__main__.py
Normal file → Executable file
|
@ -895,6 +895,7 @@ class CustomWindow(QMainWindow):
|
|||
IdPage(self.page_stack, self),
|
||||
TorPage(self.page_stack, self),
|
||||
EditorPage(self.page_stack, self),
|
||||
FastModePromptPage(self.page_stack, self),
|
||||
FastRegistrationPage(self.page_stack, self),
|
||||
Settings(self.page_stack, self),
|
||||
ConnectionPage(self.page_stack, self),
|
||||
|
@ -949,6 +950,34 @@ class CustomWindow(QMainWindow):
|
|||
else:
|
||||
return False
|
||||
|
||||
def has_shown_fast_mode_prompt(self):
|
||||
flag_file = os.path.join(self.gui_config_home, '.fast-mode-prompted')
|
||||
return os.path.exists(flag_file)
|
||||
|
||||
def mark_fast_mode_prompt_shown(self):
|
||||
os.makedirs(self.gui_config_home, exist_ok=True)
|
||||
flag_file = os.path.join(self.gui_config_home, '.fast-mode-prompted')
|
||||
try:
|
||||
with open(flag_file, 'w') as f:
|
||||
f.write('shown')
|
||||
except Exception as e:
|
||||
print(f"Error writing fast mode flag: {e}")
|
||||
|
||||
def set_fast_mode_enabled(self, enabled):
|
||||
config = self._load_gui_config()
|
||||
if config is None:
|
||||
config = {"logging": {"gui_logging_enabled": False, "log_level": "INFO"}}
|
||||
if "registrations" not in config:
|
||||
config["registrations"] = {}
|
||||
config["registrations"]["fast_registration_enabled"] = bool(enabled)
|
||||
self._save_gui_config(config)
|
||||
|
||||
def navigate_after_profile_created(self):
|
||||
if not self.has_shown_fast_mode_prompt():
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(FastModePromptPage)))
|
||||
else:
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage)))
|
||||
|
||||
def enable_marquee(self, text):
|
||||
self.marquee_text = text + " "
|
||||
self.marquee_position = 0
|
||||
|
@ -1015,7 +1044,7 @@ class CustomWindow(QMainWindow):
|
|||
|
||||
if isinstance(current_page, MenuPage):
|
||||
self.update_status(None)
|
||||
if isinstance(previous_page, (ResumePage, EditorPage, Settings, FastRegistrationPage)):
|
||||
if isinstance(previous_page, (ResumePage, EditorPage, Settings, FastRegistrationPage, FastModePromptPage)):
|
||||
current_page.eliminacion()
|
||||
|
||||
else:
|
||||
|
@ -3893,8 +3922,11 @@ class ResumePage(Page):
|
|||
self.create_core_profiles(new_profile, profile_id)
|
||||
|
||||
|
||||
# Restablecer el índice de la página actual al menú principal
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage)))
|
||||
main = self.update_status
|
||||
if hasattr(main, 'navigate_after_profile_created'):
|
||||
main.navigate_after_profile_created()
|
||||
else:
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage)))
|
||||
|
||||
self.update_status.clear_data()
|
||||
|
||||
|
@ -4497,11 +4529,7 @@ class EditorPage(Page):
|
|||
|
||||
else:
|
||||
location = self.connection_manager.get_location_info(new_value)
|
||||
if profile.has_wireguard_configuration():
|
||||
profile.delete_wireguard_configuration()
|
||||
|
||||
if profile.has_proxy_configuration():
|
||||
profile.delete_proxy_configuration()
|
||||
|
||||
if location:
|
||||
profile.location.code = location.code
|
||||
|
@ -4614,7 +4642,8 @@ class Settings(Page):
|
|||
("Subscriptions", self.show_subscription_page),
|
||||
("Create/Edit", self.show_registrations_page),
|
||||
("Delete Profile", self.show_delete_page),
|
||||
("Error Logs", self.show_logs_page)
|
||||
("Error Logs", self.show_logs_page),
|
||||
("Debug Help", self.show_debug_page)
|
||||
]
|
||||
|
||||
|
||||
|
@ -4657,12 +4686,14 @@ class Settings(Page):
|
|||
self.subscription_page = self.create_subscription_page()
|
||||
self.logs_page = self.create_logs_page()
|
||||
self.delete_page = self.create_delete_page()
|
||||
self.debug_page = self.create_debug_page()
|
||||
|
||||
self.content_layout.addWidget(self.account_page)
|
||||
self.content_layout.addWidget(self.wireguard_page)
|
||||
self.content_layout.addWidget(self.subscription_page)
|
||||
self.content_layout.addWidget(self.logs_page)
|
||||
self.content_layout.addWidget(self.delete_page)
|
||||
self.content_layout.addWidget(self.debug_page)
|
||||
|
||||
self.show_account_page()
|
||||
|
||||
|
@ -4751,6 +4782,344 @@ class Settings(Page):
|
|||
|
||||
return page
|
||||
|
||||
def create_debug_page(self):
|
||||
page = QWidget()
|
||||
layout = QVBoxLayout(page)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
layout.setSpacing(15)
|
||||
|
||||
title = QLabel("DEBUG HELP")
|
||||
title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
layout.addWidget(title)
|
||||
|
||||
scroll_area = QScrollArea()
|
||||
scroll_area.setWidgetResizable(True)
|
||||
scroll_area.setStyleSheet(f"""
|
||||
QScrollArea {{
|
||||
border: none;
|
||||
background: transparent;
|
||||
}}
|
||||
QScrollArea > QWidget > QWidget {{
|
||||
background: transparent;
|
||||
}}
|
||||
""")
|
||||
|
||||
scroll_content = QWidget()
|
||||
scroll_layout = QVBoxLayout(scroll_content)
|
||||
scroll_layout.setSpacing(15)
|
||||
|
||||
app_path = sys.executable if hasattr(sys, 'frozen') else os.path.abspath(__file__)
|
||||
if hasattr(sys, 'frozen'):
|
||||
app_dir = os.path.dirname(app_path)
|
||||
else:
|
||||
app_dir = os.path.dirname(os.path.dirname(app_path))
|
||||
|
||||
app_path_label = QLabel(f"Application Path: {app_path}")
|
||||
app_path_label.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}")
|
||||
app_path_label.setWordWrap(True)
|
||||
scroll_layout.addWidget(app_path_label)
|
||||
|
||||
app_dir_label = QLabel(f"Application Directory: {app_dir}")
|
||||
app_dir_label.setStyleSheet(f"color: white; font-size: 14px; {self.font_style}")
|
||||
app_dir_label.setWordWrap(True)
|
||||
scroll_layout.addWidget(app_dir_label)
|
||||
|
||||
command_group = QGroupBox("CLI Commands")
|
||||
command_group.setStyleSheet(f"""
|
||||
QGroupBox {{
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
font-size: 10px;
|
||||
margin-top: 15px;
|
||||
{self.font_style}
|
||||
}}
|
||||
QGroupBox::title {{
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px;
|
||||
}}
|
||||
""")
|
||||
command_layout = QVBoxLayout(command_group)
|
||||
|
||||
self.cli_command = QLineEdit()
|
||||
self.cli_command.setReadOnly(True)
|
||||
self.cli_command.setText(f"{app_path} --cli profile enable -i 1")
|
||||
self.cli_command.setStyleSheet(f"""
|
||||
QLineEdit {{
|
||||
color: white;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
}}
|
||||
""")
|
||||
command_layout.addWidget(self.cli_command)
|
||||
|
||||
copy_button = QPushButton("Copy Command")
|
||||
copy_button.setFixedSize(120, 40)
|
||||
copy_button.setStyleSheet(f"""
|
||||
QPushButton {{
|
||||
font-size: 12px;
|
||||
background: #007AFF;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
{self.font_style}
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
background: #0056CC;
|
||||
}}
|
||||
""")
|
||||
copy_button.clicked.connect(self.copy_cli_command)
|
||||
command_layout.addWidget(copy_button)
|
||||
|
||||
execute_button = QPushButton("Execute Command")
|
||||
execute_button.setFixedSize(120, 40)
|
||||
execute_button.setStyleSheet(f"""
|
||||
QPushButton {{
|
||||
font-size: 10px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
{self.font_style}
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
background: #45a049;
|
||||
}}
|
||||
""")
|
||||
execute_button.clicked.connect(self.execute_cli_command)
|
||||
command_layout.addWidget(execute_button)
|
||||
|
||||
scroll_layout.addWidget(command_group)
|
||||
|
||||
debug_helper_group = QGroupBox("Debug Helper")
|
||||
debug_helper_group.setStyleSheet(f"""
|
||||
QGroupBox {{
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
font-size: 10px;
|
||||
margin-top: 15px;
|
||||
{self.font_style}
|
||||
}}
|
||||
QGroupBox::title {{
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px;
|
||||
}}
|
||||
""")
|
||||
debug_helper_layout = QVBoxLayout(debug_helper_group)
|
||||
|
||||
profile_label = QLabel("Select System-wide Profile:")
|
||||
profile_label.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}")
|
||||
debug_helper_layout.addWidget(profile_label)
|
||||
|
||||
self.debug_profile_selector = QComboBox()
|
||||
self.debug_profile_selector.setStyleSheet(self.get_combobox_style())
|
||||
self.debug_profile_selector.currentTextChanged.connect(self.on_debug_profile_selected)
|
||||
debug_helper_layout.addWidget(self.debug_profile_selector)
|
||||
|
||||
self.ping_instruction_label = QLabel("")
|
||||
self.ping_instruction_label.setStyleSheet(f"color: white; font-size: 12px; {self.font_style}")
|
||||
self.ping_instruction_label.setWordWrap(True)
|
||||
self.ping_instruction_label.hide()
|
||||
debug_helper_layout.addWidget(self.ping_instruction_label)
|
||||
|
||||
ping_buttons_layout = QHBoxLayout()
|
||||
|
||||
self.copy_ping_button = QPushButton("Copy Ping Command")
|
||||
self.copy_ping_button.setFixedSize(140, 40)
|
||||
self.copy_ping_button.setStyleSheet(f"""
|
||||
QPushButton {{
|
||||
font-size: 12px;
|
||||
background: #007AFF;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
{self.font_style}
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
background: #0056CC;
|
||||
}}
|
||||
QPushButton:disabled {{
|
||||
background: #666666;
|
||||
}}
|
||||
""")
|
||||
self.copy_ping_button.clicked.connect(self.copy_ping_command)
|
||||
self.copy_ping_button.setEnabled(False)
|
||||
ping_buttons_layout.addWidget(self.copy_ping_button)
|
||||
|
||||
self.test_ping_button = QPushButton("Test Ping")
|
||||
self.test_ping_button.setFixedSize(120, 40)
|
||||
self.test_ping_button.setStyleSheet(f"""
|
||||
QPushButton {{
|
||||
font-size: 12px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
{self.font_style}
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
background: #45a049;
|
||||
}}
|
||||
QPushButton:disabled {{
|
||||
background: #666666;
|
||||
}}
|
||||
""")
|
||||
self.test_ping_button.clicked.connect(self.test_ping_connection)
|
||||
self.test_ping_button.setEnabled(False)
|
||||
ping_buttons_layout.addWidget(self.test_ping_button)
|
||||
|
||||
debug_helper_layout.addLayout(ping_buttons_layout)
|
||||
|
||||
self.ping_result_label = QLabel("")
|
||||
self.ping_result_label.setStyleSheet(f"color: white; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
self.ping_result_label.setWordWrap(True)
|
||||
self.ping_result_label.hide()
|
||||
debug_helper_layout.addWidget(self.ping_result_label)
|
||||
|
||||
self.update_debug_profile_list()
|
||||
scroll_layout.addWidget(debug_helper_group)
|
||||
|
||||
scroll_area.setWidget(scroll_content)
|
||||
layout.addWidget(scroll_area)
|
||||
|
||||
return page
|
||||
|
||||
def copy_cli_command(self):
|
||||
clipboard = QApplication.clipboard()
|
||||
clipboard.setText(self.cli_command.text())
|
||||
self.update_status.update_status("CLI command copied to clipboard")
|
||||
|
||||
def execute_cli_command(self):
|
||||
try:
|
||||
command = self.cli_command.text().split()
|
||||
subprocess.Popen(command)
|
||||
self.update_status.update_status("CLI command executed")
|
||||
except Exception as e:
|
||||
self.update_status.update_status(f"Error executing command: {str(e)}")
|
||||
|
||||
def update_debug_profile_list(self):
|
||||
self.debug_profile_selector.clear()
|
||||
profiles = ProfileController.get_all()
|
||||
system_profiles = {pid: profile for pid, profile in profiles.items() if isinstance(profile, SystemProfile)}
|
||||
|
||||
if system_profiles:
|
||||
for profile_id, profile in system_profiles.items():
|
||||
self.debug_profile_selector.addItem(f"Profile {profile_id}: {profile.name}", profile_id)
|
||||
else:
|
||||
self.debug_profile_selector.addItem("No system-wide profiles found", None)
|
||||
|
||||
def on_debug_profile_selected(self, text):
|
||||
profile_id = self.debug_profile_selector.currentData()
|
||||
if profile_id is None:
|
||||
self.ping_instruction_label.hide()
|
||||
self.copy_ping_button.setEnabled(False)
|
||||
self.test_ping_button.setEnabled(False)
|
||||
self.ping_result_label.hide()
|
||||
return
|
||||
|
||||
profile = ProfileController.get(profile_id)
|
||||
if profile and isinstance(profile, SystemProfile):
|
||||
ip_address = self.extract_endpoint_ip(profile)
|
||||
if ip_address:
|
||||
self.ping_instruction_label.setText(f"Step 1, Can you Ping it? Copy-paste the command below into your terminal. This VPN Node's IP address is {ip_address}")
|
||||
self.ping_instruction_label.show()
|
||||
self.copy_ping_button.setEnabled(True)
|
||||
self.test_ping_button.setEnabled(True)
|
||||
self.ping_result_label.hide()
|
||||
else:
|
||||
self.ping_instruction_label.setText("Could not extract IP address from WireGuard configuration")
|
||||
self.ping_instruction_label.show()
|
||||
self.copy_ping_button.setEnabled(False)
|
||||
self.test_ping_button.setEnabled(False)
|
||||
self.ping_result_label.hide()
|
||||
|
||||
def extract_endpoint_ip(self, profile):
|
||||
try:
|
||||
profile_path = Constants.HV_PROFILE_CONFIG_HOME + f'/{profile.id}'
|
||||
wg_conf_path = f'{profile_path}/wg.conf.bak'
|
||||
if not os.path.exists(wg_conf_path):
|
||||
return None
|
||||
|
||||
with open(wg_conf_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
for line in content.split('\n'):
|
||||
if line.strip().startswith('Endpoint = '):
|
||||
endpoint = line.strip().split(' = ')[1]
|
||||
ip_address = endpoint.split(':')[0]
|
||||
return ip_address
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def copy_ping_command(self):
|
||||
profile_id = self.debug_profile_selector.currentData()
|
||||
if profile_id is None:
|
||||
return
|
||||
|
||||
profile = ProfileController.get(profile_id)
|
||||
if profile and isinstance(profile, SystemProfile):
|
||||
ip_address = self.extract_endpoint_ip(profile)
|
||||
if ip_address:
|
||||
ping_command = f"ping {ip_address}"
|
||||
clipboard = QApplication.clipboard()
|
||||
clipboard.setText(ping_command)
|
||||
self.update_status.update_status("Ping command copied to clipboard")
|
||||
|
||||
def test_ping_connection(self):
|
||||
profile_id = self.debug_profile_selector.currentData()
|
||||
if profile_id is None:
|
||||
return
|
||||
|
||||
profile = ProfileController.get(profile_id)
|
||||
if profile and isinstance(profile, SystemProfile):
|
||||
ip_address = self.extract_endpoint_ip(profile)
|
||||
if ip_address:
|
||||
self.test_ping_button.setEnabled(False)
|
||||
self.ping_result_label.setText("Testing ping...")
|
||||
self.ping_result_label.setStyleSheet(f"color: #FFA500; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
self.ping_result_label.show()
|
||||
|
||||
def ping_test():
|
||||
try:
|
||||
if sys.platform == "win32":
|
||||
result = subprocess.run(['ping', '-n', '4', ip_address],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
else:
|
||||
result = subprocess.run(['ping', '-c', '4', ip_address],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
if result.returncode == 0:
|
||||
self.ping_result_label.setText("✅ Ping successful - Connection is working!")
|
||||
self.ping_result_label.setStyleSheet(f"color: #4CAF50; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
else:
|
||||
self.ping_result_label.setText("❌ Ping failed - Connection issue detected")
|
||||
self.ping_result_label.setStyleSheet(f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
except subprocess.TimeoutExpired:
|
||||
self.ping_result_label.setText("❌ Ping timeout - Connection issue detected")
|
||||
self.ping_result_label.setStyleSheet(f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
except Exception as e:
|
||||
self.ping_result_label.setText(f"❌ Ping error: {str(e)}")
|
||||
self.ping_result_label.setStyleSheet(f"color: #F44336; font-size: 12px; font-weight: bold; {self.font_style}")
|
||||
finally:
|
||||
self.test_ping_button.setEnabled(True)
|
||||
|
||||
threading.Thread(target=ping_test, daemon=True).start()
|
||||
|
||||
def on_profile_selected(self, button):
|
||||
self.delete_button.setEnabled(True)
|
||||
self.selected_profile_id = self.profile_buttons.id(button)
|
||||
|
@ -4903,6 +5272,10 @@ class Settings(Page):
|
|||
self.content_layout.setCurrentWidget(self.logs_page)
|
||||
self.update_button_states(4)
|
||||
|
||||
def show_debug_page(self):
|
||||
self.content_layout.setCurrentWidget(self.debug_page)
|
||||
self.update_button_states(5)
|
||||
|
||||
def update_button_states(self, active_index):
|
||||
for i, btn in enumerate(self.menu_buttons):
|
||||
btn.setChecked(i == active_index)
|
||||
|
@ -4975,26 +5348,70 @@ class Settings(Page):
|
|||
]
|
||||
|
||||
for i, (label, key) in enumerate(info_items):
|
||||
stat_widget = self.create_stat_widget(label, "N/A")
|
||||
row, col = divmod(i, 2)
|
||||
subscription_layout.addWidget(stat_widget, row, col)
|
||||
if key == "billing_code":
|
||||
billing_container = QWidget()
|
||||
billing_layout = QVBoxLayout(billing_container)
|
||||
billing_layout.setContentsMargins(0, 0, 0, 0)
|
||||
billing_layout.setSpacing(5)
|
||||
|
||||
old_label = stat_widget.findChild(QLabel, "value_label")
|
||||
if old_label:
|
||||
old_label.setParent(None)
|
||||
old_label.deleteLater()
|
||||
stat_widget = self.create_stat_widget(label, "N/A")
|
||||
billing_layout.addWidget(stat_widget)
|
||||
|
||||
value_label = ClickableValueLabel("N/A", stat_widget)
|
||||
value_label.setObjectName("value_label")
|
||||
value_label.setStyleSheet(f"color: #00ffff; font-size: 12px; font-family: 'Retro Gaming', sans-serif;")
|
||||
value_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
stat_widget.layout().insertWidget(0, value_label)
|
||||
copy_button = QPushButton("Copy")
|
||||
copy_button.setFixedSize(60, 30)
|
||||
copy_button.setStyleSheet(f"""
|
||||
QPushButton {{
|
||||
background: #007AFF;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
{self.font_style}
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
background: #0056CC;
|
||||
}}
|
||||
""")
|
||||
copy_button.clicked.connect(lambda: self.copy_billing_code())
|
||||
billing_layout.addWidget(copy_button)
|
||||
|
||||
self.subscription_info[key] = value_label
|
||||
row, col = divmod(i, 2)
|
||||
subscription_layout.addWidget(billing_container, row, col)
|
||||
|
||||
old_label = stat_widget.findChild(QLabel, "value_label")
|
||||
if old_label:
|
||||
old_label.setParent(None)
|
||||
old_label.deleteLater()
|
||||
|
||||
value_label = ClickableValueLabel("N/A", stat_widget)
|
||||
value_label.setObjectName("value_label")
|
||||
value_label.setStyleSheet(f"color: #00ffff; font-size: 12px; font-family: 'Retro Gaming', sans-serif;")
|
||||
value_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
stat_widget.layout().insertWidget(0, value_label)
|
||||
|
||||
self.subscription_info[key] = value_label
|
||||
else:
|
||||
stat_widget = self.create_stat_widget(label, "N/A")
|
||||
row, col = divmod(i, 2)
|
||||
subscription_layout.addWidget(stat_widget, row, col)
|
||||
|
||||
old_label = stat_widget.findChild(QLabel, "value_label")
|
||||
if old_label:
|
||||
old_label.setParent(None)
|
||||
old_label.deleteLater()
|
||||
|
||||
value_label = ClickableValueLabel("N/A", stat_widget)
|
||||
value_label.setObjectName("value_label")
|
||||
value_label.setStyleSheet(f"color: #00ffff; font-size: 12px; font-family: 'Retro Gaming', sans-serif;")
|
||||
value_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
stat_widget.layout().insertWidget(0, value_label)
|
||||
|
||||
self.subscription_info[key] = value_label
|
||||
|
||||
layout.addWidget(subscription_group)
|
||||
|
||||
clipboard_hint = QLabel("💡 Click on the billing code to copy it to clipboard")
|
||||
clipboard_hint = QLabel("💡 Click on the billing code or use the Copy button to copy it to clipboard")
|
||||
clipboard_hint.setStyleSheet(f"color: #666666; font-size: 11px; font-style: italic; {self.font_style}")
|
||||
clipboard_hint.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
layout.addWidget(clipboard_hint)
|
||||
|
@ -5032,6 +5449,16 @@ class Settings(Page):
|
|||
for label in self.subscription_info.values():
|
||||
label.setText("N/A")
|
||||
|
||||
def copy_billing_code(self):
|
||||
if "billing_code" in self.subscription_info:
|
||||
billing_code = self.subscription_info["billing_code"].text()
|
||||
if billing_code and billing_code != "N/A":
|
||||
clipboard = QApplication.clipboard()
|
||||
clipboard.setText(billing_code)
|
||||
self.update_status.update_status("Billing code copied to clipboard")
|
||||
else:
|
||||
self.update_status.update_status("No billing code available to copy")
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
|
||||
|
@ -5058,6 +5485,10 @@ class Settings(Page):
|
|||
self.logs_page = self.create_logs_page()
|
||||
self.content_layout.addWidget(self.logs_page)
|
||||
|
||||
self.content_layout.removeWidget(self.debug_page)
|
||||
self.debug_page = self.create_debug_page()
|
||||
self.content_layout.addWidget(self.debug_page)
|
||||
|
||||
self.content_layout.setCurrentIndex(current_index)
|
||||
|
||||
if self.content_layout.currentWidget() == self.subscription_page:
|
||||
|
@ -5252,12 +5683,14 @@ class Settings(Page):
|
|||
self.registrations_page = self.create_registrations_page()
|
||||
self.logs_page = self.create_logs_page()
|
||||
self.delete_page = self.create_delete_page()
|
||||
self.debug_page = self.create_debug_page()
|
||||
|
||||
self.content_layout.addWidget(self.account_page)
|
||||
self.content_layout.addWidget(self.subscription_page)
|
||||
self.content_layout.addWidget(self.registrations_page)
|
||||
self.content_layout.addWidget(self.logs_page)
|
||||
self.content_layout.addWidget(self.delete_page)
|
||||
self.content_layout.addWidget(self.debug_page)
|
||||
|
||||
self.show_account_page()
|
||||
|
||||
|
@ -6706,6 +7139,32 @@ class FastRegistrationPage(Page):
|
|||
|
||||
self.initialize_default_selections()
|
||||
|
||||
def initialize_default_selections(self):
|
||||
if not self.selected_values['location']:
|
||||
locations = self.connection_manager.get_location_list()
|
||||
if locations:
|
||||
random_index = random.randint(0, len(locations) - 1)
|
||||
self.selected_values['location'] = locations[random_index]
|
||||
|
||||
if not self.selected_values['browser']:
|
||||
browsers = self.connection_manager.get_browser_list()
|
||||
if browsers:
|
||||
random_index = random.randint(0, len(browsers) - 1)
|
||||
self.selected_values['browser'] = browsers[random_index]
|
||||
|
||||
def get_next_available_profile_id(self) -> int:
|
||||
profiles = ProfileController.get_all()
|
||||
if not profiles:
|
||||
return 1
|
||||
|
||||
existing_ids = sorted(profiles.keys())
|
||||
|
||||
for i in range(1, max(existing_ids) + 2):
|
||||
if i not in existing_ids:
|
||||
return i
|
||||
|
||||
return 1
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
self.initialize_default_selections()
|
||||
|
@ -6729,6 +7188,7 @@ class FastRegistrationPage(Page):
|
|||
self.create_location_section()
|
||||
self.create_browser_section()
|
||||
self.create_resolution_section()
|
||||
self.update_ui_state_for_connection()
|
||||
|
||||
def create_protocol_section(self):
|
||||
label = QLabel("Protocol", self)
|
||||
|
@ -6907,6 +7367,17 @@ class FastRegistrationPage(Page):
|
|||
next_button.setIconSize(next_button.size())
|
||||
self.buttons.append(next_button)
|
||||
|
||||
def update_ui_state_for_connection(self):
|
||||
is_system_wide = self.selected_values['connection'] == 'system-wide'
|
||||
|
||||
for button in self.buttons:
|
||||
if hasattr(button, 'geometry'):
|
||||
button_geometry = button.geometry()
|
||||
if button_geometry.y() == 350:
|
||||
if button_geometry.x() in [115, 340, 400, 625]:
|
||||
button.setEnabled(not is_system_wide)
|
||||
|
||||
|
||||
def show_previous_value(self, key):
|
||||
if key == 'protocol':
|
||||
protocols = ['wireguard', 'hidetor']
|
||||
|
@ -6925,6 +7396,7 @@ class FastRegistrationPage(Page):
|
|||
current_index = connections.index(self.selected_values[key])
|
||||
previous_index = (current_index - 1) % len(connections)
|
||||
self.selected_values[key] = connections[previous_index]
|
||||
self.update_ui_state_for_connection()
|
||||
elif key == 'location':
|
||||
locations = self.connection_manager.get_location_list()
|
||||
if locations and self.selected_values[key] in locations:
|
||||
|
@ -6967,6 +7439,7 @@ class FastRegistrationPage(Page):
|
|||
current_index = connections.index(self.selected_values[key])
|
||||
next_index = (current_index + 1) % len(connections)
|
||||
self.selected_values[key] = connections[next_index]
|
||||
self.update_ui_state_for_connection()
|
||||
elif key == 'location':
|
||||
locations = self.connection_manager.get_location_list()
|
||||
if locations and self.selected_values[key] in locations:
|
||||
|
@ -7048,7 +7521,10 @@ class FastRegistrationPage(Page):
|
|||
|
||||
resume_page = self.find_resume_page()
|
||||
if resume_page:
|
||||
resume_page.handle_core_action_create_profile('CREATE_SESSION_PROFILE', profile_data_for_resume, 'session')
|
||||
if profile_data['connection'] == 'system-wide':
|
||||
resume_page.handle_core_action_create_profile('CREATE_SYSTEM_PROFILE', profile_data_for_resume, 'system')
|
||||
else:
|
||||
resume_page.handle_core_action_create_profile('CREATE_SESSION_PROFILE', profile_data_for_resume, 'session')
|
||||
|
||||
def create_tor_profile(self, profile_data):
|
||||
location_info = self.connection_manager.get_location_info(profile_data['location'])
|
||||
|
@ -7082,6 +7558,69 @@ class FastRegistrationPage(Page):
|
|||
return page
|
||||
return None
|
||||
|
||||
class FastModePromptPage(Page):
|
||||
def __init__(self, page_stack, main_window):
|
||||
super().__init__("FastModePrompt", page_stack, main_window)
|
||||
self.page_stack = page_stack
|
||||
self.update_status = main_window
|
||||
self.title.setGeometry(500, 40, 350, 40)
|
||||
self.title.setText("Quick Setup Option")
|
||||
self.button_back.setVisible(False)
|
||||
self.button_apply.setVisible(False)
|
||||
|
||||
container = QWidget(self)
|
||||
container.setGeometry(QtCore.QRect(80, 100, 640, 360))
|
||||
v = QVBoxLayout(container)
|
||||
v.setContentsMargins(0, 0, 0, 0)
|
||||
v.setSpacing(20)
|
||||
|
||||
large_text = QLabel("Would you like to switch to convenient \"fast mode\" for profile creation going forward? (recommended)")
|
||||
large_text.setWordWrap(True)
|
||||
large_text.setStyleSheet("color: white; font-size: 18px;")
|
||||
large_text.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||
v.addWidget(large_text)
|
||||
|
||||
buttons_row = QWidget()
|
||||
h = QHBoxLayout(buttons_row)
|
||||
h.setContentsMargins(0, 0, 0, 0)
|
||||
h.setSpacing(20)
|
||||
|
||||
yes_btn = QPushButton("Yes Fast Mode")
|
||||
yes_btn.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)
|
||||
yes_btn.setFixedSize(240, 56)
|
||||
yes_btn.setStyleSheet("background-color: #27ae60; color: white; font-weight: bold; font-size: 16px; border: none; border-radius: 6px;")
|
||||
yes_btn.clicked.connect(self.choose_yes)
|
||||
|
||||
no_btn = QPushButton("No Keep This")
|
||||
no_btn.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)
|
||||
no_btn.setFixedSize(160, 42)
|
||||
no_btn.setStyleSheet("background-color: #c0392b; color: white; font-size: 14px; border: none; border-radius: 6px;")
|
||||
no_btn.clicked.connect(self.choose_no)
|
||||
|
||||
h.addStretch()
|
||||
h.addWidget(yes_btn)
|
||||
h.addWidget(no_btn)
|
||||
h.addStretch()
|
||||
v.addWidget(buttons_row)
|
||||
|
||||
small_text = QLabel("You can toggle this anytime in the \"Options\" Menu, under \"Create/Edit\"")
|
||||
small_text.setWordWrap(True)
|
||||
small_text.setStyleSheet("color: #999999; font-size: 12px;")
|
||||
small_text.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||
v.addWidget(small_text)
|
||||
|
||||
def finalize(self):
|
||||
self.update_status.mark_fast_mode_prompt_shown()
|
||||
self.page_stack.setCurrentIndex(self.page_stack.indexOf(self.page_stack.findChild(MenuPage)))
|
||||
|
||||
def choose_yes(self):
|
||||
self.update_status.set_fast_mode_enabled(True)
|
||||
self.finalize()
|
||||
|
||||
def choose_no(self):
|
||||
self.update_status.set_fast_mode_enabled(False)
|
||||
self.finalize()
|
||||
|
||||
def initialize_default_selections(self):
|
||||
if not self.selected_values['location']:
|
||||
locations = self.connection_manager.get_location_list()
|
||||
|
|
Loading…
Reference in a new issue