hydraveil-gui/gui/v2/ui/pages/editor_page.py

849 lines
35 KiB
Python
Executable file

import os
from PyQt6.QtWidgets import (
QLabel, QPushButton, QLineEdit, QTextEdit, QFrame, QDialog,
QVBoxLayout, QHBoxLayout, QMessageBox, QGraphicsDropShadowEffect
)
from PyQt6.QtGui import QPixmap, QIcon, QPainter, QColor, QTransform
from PyQt6.QtCore import Qt, QSize, QTimer, QPointF
from PyQt6 import QtCore, QtGui
from core.controllers.ProfileController import ProfileController
from core.controllers.LocationController import LocationController
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.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):
def __init__(self, page_stack, main_window):
super().__init__("Editor", page_stack, main_window)
self.page_stack = page_stack
self.update_status = main_window
self.connection_manager = main_window.connection_manager
self.labels = []
self.buttons = []
self.title.setGeometry(570, 40, 185, 40)
self.title.setText("Edit Profile")
self.button_apply.setVisible(True)
self.button_apply.clicked.connect(self.go_selected)
self.button_back.setVisible(True)
try:
self.button_back.clicked.disconnect()
except TypeError:
pass
self.button_back.clicked.connect(self.go_back)
self.name_handle = QLabel(self)
self.name_handle.setGeometry(110, 70, 400, 30)
self.name_handle.setStyleSheet('color: #cacbcb;')
self.name_handle.setText("Profile Name:")
self.name_hint = QLabel(self)
self.name_hint.setGeometry(265, 100, 190, 20)
self.name_hint.setStyleSheet(
'color: #888888; font-size: 10px; font-style: italic;')
self.name_hint.setText("Click here to edit profile name")
self.name_hint.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.name = QLineEdit(self)
self.name.setPlaceholderText("Enter name")
self.name.setGeometry(265, 70, 190, 30)
self.name.setStyleSheet(
"color: cyan; border: 1px solid #666666; border-radius: 3px; background-color: rgba(0, 0, 0, 0.3);")
self.name.setCursor(QtCore.Qt.CursorShape.IBeamCursor)
self.name.focusInEvent = lambda event: self.name_hint.hide()
self.name.focusOutEvent = lambda event: self.name_hint.show(
) if not self.name.text() else self.name_hint.hide()
self.name.textChanged.connect(
lambda text: self.name_hint.hide() if text else self.name_hint.show())
self.temp_changes = {}
self.original_values = {}
self.res_hint_shown = False
self.display.setGeometry(QtCore.QRect(0, 60, 540, 405))
self.display.hide()
self.garaje = QLabel(self)
self.garaje.setGeometry(QtCore.QRect(0, 70, 540, 460))
self.brow_disp = QLabel(self)
self.brow_disp.setGeometry(QtCore.QRect(0, 50, 540, 460))
self.brow_disp.setPixmap(
QPixmap(os.path.join(self.btn_path, "browser only.png")))
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:
return ', '.join(
[f"Profile_{profile['profile_number']}" for profile in menu_page.selected_profiles])
profile_id = getattr(self.update_status, 'current_profile_id', None)
if profile_id is not None:
return f"Profile_{int(profile_id)}"
return ''
def update_name_value(self):
original_name = self.data_profile.get('name', '')
new_name = self.name.text()
if original_name != new_name:
self.update_temp_value('name', new_name)
else:
pass
def go_back(self):
selected_profiles_str = self._selected_profiles_str()
if self.has_unsaved_changes(selected_profiles_str):
self.show_unsaved_changes_popup()
else:
self.custom_window.navigator.navigate("menu")
def find_menu_page(self):
return self.custom_window.navigator.get_cached("menu")
def find_resume_page(self):
return self.custom_window.navigator.get_cached("resume")
def find_protocol_page(self):
return self.custom_window.navigator.get_cached("protocol")
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:
label.deleteLater()
self.labels = []
for button in self.buttons:
button.deleteLater()
self.buttons = []
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)
self.data_profile = self.profiles_data[selected_profiles_str].copy(
)
profile_id = int(selected_profiles_str.split('_')[1])
self.data_profile['id'] = profile_id
if selected_profiles_str in self.temp_changes:
for key, value in self.temp_changes[selected_profiles_str].items():
self.data_profile[key] = value
self.name.textChanged.connect(self.update_name_value)
self.verificate(self.data_profile, selected_profiles_str)
def verificate(self, data_profile, selected_profile_str):
protocol = data_profile.get("protocol", "")
try:
if protocol == "wireguard":
self.process_and_show_labels(data_profile, {
"protocol": ['wireguard', 'residential', 'hidetor'],
"connection": ['browser-only', 'system-wide'],
"location": self.connection_manager.get_location_list(),
"browser": self.connection_manager.get_browser_list(),
"dimentions": self.connection_manager.get_available_resolutions(data_profile.get('id', ''))
}, selected_profile_str)
elif protocol == "residential" or protocol == "hidetor":
self.process_and_show_labels(data_profile, {
"protocol": ['residential', 'wireguard', 'hidetor'],
"connection": ['tor', 'just proxy'],
"location": self.connection_manager.get_location_list(),
"browser": self.connection_manager.get_browser_list(),
"dimentions": self.connection_manager.get_available_resolutions(data_profile.get('id', ''))
}, selected_profile_str)
elif protocol == "open":
self.process_and_show_labels(data_profile, {
"protocol": ['open']
}, selected_profile_str)
except Exception as e:
print(f'An error occurred in verificate: {e}')
def process_and_show_labels(self, data_profile, parameters, selected_profile_str):
protocol = data_profile.get('protocol', "")
connection = data_profile.get('connection', "")
location = data_profile.get('location', "")
country_garaje = location
name = data_profile.get('name', "")
self.name.setText(name)
if protocol == "hidetor":
if connection == "just proxy":
self.display.setPixmap(QPixmap(os.path.join(
self.btn_path, f"icon_{location}.png")))
else:
self.display.setPixmap(QPixmap(os.path.join(
self.btn_path, f"hdtor_{location}.png")))
self.display.show()
self.display.setGeometry(0, 100, 400, 394)
self.display.setScaledContents(True)
self.garaje.hide()
self.brow_disp.hide()
if protocol == "wireguard":
self.display.setGeometry(0, 60, 540, 405)
self.display.show()
self.display.setPixmap(QPixmap(os.path.join(
self.btn_path, f"wireguard_{location}.png")))
self.garaje.hide()
if connection == "browser-only":
is_supported = data_profile.get('browser_supported', False)
image_name = "browser only.png" if is_supported else "unsupported_browser_only.png"
self.brow_disp.setPixmap(
QPixmap(os.path.join(self.btn_path, image_name)))
self.brow_disp.show()
else:
self.brow_disp.hide()
if protocol == "residential":
self.display.setGeometry(0, 60, 540, 405)
self.brow_disp.show()
self.garaje.show()
self.display.hide()
if country_garaje:
country_garaje = 'brazil'
self.garaje.setPixmap(QPixmap(os.path.join(
self.btn_path, f"{country_garaje} garaje.png")))
profile_id = data_profile.get('id')
profile_obj = ProfileController.get(profile_id)
location_info = None
if location:
try:
if '_' in location:
country_code, location_code = location.split('_', 1)
location_info = LocationController.get(
country_code, location_code)
except Exception:
location_info = None
operator_name = ""
l_name = ""
o_name = ""
n_key = ""
if location_info:
if hasattr(location_info, 'operator') and location_info.operator:
operator_name = location_info.operator.name
o_name = location_info.operator.name
n_key = location_info.operator.nostr_public_key
l_name = f"{location_info.country_name}, {location_info.name}" if hasattr(
location_info, 'country_name') else ""
if operator_name != 'Simplified Privacy' and operator_name != "" and protocol != 'hidetor':
text_color = "white"
if profile_obj and profile_obj.is_session_profile():
text_color = "black"
l_img = QLabel(self)
l_img.setGeometry(20, 125, 150, 150)
pixmap_loc = QPixmap(os.path.join(
self.btn_path, f"icon_{location}.png"))
l_img.setPixmap(pixmap_loc)
l_img.setScaledContents(True)
l_img.show()
self.labels.append(l_img)
info_txt = QTextEdit(self)
info_txt.setGeometry(180, 120, 300, 250)
info_txt.setReadOnly(True)
info_txt.setFrameStyle(QFrame.Shape.NoFrame)
info_txt.setStyleSheet(
f"background: transparent; border: none; color: {text_color}; font-size: 19px;")
info_txt.setVerticalScrollBarPolicy(
Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
info_txt.setHorizontalScrollBarPolicy(
Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
info_txt.setWordWrapMode(
QtGui.QTextOption.WrapMode.WrapAtWordBoundaryOrAnywhere)
info_txt.setText(
f"Location: {l_name}\n\nOperator: {o_name}")
info_txt.show()
self.labels.append(info_txt)
nostr_txt = QTextEdit(self)
nostr_txt.setGeometry(20, 300, 450, 170)
nostr_txt.setReadOnly(True)
nostr_txt.setFrameStyle(QFrame.Shape.NoFrame)
nostr_txt.setStyleSheet(
f"background: transparent; border: none; color: {text_color}; font-size: 21px;")
nostr_txt.setVerticalScrollBarPolicy(
Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
nostr_txt.setHorizontalScrollBarPolicy(
Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
nostr_txt.setWordWrapMode(
QtGui.QTextOption.WrapMode.WrapAnywhere)
nostr_txt.setText(f"Nostr: {n_key}")
nostr_txt.show()
self.labels.append(nostr_txt)
for i, key in enumerate(parameters.keys()):
if key == 'browser':
browser_value = f"{data_profile.get(key, '')}"
split_value = browser_value.split(':', 1)
browser_type = split_value[0]
browser_version = split_value[1] if len(
split_value) > 1 else ''
browser_value = f"{browser_type} {browser_version}"
if browser_version == '':
browser_version = data_profile.get('browser_version', '')
browser_value = f"{browser_type} {browser_version}"
if connection == 'system-wide' or not browser_value.strip():
base_image = QPixmap()
else:
base_image = BrowserPage.create_browser_button_image(
browser_value, self.btn_path)
if base_image.isNull():
fallback_path = os.path.join(
self.btn_path, "default_browser_button.png")
base_image = BrowserPage.create_browser_button_image(
browser_value, fallback_path, True)
elif key == 'location':
current_value = f"{data_profile.get(key, '')}"
image_path = os.path.join(
self.btn_path, f"button_{current_value}.png")
base_image = QPixmap(image_path)
locations = self.connection_manager.get_location_info(
current_value)
provider = locations.operator.name if locations and hasattr(
locations, 'operator') else None
fallback_path = os.path.join(
self.btn_path, "default_location_button.png")
if base_image.isNull():
if locations and hasattr(locations, 'country_name'):
location_name = locations.country_name
base_image = LocationPage.create_location_button_image(
location_name, fallback_path, provider)
else:
base_image = LocationPage.create_location_button_image(
current_value, fallback_path, provider)
else:
if locations and hasattr(locations, 'country_name'):
base_image = LocationPage.create_location_button_image(
f'{locations.country_code}_{locations.code}', fallback_path, provider, image_path)
else:
base_image = LocationPage.create_location_button_image(
current_value, fallback_path, provider, image_path)
elif key == 'dimentions':
current_value = f"{data_profile.get(key, '')}"
if current_value != 'None':
base_image = ScreenPage.create_resolution_button_image(
self, current_value)
else:
image_path = os.path.join(
self.btn_path, f"{data_profile.get(key, '')}_button.png")
current_value = data_profile.get(key, '')
base_image = QPixmap(image_path)
if key == 'dimentions':
label = QPushButton(self)
label.setGeometry(565, 90 + i * 80, 185, 75)
label.setFlat(True)
label.setStyleSheet("border: none; background: transparent;")
original_icon = QIcon(base_image)
label.setIconSize(QSize(185, 75))
label.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)
label.clicked.connect(self.show_custom_res_dialog)
template_path = os.path.join(
self.btn_path, "resolution_template_button.png")
template_pixmap = QPixmap(template_path).scaled(
187, 75) if os.path.exists(template_path) else None
if not getattr(self, 'res_hint_shown', False) and connection != 'system-wide':
self.res_hint_shown = True
if template_pixmap:
label.setIcon(QIcon(template_pixmap))
else:
label.setIcon(QIcon())
hint_label = QLabel("Click here to customize", label)
hint_label.setGeometry(15, 0, 155, 75)
hint_label.setWordWrap(True)
hint_label.setAlignment(
QtCore.Qt.AlignmentFlag.AlignCenter)
hint_label.setStyleSheet(
"color: #00ffff; font-weight: bold; font-size: 16px; background: transparent;")
hint_label.setCursor(
QtCore.Qt.CursorShape.PointingHandCursor)
hint_label.setAttribute(
QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents)
shadow = QGraphicsDropShadowEffect(hint_label)
shadow.setBlurRadius(20)
shadow.setColor(QColor(0, 255, 255))
shadow.setOffset(0, 0)
hint_label.setGraphicsEffect(shadow)
def restore():
try:
if hint_label and not hint_label.isHidden():
hint_label.hide()
label.setIcon(original_icon)
except:
pass
QTimer.singleShot(3500, restore)
else:
label.setIcon(original_icon)
else:
label = QLabel(key, self)
label.setGeometry(565, 90 + i * 80, 185, 75)
label.setPixmap(base_image)
label.setScaledContents(True)
label.show()
self.labels.append(label)
try:
if key == 'browser':
value_index = [item.replace(
':', ' ') for item in parameters[key]].index(browser_value)
else:
value_index = parameters[key].index(current_value)
except ValueError:
value_index = 0
prev_button = QPushButton(self)
prev_button.setGeometry(535, 90 + i * 80, 30, 75)
prev_button.clicked.connect(
lambda _, k=key, idx=value_index: self.show_previous_value(k, idx, parameters))
prev_button.show()
icon_path = os.path.join(self.btn_path, f"UP_button.png")
icon = QPixmap(icon_path)
transform = QTransform().rotate(180)
rotated_icon = icon.transformed(transform)
prev_button.setIcon(QIcon(rotated_icon))
prev_button.setIconSize(prev_button.size())
if (key == 'location' or key == 'browser') and not self.connection_manager.is_synced():
w = prev_button.width()
h = prev_button.height()
outline_pix = QPixmap(w, h)
outline_pix.fill(Qt.GlobalColor.transparent)
painter = QPainter(outline_pix)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
pen = QtGui.QPen(QColor(0, 255, 0))
pen.setWidth(3)
painter.setPen(pen)
painter.setBrush(Qt.BrushStyle.NoBrush)
left_points = [
QPointF(w*0.65, h*0.15), QPointF(w*0.25, h*0.50), QPointF(w*0.65, h*0.85)]
painter.drawPolygon(QtGui.QPolygonF(left_points))
painter.end()
prev_button.setIcon(QIcon(outline_pix))
prev_button.setIconSize(prev_button.size())
if (key == 'location' or key == 'browser') and not self.connection_manager.is_synced():
prev_button.setStyleSheet("""
QPushButton {
background-color: transparent;
border: none;
}
QPushButton:hover {
background-color: rgba(0, 255, 0, 0.1);
border-radius: 3px;
}
QPushButton:pressed {
background-color: rgba(0, 255, 0, 0.2);
border-radius: 3px;
}
""")
self.buttons.append(prev_button)
next_button = QPushButton(self)
next_button.setGeometry(750, 90 + i * 80, 30, 75)
next_button.clicked.connect(
lambda _, k=key, idx=value_index: self.show_next_value(k, idx, parameters))
next_button.show()
self.buttons.append(next_button)
next_button.setIcon(
QIcon(os.path.join(self.btn_path, f"UP_button.png")))
next_button.setIconSize(next_button.size())
if (key == 'location' or key == 'browser') and not self.connection_manager.is_synced():
w = next_button.width()
h = next_button.height()
outline_pix_r = QPixmap(w, h)
outline_pix_r.fill(Qt.GlobalColor.transparent)
painter_r = QPainter(outline_pix_r)
painter_r.setRenderHint(QPainter.RenderHint.Antialiasing)
pen_r = QtGui.QPen(QColor(0, 255, 0))
pen_r.setWidth(3)
painter_r.setPen(pen_r)
painter_r.setBrush(Qt.BrushStyle.NoBrush)
right_points = [
QPointF(w*0.35, h*0.15), QPointF(w*0.75, h*0.50), QPointF(w*0.35, h*0.85)]
painter_r.drawPolygon(QtGui.QPolygonF(right_points))
painter_r.end()
next_button.setIcon(QIcon(outline_pix_r))
next_button.setIconSize(next_button.size())
if (key == 'location' or key == 'browser') and not self.connection_manager.is_synced():
next_button.setStyleSheet("""
QPushButton {
background-color: transparent;
border: none;
}
QPushButton:hover {
background-color: rgba(0, 255, 0, 0.1);
border-radius: 3px;
}
QPushButton:pressed {
background-color: rgba(0, 255, 0, 0.2);
border-radius: 3px;
}
""")
prev_button.setVisible(True)
next_button.setVisible(True)
if key == 'protocol' or (protocol == 'wireguard' and key == 'connection'):
prev_button.setDisabled(True)
next_button.setDisabled(True)
if connection == 'system-wide' and (key == 'browser' or key == 'dimentions'):
prev_button.setVisible(False)
next_button.setVisible(False)
def on_sync_complete_for_edit_profile(self, available_locations, available_browsers, status, is_tor, locations, all_browsers):
if status:
self.update_status.update_status('Sync complete.')
self.extraccion()
else:
self.update_status.update_status(
'Sync failed. Please try again later.')
def show_previous_value(self, key: str, index: int, parameters: dict) -> None:
if key == 'browser' or key == 'location':
if not self.connection_manager.is_synced():
self.update_status.update_status('Syncing in progress..')
self.update_status.sync()
self.update_status.worker_thread.sync_output.connect(
self.on_sync_complete_for_edit_profile)
return
previous_index = (index - 1) % len(parameters[key])
previous_value = parameters[key][previous_index]
self.update_temp_value(key, previous_value)
def show_next_value(self, key: str, index: int, parameters: dict) -> None:
if key == 'browser' or key == 'location':
if not self.connection_manager.is_synced():
self.update_status.update_status('Syncing in progress..')
self.update_status.sync()
self.update_status.worker_thread.sync_output.connect(
self.on_sync_complete_for_edit_profile)
return
next_index = (index + 1) % len(parameters[key])
next_value = parameters[key][next_index]
self.update_temp_value(key, next_value)
def update_temp_value(self, key: str, new_value: str) -> None:
selected_profiles_str = self._selected_profiles_str()
if selected_profiles_str not in self.temp_changes:
self.temp_changes[selected_profiles_str] = {}
self.original_values[selected_profiles_str] = self.data_profile.copy(
)
self.temp_changes[selected_profiles_str][key] = new_value
self.extraccion()
def show_custom_res_dialog(self):
dialog = QDialog(self)
dialog.setWindowTitle("Custom Resolution")
dialog.setFixedSize(300, 150)
dialog.setModal(True)
dialog.setStyleSheet("""
QDialog {
background-color: #2c3e50;
border: 2px solid #00ffff;
border-radius: 10px;
}
QLabel {
color: white;
font-size: 12px;
}
QLineEdit {
background-color: #34495e;
color: white;
border: 1px solid #00ffff;
border-radius: 5px;
padding: 5px;
font-size: 12px;
}
QPushButton {
background-color: #2c3e50;
color: white;
border: 2px solid #00ffff;
border-radius: 5px;
padding: 8px;
font-size: 12px;
}
QPushButton:hover {
background-color: #34495e;
}
""")
layout = QVBoxLayout()
input_layout = QHBoxLayout()
width_label = QLabel("Width:")
width_input = QLineEdit()
width_input.setPlaceholderText("1920")
height_label = QLabel("Height:")
height_input = QLineEdit()
height_input.setPlaceholderText("1080")
input_layout.addWidget(width_label)
input_layout.addWidget(width_input)
input_layout.addWidget(height_label)
input_layout.addWidget(height_input)
button_layout = QHBoxLayout()
ok_button = QPushButton("OK")
cancel_button = QPushButton("Cancel")
button_layout.addWidget(cancel_button)
button_layout.addWidget(ok_button)
layout.addLayout(input_layout)
layout.addLayout(button_layout)
dialog.setLayout(layout)
def validate_and_accept():
try:
width = int(width_input.text())
height = int(height_input.text())
if width <= 0 or height <= 0:
return
host_w = self.custom_window.host_screen_width
host_h = self.custom_window.host_screen_height
adjusted = False
if width > host_w:
width = host_w - 50
adjusted = True
if height > host_h:
height = host_h - 50
adjusted = True
if adjusted:
QMessageBox.information(
dialog, "Notice", "Adjusted to fit host size")
self.update_temp_value('dimentions', f"{width}x{height}")
dialog.accept()
except ValueError:
pass
ok_button.clicked.connect(validate_and_accept)
cancel_button.clicked.connect(dialog.reject)
width_input.returnPressed.connect(validate_and_accept)
height_input.returnPressed.connect(validate_and_accept)
dialog.exec()
def has_unsaved_changes(self, profile_str: str) -> bool:
return profile_str in self.temp_changes and bool(self.temp_changes[profile_str])
def show_apply_changes_popup(self, selected_profiles_str: str) -> bool:
if selected_profiles_str not in self.temp_changes:
return False
temp_changes = self.temp_changes[selected_profiles_str]
current_data = self.original_values[selected_profiles_str]
current_browser = f"{current_data.get('browser', '')} {current_data.get('browser_version', '')}"
if 'location' in temp_changes and temp_changes['location'] != current_data.get('location'):
message = "A new location would require a new subscription code.\nDo you want to proceed with erasing the old one?"
elif 'browser' in temp_changes and temp_changes['browser'] != current_browser:
message = "Changing the browser would delete all data associated with it. Proceed?"
else:
return False
self.popup = ConfirmationPopup(
self,
message=message,
action_button_text="Continue",
cancel_button_text="Cancel"
)
self.popup.setWindowModality(Qt.WindowModality.ApplicationModal)
self.popup.finished.connect(
lambda result: self.handle_apply_changes_response(result))
self.popup.show()
return True
def show_unsaved_changes_popup(self) -> None:
self.popup = ConfirmationPopup(
self,
message="You have unsaved changes. Do you want to continue?",
action_button_text="Continue",
cancel_button_text="Cancel"
)
self.popup.setWindowModality(Qt.WindowModality.ApplicationModal)
self.popup.finished.connect(
lambda result: self.handle_unsaved_changes_response(result))
self.popup.show()
def _refresh_menu_and_navigate(self):
menu_page = self.find_menu_page()
if menu_page is not None and hasattr(menu_page, 'refresh_menu_buttons'):
menu_page.refresh_menu_buttons()
self.custom_window.navigator.navigate("menu")
def handle_apply_changes_response(self, result: bool) -> None:
if result:
self.commit_changes()
self._refresh_menu_and_navigate()
def handle_unsaved_changes_response(self, result: bool) -> None:
if result:
self.temp_changes.clear()
self._refresh_menu_and_navigate()
def go_selected(self) -> None:
selected_profiles_str = self._selected_profiles_str()
if selected_profiles_str in self.temp_changes and self.temp_changes[selected_profiles_str]:
needs_confirmation = self.show_apply_changes_popup(
selected_profiles_str)
if not needs_confirmation:
self.commit_changes()
self._refresh_menu_and_navigate()
else:
self.custom_window.navigator.navigate("menu")
def commit_changes(self) -> None:
selected_profiles_str = self._selected_profiles_str()
if selected_profiles_str in self.temp_changes:
for key, new_value in self.temp_changes[selected_profiles_str].items():
self.update_core_profiles(key, new_value)
self.temp_changes.pop(selected_profiles_str, None)
self.original_values.pop(selected_profiles_str, None)
def update_core_profiles(self, key, new_value):
profile = ProfileController.get(
int(self.update_status.current_profile_id))
self.update_res = False
if key == 'dimentions':
profile.resolution = new_value
self.update_res = True
elif key == 'name':
profile.name = new_value
elif key == 'connection':
if new_value == 'tor':
profile.connection.code = new_value
profile.connection.masked = True
elif new_value == 'just proxy':
profile.connection.code = 'system'
profile.connection.masked = True
else:
self.update_status.update_status(
'System wide profiles not supported atm')
elif key == 'browser':
browser_type, browser_version = new_value.split(':', 1)
profile.application_version.application_code = browser_type
profile.application_version.version_number = browser_version
elif key == 'protocol':
if self.data_profile.get('connection') == 'system-wide':
self.edit_to_session()
else:
profile.connection.code = 'wireguard' if new_value == 'wireguard' else 'tor'
profile.connection.masked = False if new_value == 'wireguard' else True
else:
location = self.connection_manager.get_location_info(new_value)
if location:
profile.location.code = location.code
profile.location.country_code = location.country_code
profile.location.time_zone = location.time_zone
profile.subscription = None
ProfileController.update(profile)
def edit_to_session(self):
id = int(self.update_status.current_profile_id)
profile = self.data_profile
default_app = 'firefox:123.0'
default_resolution = '1024x760'
location_code = self.connection_manager.get_location_info(
profile.get('location'))
connection_type = 'tor'
profile_data = {
'id': int(id),
'name': profile.get('name'),
'country_code': location_code.country_code,
'code': location_code.code,
'application': default_app,
'connection_type': connection_type,
'resolution': default_resolution,
}
resume_page = self.find_resume_page()
if resume_page:
resume_page.handle_core_action_create_profile(
'CREATE_SESSION_PROFILE', profile_data, 'session')