mirror of
https://github.com/Yuvi9587/Kemono-Downloader.git
synced 2025-12-29 16:14:44 +00:00
323 lines
15 KiB
Python
323 lines
15 KiB
Python
# --- Standard Library Imports ---
|
|
import os
|
|
import json
|
|
|
|
# --- PyQt5 Imports ---
|
|
from PyQt5.QtCore import Qt, QStandardPaths
|
|
from PyQt5.QtWidgets import (
|
|
QApplication, QDialog, QHBoxLayout, QLabel, QPushButton, QVBoxLayout,
|
|
QGroupBox, QComboBox, QMessageBox, QGridLayout, QCheckBox
|
|
)
|
|
|
|
# --- Local Application Imports ---
|
|
from ...i18n.translator import get_translation
|
|
from ...utils.resolution import get_dark_theme
|
|
from ..main_window import get_app_icon_object
|
|
from ...config.constants import (
|
|
THEME_KEY, LANGUAGE_KEY, DOWNLOAD_LOCATION_KEY,
|
|
RESOLUTION_KEY, UI_SCALE_KEY, SAVE_CREATOR_JSON_KEY,
|
|
COOKIE_TEXT_KEY, USE_COOKIE_KEY
|
|
)
|
|
|
|
|
|
class FutureSettingsDialog(QDialog):
|
|
"""
|
|
A dialog for managing application-wide settings like theme, language,
|
|
and display options, with an organized layout.
|
|
"""
|
|
def __init__(self, parent_app_ref, parent=None):
|
|
super().__init__(parent)
|
|
self.parent_app = parent_app_ref
|
|
self.setModal(True)
|
|
|
|
app_icon = get_app_icon_object()
|
|
if app_icon and not app_icon.isNull():
|
|
self.setWindowIcon(app_icon)
|
|
|
|
screen_height = QApplication.primaryScreen().availableGeometry().height() if QApplication.primaryScreen() else 800
|
|
scale_factor = screen_height / 800.0
|
|
base_min_w, base_min_h = 420, 360 # Adjusted height for new layout
|
|
scaled_min_w = int(base_min_w * scale_factor)
|
|
scaled_min_h = int(base_min_h * scale_factor)
|
|
self.setMinimumSize(scaled_min_w, scaled_min_h)
|
|
|
|
self._init_ui()
|
|
self._retranslate_ui()
|
|
self._apply_theme()
|
|
|
|
def _init_ui(self):
|
|
"""Initializes all UI components and layouts for the dialog."""
|
|
main_layout = QVBoxLayout(self)
|
|
|
|
# --- Group 1: Interface Settings ---
|
|
self.interface_group_box = QGroupBox()
|
|
interface_layout = QGridLayout(self.interface_group_box)
|
|
|
|
# Theme
|
|
self.theme_label = QLabel()
|
|
self.theme_toggle_button = QPushButton()
|
|
self.theme_toggle_button.clicked.connect(self._toggle_theme)
|
|
interface_layout.addWidget(self.theme_label, 0, 0)
|
|
interface_layout.addWidget(self.theme_toggle_button, 0, 1)
|
|
|
|
# UI Scale
|
|
self.ui_scale_label = QLabel()
|
|
self.ui_scale_combo_box = QComboBox()
|
|
self.ui_scale_combo_box.currentIndexChanged.connect(self._display_setting_changed)
|
|
interface_layout.addWidget(self.ui_scale_label, 1, 0)
|
|
interface_layout.addWidget(self.ui_scale_combo_box, 1, 1)
|
|
|
|
# Language
|
|
self.language_label = QLabel()
|
|
self.language_combo_box = QComboBox()
|
|
self.language_combo_box.currentIndexChanged.connect(self._language_selection_changed)
|
|
interface_layout.addWidget(self.language_label, 2, 0)
|
|
interface_layout.addWidget(self.language_combo_box, 2, 1)
|
|
|
|
main_layout.addWidget(self.interface_group_box)
|
|
|
|
# --- Group 2: Download & Window Settings ---
|
|
self.download_window_group_box = QGroupBox()
|
|
download_window_layout = QGridLayout(self.download_window_group_box)
|
|
|
|
# Window Size (Resolution)
|
|
self.window_size_label = QLabel()
|
|
self.resolution_combo_box = QComboBox()
|
|
self.resolution_combo_box.currentIndexChanged.connect(self._display_setting_changed)
|
|
download_window_layout.addWidget(self.window_size_label, 0, 0)
|
|
download_window_layout.addWidget(self.resolution_combo_box, 0, 1)
|
|
|
|
# Default Path
|
|
self.default_path_label = QLabel()
|
|
self.save_path_button = QPushButton()
|
|
# --- START: MODIFIED LOGIC ---
|
|
self.save_path_button.clicked.connect(self._save_cookie_and_path)
|
|
# --- END: MODIFIED LOGIC ---
|
|
download_window_layout.addWidget(self.default_path_label, 1, 0)
|
|
download_window_layout.addWidget(self.save_path_button, 1, 1)
|
|
|
|
# Save Creator.json Checkbox
|
|
self.save_creator_json_checkbox = QCheckBox()
|
|
self.save_creator_json_checkbox.stateChanged.connect(self._creator_json_setting_changed)
|
|
download_window_layout.addWidget(self.save_creator_json_checkbox, 2, 0, 1, 2)
|
|
|
|
main_layout.addWidget(self.download_window_group_box)
|
|
|
|
main_layout.addStretch(1)
|
|
|
|
# --- OK Button ---
|
|
self.ok_button = QPushButton()
|
|
self.ok_button.clicked.connect(self.accept)
|
|
main_layout.addWidget(self.ok_button, 0, Qt.AlignRight | Qt.AlignBottom)
|
|
|
|
def _load_checkbox_states(self):
|
|
"""Loads the initial state for all checkboxes from settings."""
|
|
self.save_creator_json_checkbox.blockSignals(True)
|
|
# Default to True so the feature is on by default for users
|
|
should_save = self.parent_app.settings.value(SAVE_CREATOR_JSON_KEY, True, type=bool)
|
|
self.save_creator_json_checkbox.setChecked(should_save)
|
|
self.save_creator_json_checkbox.blockSignals(False)
|
|
|
|
def _creator_json_setting_changed(self, state):
|
|
"""Saves the state of the 'Save Creator.json' checkbox."""
|
|
is_checked = state == Qt.Checked
|
|
self.parent_app.settings.setValue(SAVE_CREATOR_JSON_KEY, is_checked)
|
|
self.parent_app.settings.sync()
|
|
|
|
def _tr(self, key, default_text=""):
|
|
if callable(get_translation) and self.parent_app:
|
|
return get_translation(self.parent_app.current_selected_language, key, default_text)
|
|
return default_text
|
|
|
|
def _retranslate_ui(self):
|
|
self.setWindowTitle(self._tr("settings_dialog_title", "Settings"))
|
|
|
|
# Group Box Titles
|
|
self.interface_group_box.setTitle(self._tr("interface_group_title", "Interface Settings"))
|
|
self.download_window_group_box.setTitle(self._tr("download_window_group_title", "Download & Window Settings"))
|
|
|
|
# Interface Group Labels
|
|
self.theme_label.setText(self._tr("theme_label", "Theme:"))
|
|
self.ui_scale_label.setText(self._tr("ui_scale_label", "UI Scale:"))
|
|
self.language_label.setText(self._tr("language_label", "Language:"))
|
|
|
|
# Download & Window Group Labels
|
|
self.window_size_label.setText(self._tr("window_size_label", "Window Size:"))
|
|
self.default_path_label.setText(self._tr("default_path_label", "Default Path:"))
|
|
self.save_creator_json_checkbox.setText(self._tr("save_creator_json_label", "Save Creator.json file"))
|
|
|
|
# --- START: MODIFIED LOGIC ---
|
|
# Buttons and Controls
|
|
self._update_theme_toggle_button_text()
|
|
self.save_path_button.setText(self._tr("settings_save_cookie_path_button", "Save Cookie + Download Path"))
|
|
self.save_path_button.setToolTip(self._tr("settings_save_cookie_path_tooltip", "Save the current 'Download Location' and Cookie settings for future sessions."))
|
|
self.ok_button.setText(self._tr("ok_button", "OK"))
|
|
# --- END: MODIFIED LOGIC ---
|
|
|
|
# Populate dropdowns
|
|
self._populate_display_combo_boxes()
|
|
self._populate_language_combo_box()
|
|
self._load_checkbox_states()
|
|
|
|
def _apply_theme(self):
|
|
if self.parent_app and self.parent_app.current_theme == "dark":
|
|
scale = getattr(self.parent_app, 'scale_factor', 1)
|
|
self.setStyleSheet(get_dark_theme(scale))
|
|
else:
|
|
self.setStyleSheet("")
|
|
|
|
def _update_theme_toggle_button_text(self):
|
|
if self.parent_app.current_theme == "dark":
|
|
self.theme_toggle_button.setText(self._tr("theme_toggle_light", "Switch to Light Mode"))
|
|
else:
|
|
self.theme_toggle_button.setText(self._tr("theme_toggle_dark", "Switch to Dark Mode"))
|
|
|
|
def _toggle_theme(self):
|
|
new_theme = "light" if self.parent_app.current_theme == "dark" else "dark"
|
|
self.parent_app.settings.setValue(THEME_KEY, new_theme)
|
|
self.parent_app.settings.sync()
|
|
self.parent_app.current_theme = new_theme
|
|
self._apply_theme()
|
|
if hasattr(self.parent_app, '_apply_theme_and_restart_prompt'):
|
|
self.parent_app._apply_theme_and_restart_prompt()
|
|
|
|
def _populate_display_combo_boxes(self):
|
|
self.resolution_combo_box.blockSignals(True)
|
|
self.resolution_combo_box.clear()
|
|
resolutions = [
|
|
("Auto", self._tr("auto_resolution", "Auto (System Default)")),
|
|
("1280x720", "1280 x 720"),
|
|
("1600x900", "1600 x 900"),
|
|
("1920x1080", "1920 x 1080 (Full HD)"),
|
|
("2560x1440", "2560 x 1440 (2K)"),
|
|
("3840x2160", "3840 x 2160 (4K)")
|
|
]
|
|
current_res = self.parent_app.settings.value(RESOLUTION_KEY, "Auto")
|
|
for res_key, res_name in resolutions:
|
|
self.resolution_combo_box.addItem(res_name, res_key)
|
|
if current_res == res_key:
|
|
self.resolution_combo_box.setCurrentIndex(self.resolution_combo_box.count() - 1)
|
|
self.resolution_combo_box.blockSignals(False)
|
|
|
|
self.ui_scale_combo_box.blockSignals(True)
|
|
self.ui_scale_combo_box.clear()
|
|
scales = [
|
|
(0.5, "50%"),
|
|
(0.7, "70%"),
|
|
(0.9, "90%"),
|
|
(1.0, "100% (Default)"),
|
|
(1.25, "125%"),
|
|
(1.50, "150%"),
|
|
(1.75, "175%"),
|
|
(2.0, "200%")
|
|
]
|
|
|
|
current_scale = float(self.parent_app.settings.value(UI_SCALE_KEY, 1.0))
|
|
for scale_val, scale_name in scales:
|
|
self.ui_scale_combo_box.addItem(scale_name, scale_val)
|
|
if abs(current_scale - scale_val) < 0.01:
|
|
self.ui_scale_combo_box.setCurrentIndex(self.ui_scale_combo_box.count() - 1)
|
|
self.ui_scale_combo_box.blockSignals(False)
|
|
|
|
def _display_setting_changed(self):
|
|
selected_res = self.resolution_combo_box.currentData()
|
|
selected_scale = self.ui_scale_combo_box.currentData()
|
|
|
|
self.parent_app.settings.setValue(RESOLUTION_KEY, selected_res)
|
|
self.parent_app.settings.setValue(UI_SCALE_KEY, selected_scale)
|
|
self.parent_app.settings.sync()
|
|
|
|
msg_box = QMessageBox(self)
|
|
msg_box.setIcon(QMessageBox.Information)
|
|
msg_box.setWindowTitle(self._tr("display_change_title", "Display Settings Changed"))
|
|
msg_box.setText(self._tr("language_change_message", "A restart is required for these changes to take effect."))
|
|
msg_box.setInformativeText(self._tr("language_change_informative", "Would you like to restart now?"))
|
|
restart_button = msg_box.addButton(self._tr("restart_now_button", "Restart Now"), QMessageBox.ApplyRole)
|
|
ok_button = msg_box.addButton(self._tr("ok_button", "OK"), QMessageBox.AcceptRole)
|
|
msg_box.setDefaultButton(ok_button)
|
|
msg_box.exec_()
|
|
|
|
if msg_box.clickedButton() == restart_button:
|
|
self.parent_app._request_restart_application()
|
|
|
|
def _populate_language_combo_box(self):
|
|
self.language_combo_box.blockSignals(True)
|
|
self.language_combo_box.clear()
|
|
languages = [
|
|
("en", "English"), ("ja", "日本語 (Japanese)"), ("fr", "Français (French)"),
|
|
("de", "Deutsch (German)"), ("es", "Español (Spanish)"), ("pt", "Português (Portuguese)"),
|
|
("ru", "Русский (Russian)"), ("zh_CN", "简体中文 (Simplified Chinese)"),
|
|
("zh_TW", "繁體中文 (Traditional Chinese)"), ("ko", "한국어 (Korean)")
|
|
]
|
|
current_lang = self.parent_app.current_selected_language
|
|
for lang_code, lang_name in languages:
|
|
self.language_combo_box.addItem(lang_name, lang_code)
|
|
if current_lang == lang_code:
|
|
self.language_combo_box.setCurrentIndex(self.language_combo_box.count() - 1)
|
|
self.language_combo_box.blockSignals(False)
|
|
|
|
def _language_selection_changed(self, index):
|
|
selected_lang_code = self.language_combo_box.itemData(index)
|
|
if selected_lang_code and selected_lang_code != self.parent_app.current_selected_language:
|
|
self.parent_app.settings.setValue(LANGUAGE_KEY, selected_lang_code)
|
|
self.parent_app.settings.sync()
|
|
self.parent_app.current_selected_language = selected_lang_code
|
|
|
|
self._retranslate_ui()
|
|
if hasattr(self.parent_app, '_retranslate_main_ui'):
|
|
self.parent_app._retranslate_main_ui()
|
|
|
|
msg_box = QMessageBox(self)
|
|
msg_box.setIcon(QMessageBox.Information)
|
|
msg_box.setWindowTitle(self._tr("language_change_title", "Language Changed"))
|
|
msg_box.setText(self._tr("language_change_message", "A restart is required..."))
|
|
msg_box.setInformativeText(self._tr("language_change_informative", "Would you like to restart now?"))
|
|
restart_button = msg_box.addButton(self._tr("restart_now_button", "Restart Now"), QMessageBox.ApplyRole)
|
|
ok_button = msg_box.addButton(self._tr("ok_button", "OK"), QMessageBox.AcceptRole)
|
|
msg_box.setDefaultButton(ok_button)
|
|
msg_box.exec_()
|
|
|
|
if msg_box.clickedButton() == restart_button:
|
|
self.parent_app._request_restart_application()
|
|
|
|
def _save_cookie_and_path(self):
|
|
"""Saves the current download path and/or cookie settings from the main window."""
|
|
path_saved = False
|
|
cookie_saved = False
|
|
|
|
# --- Save Download Path Logic ---
|
|
if hasattr(self.parent_app, 'dir_input') and self.parent_app.dir_input:
|
|
current_path = self.parent_app.dir_input.text().strip()
|
|
if current_path and os.path.isdir(current_path):
|
|
self.parent_app.settings.setValue(DOWNLOAD_LOCATION_KEY, current_path)
|
|
path_saved = True
|
|
|
|
# --- Save Cookie Logic ---
|
|
if hasattr(self.parent_app, 'use_cookie_checkbox'):
|
|
use_cookie = self.parent_app.use_cookie_checkbox.isChecked()
|
|
cookie_content = self.parent_app.cookie_text_input.text().strip()
|
|
|
|
if use_cookie and cookie_content:
|
|
self.parent_app.settings.setValue(USE_COOKIE_KEY, True)
|
|
self.parent_app.settings.setValue(COOKIE_TEXT_KEY, cookie_content)
|
|
cookie_saved = True
|
|
else: # Also save the 'off' state
|
|
self.parent_app.settings.setValue(USE_COOKIE_KEY, False)
|
|
self.parent_app.settings.setValue(COOKIE_TEXT_KEY, "")
|
|
|
|
self.parent_app.settings.sync()
|
|
|
|
# --- User Feedback ---
|
|
if path_saved and cookie_saved:
|
|
message = self._tr("settings_save_both_success", "Download location and cookie settings saved.")
|
|
elif path_saved:
|
|
message = self._tr("settings_save_path_only_success", "Download location saved. No cookie settings were active to save.")
|
|
elif cookie_saved:
|
|
message = self._tr("settings_save_cookie_only_success", "Cookie settings saved. Download location was not set.")
|
|
else:
|
|
QMessageBox.warning(self, self._tr("settings_save_nothing_title", "Nothing to Save"),
|
|
self._tr("settings_save_nothing_message", "The download location is not a valid directory and no cookie was active."))
|
|
return
|
|
|
|
QMessageBox.information(self, self._tr("settings_save_success_title", "Settings Saved"), message)
|