mirror of
				https://github.com/nixietab/picodulce.git
				synced 2025-10-31 05:25:12 +00:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "152b7d82dcf952b5eead4ac902fd30e758ab6ce3" and "33d85e4cb2d8d69124b8476d8d0bd213bdc39f99" have entirely different histories.
		
	
	
		
			152b7d82dc
			...
			33d85e4cb2
		
	
		
| @ -41,4 +41,4 @@ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### About the name | ### About the name | ||||||
| The name "Picodulce" comes from a popular Argentinian candy. This reflects the enjoyable and user-friendly experience that the launcher aims to provide, making game management straightforward and pleasant. | The name "Picodulce" comes from a popular Argentine candy. This reflects the enjoyable and user-friendly experience that the launcher aims to provide, making game management straightforward and pleasant. | ||||||
|  | |||||||
							
								
								
									
										623
									
								
								picodulce.py
									
									
									
									
									
								
							
							
						
						
									
										623
									
								
								picodulce.py
									
									
									
									
									
								
							| @ -9,9 +9,9 @@ import requests | |||||||
| import json | import json | ||||||
| import os | import os | ||||||
| import time | import time | ||||||
| from PyQt5.QtWidgets import QApplication, QComboBox, QWidget, QVBoxLayout, QListWidget, QPushButton, QMessageBox, QDialog, QHBoxLayout, QLabel, QLineEdit, QCheckBox, QTabWidget, QFrame, QSpacerItem, QSizePolicy, QMainWindow, QGridLayout, QTextEdit, QListWidget, QListWidgetItem | from PyQt5.QtWidgets import QApplication, QComboBox, QWidget, QVBoxLayout, QListWidget, QPushButton, QMessageBox, QDialog, QHBoxLayout, QLabel, QLineEdit, QCheckBox, QTabWidget, QFrame, QSpacerItem, QSizePolicy, QMainWindow, QGridLayout, QTextEdit | ||||||
| from PyQt5.QtGui import QFont, QIcon, QColor, QPalette, QMovie, QPixmap, QDesktopServices, QBrush | from PyQt5.QtGui import QFont, QIcon, QColor, QPalette, QMovie, QPixmap, QDesktopServices | ||||||
| from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread, QUrl, QMetaObject, Q_ARG, QByteArray, QSize | from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread, QUrl, QMetaObject, Q_ARG | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| 
 | 
 | ||||||
| logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') | logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s') | ||||||
| @ -20,27 +20,10 @@ class PicomcVersionSelector(QWidget): | |||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.current_state = "menu" |         self.current_state = "menu" | ||||||
|         self.open_dialogs = [] |         self.open_dialogs = [] | ||||||
|         self.check_config_file() |  | ||||||
|         self.themes_integrity() |  | ||||||
|         # Specify the path to the themes directory |  | ||||||
|         themes_folder = "themes" |  | ||||||
|          |  | ||||||
|         # Default theme file name (can be changed) |  | ||||||
|         theme_file = self.config.get("Theme", "Dark.json") |  | ||||||
| 
 |  | ||||||
|         # Ensure the theme file exists in the themes directory |  | ||||||
|         theme_file_path = os.path.join(themes_folder, theme_file) |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             # Load and apply the theme from the file |  | ||||||
|             self.load_theme_from_file(theme_file_path, app) |  | ||||||
|             print(f"Theme '{theme_file}' loaded successfully.") |  | ||||||
|         except Exception as e: |  | ||||||
|             print(f"Error: Could not load theme '{theme_file}'. Falling back to default theme. {e}") |  | ||||||
| 
 |  | ||||||
|         super().__init__() |         super().__init__() | ||||||
|         self.init_ui() |  | ||||||
| 
 | 
 | ||||||
|  |         self.init_ui() | ||||||
|  |         self.check_config_file() | ||||||
|         if self.config.get("CheckUpdate", False): |         if self.config.get("CheckUpdate", False): | ||||||
|             self.check_for_update_start() |             self.check_for_update_start() | ||||||
| 
 | 
 | ||||||
| @ -49,98 +32,6 @@ class PicomcVersionSelector(QWidget): | |||||||
|             discord_rcp_thread.daemon = True  # Make the thread a daemon so it terminates when the main program exits |             discord_rcp_thread.daemon = True  # Make the thread a daemon so it terminates when the main program exits | ||||||
|             discord_rcp_thread.start() |             discord_rcp_thread.start() | ||||||
| 
 | 
 | ||||||
|     def load_theme_from_file(self, file_path, app): |  | ||||||
|         if not os.path.exists(file_path): |  | ||||||
|             raise FileNotFoundError(f"Theme file '{file_path}' not found.") |  | ||||||
| 
 |  | ||||||
|         # Open and parse the JSON file |  | ||||||
|         with open(file_path, "r") as file: |  | ||||||
|             self.theme = json.load(file)  # Store theme as a class attribute |  | ||||||
| 
 |  | ||||||
|         # Ensure the required keys exist |  | ||||||
|         if "palette" not in self.theme: |  | ||||||
|             raise ValueError("JSON theme must contain a 'palette' section.") |  | ||||||
| 
 |  | ||||||
|         # Extract the palette |  | ||||||
|         palette_config = self.theme["palette"] |  | ||||||
| 
 |  | ||||||
|         # Create a new QPalette |  | ||||||
|         palette = QPalette() |  | ||||||
| 
 |  | ||||||
|         # Map palette roles to PyQt5 palette roles |  | ||||||
|         role_map = { |  | ||||||
|             "Window": QPalette.Window, |  | ||||||
|             "WindowText": QPalette.WindowText, |  | ||||||
|             "Base": QPalette.Base, |  | ||||||
|             "AlternateBase": QPalette.AlternateBase, |  | ||||||
|             "ToolTipBase": QPalette.ToolTipBase, |  | ||||||
|             "ToolTipText": QPalette.ToolTipText, |  | ||||||
|             "Text": QPalette.Text, |  | ||||||
|             "Button": QPalette.Button, |  | ||||||
|             "ButtonText": QPalette.ButtonText, |  | ||||||
|             "BrightText": QPalette.BrightText, |  | ||||||
|             "Link": QPalette.Link, |  | ||||||
|             "Highlight": QPalette.Highlight, |  | ||||||
|             "HighlightedText": QPalette.HighlightedText |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Apply colors from the palette config |  | ||||||
|         for role_name, color_code in palette_config.items(): |  | ||||||
|             if role_name in role_map: |  | ||||||
|                 palette.setColor(role_map[role_name], QColor(color_code)) |  | ||||||
|             else: |  | ||||||
|                 print(f"Warning: '{role_name}' is not a recognized palette role.") |  | ||||||
|          |  | ||||||
|         # Apply the palette to the application |  | ||||||
|         app.setPalette(palette) |  | ||||||
| 
 |  | ||||||
|     def themes_integrity(self): |  | ||||||
|         # Define folder and file paths |  | ||||||
|         themes_folder = "themes" |  | ||||||
|         dark_theme_file = os.path.join(themes_folder, "Dark.json") |  | ||||||
| 
 |  | ||||||
|         # Define the default content for Dark.json |  | ||||||
|         dark_theme_content = { |  | ||||||
|             "manifest": { |  | ||||||
|                 "name": "Dark", |  | ||||||
|                 "description": "The default picodulce launcher theme", |  | ||||||
|                 "author": "Nixietab", |  | ||||||
|                 "license": "MIT" |  | ||||||
|             }, |  | ||||||
|             "palette": { |  | ||||||
|                 "Window": "#353535", |  | ||||||
|                 "WindowText": "#ffffff", |  | ||||||
|                 "Base": "#191919", |  | ||||||
|                 "AlternateBase": "#353535", |  | ||||||
|                 "ToolTipBase": "#ffffff", |  | ||||||
|                 "ToolTipText": "#ffffff", |  | ||||||
|                 "Text": "#ffffff", |  | ||||||
|                 "Button": "#353535", |  | ||||||
|                 "ButtonText": "#ffffff", |  | ||||||
|                 "BrightText": "#ff0000", |  | ||||||
|                 "Link": "#2a82da", |  | ||||||
|                 "Highlight": "#4bb679", |  | ||||||
|                 "HighlightedText": "#ffffff" |  | ||||||
|             }, |  | ||||||
|             "background_image_base64": "" |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Step 1: Ensure the themes folder exists |  | ||||||
|         if not os.path.exists(themes_folder): |  | ||||||
|             print(f"Creating folder: {themes_folder}") |  | ||||||
|             os.makedirs(themes_folder) |  | ||||||
|         else: |  | ||||||
|             print(f"Folder already exists: {themes_folder}") |  | ||||||
| 
 |  | ||||||
|         # Step 2: Ensure Dark.json exists |  | ||||||
|         if not os.path.isfile(dark_theme_file): |  | ||||||
|             print(f"Creating file: {dark_theme_file}") |  | ||||||
|             with open(dark_theme_file, "w", encoding="utf-8") as file: |  | ||||||
|                 json.dump(dark_theme_content, file, indent=2) |  | ||||||
|             print("Dark.json has been created successfully.") |  | ||||||
|         else: |  | ||||||
|             print(f"File already exists: {dark_theme_file}") |  | ||||||
| 
 |  | ||||||
|     def init_ui(self): |     def init_ui(self): | ||||||
|         self.setWindowTitle('PicoDulce Launcher')  # Change window title |         self.setWindowTitle('PicoDulce Launcher')  # Change window title | ||||||
|         current_date = datetime.now() |         current_date = datetime.now() | ||||||
| @ -149,35 +40,16 @@ class PicomcVersionSelector(QWidget): | |||||||
|         else: |         else: | ||||||
|             self.setWindowIcon(QIcon('launcher_icon.ico'))  # Set regular icon |             self.setWindowIcon(QIcon('launcher_icon.ico'))  # Set regular icon | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|         self.setGeometry(100, 100, 400, 250) |         self.setGeometry(100, 100, 400, 250) | ||||||
| 
 | 
 | ||||||
|         # Set application style and theme |         # Set application style and palette | ||||||
|         QApplication.setStyle("Fusion") |         QApplication.setStyle("Fusion") | ||||||
|         with open("config.json", "r") as config_file: |         self.check_config_file() | ||||||
|             config = json.load(config_file) |         palette_type = self.config.get("Palette", "Dark") | ||||||
| 
 |         palette = self.get_palette(palette_type) | ||||||
|         if config.get("ThemeBackground", False):  # Default to False if ThemeBackground is missing |         QApplication.instance().setPalette(palette) | ||||||
|             # Get the base64 string for the background image from the theme file |          | ||||||
|             theme_background_base64 = self.theme.get("background_image_base64", "") |  | ||||||
|             if theme_background_base64: |  | ||||||
|                 try: |  | ||||||
|                     # Decode the base64 string and create a QPixmap |  | ||||||
|                     background_image_data = QByteArray.fromBase64(theme_background_base64.encode()) |  | ||||||
|                     pixmap = QPixmap() |  | ||||||
|                     if pixmap.loadFromData(background_image_data): |  | ||||||
|                         self.setAutoFillBackground(True) |  | ||||||
|                         palette = self.palette() |  | ||||||
|                         palette.setBrush(QPalette.Window, QBrush(pixmap.scaled( |  | ||||||
|                             self.size(), Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation |  | ||||||
|                         ))) |  | ||||||
|                         self.setPalette(palette) |  | ||||||
|                     else: |  | ||||||
|                         print("Error: Failed to load background image from base64 string.") |  | ||||||
|                 except Exception as e: |  | ||||||
|                     print(f"Error: Failed to decode and set background image. {e}") |  | ||||||
|             else: |  | ||||||
|                 print("No background image base64 string found in the theme file.") |  | ||||||
| 
 |  | ||||||
|         # Create title label |         # Create title label | ||||||
|         title_label = QLabel('PicoDulce Launcher')  # Change label text |         title_label = QLabel('PicoDulce Launcher')  # Change label text | ||||||
|         title_label.setFont(QFont("Arial", 24, QFont.Bold)) |         title_label.setFont(QFont("Arial", 24, QFont.Bold)) | ||||||
| @ -263,336 +135,77 @@ class PicomcVersionSelector(QWidget): | |||||||
|             "IsRCPenabled": False, |             "IsRCPenabled": False, | ||||||
|             "CheckUpdate": False, |             "CheckUpdate": False, | ||||||
|             "LastPlayed": "", |             "LastPlayed": "", | ||||||
|             "Theme": "Dark.json", |             "Palette": "Dark" | ||||||
|             "ThemeBackground": True, |  | ||||||
|             "ThemeRepository": "https://raw.githubusercontent.com/nixietab/picodulce-themes/main/repo.json" |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         # Step 1: Check if the file exists; if not, create it with default values |         # Check if config file exists | ||||||
|         if not os.path.exists(config_path): |         if not os.path.exists(config_path): | ||||||
|  |             # Create config file with default values | ||||||
|             with open(config_path, "w") as config_file: |             with open(config_path, "w") as config_file: | ||||||
|                 json.dump(default_config, config_file, indent=4) |                 json.dump(default_config, config_file, indent=4) | ||||||
|             self.config = default_config |             self.check_config_file() | ||||||
|             return |  | ||||||
| 
 | 
 | ||||||
|         # Step 2: Try loading the config file, handle invalid JSON |  | ||||||
|         try: |  | ||||||
|             with open(config_path, "r") as config_file: |  | ||||||
|                 self.config = json.load(config_file) |  | ||||||
|         except (json.JSONDecodeError, ValueError): |  | ||||||
|             # File is corrupted, overwrite it with default configuration |  | ||||||
|             with open(config_path, "w") as config_file: |  | ||||||
|                 json.dump(default_config, config_file, indent=4) |  | ||||||
|             self.config = default_config |  | ||||||
|             return |  | ||||||
| 
 | 
 | ||||||
|         # Step 3: Check for missing keys and add defaults if necessary |         # Load config from file | ||||||
|         updated = False |         with open(config_path, "r") as config_file: | ||||||
|         for key, value in default_config.items(): |             self.config = json.load(config_file) | ||||||
|             if key not in self.config:  # Field is missing |  | ||||||
|                 self.config[key] = value |  | ||||||
|                 updated = True |  | ||||||
| 
 |  | ||||||
|         # Step 4: Save the repaired config back to the file |  | ||||||
|         if updated: |  | ||||||
|             with open(config_path, "w") as config_file: |  | ||||||
|                 json.dump(self.config, config_file, indent=4) |  | ||||||
| 
 | 
 | ||||||
|     def open_settings_dialog(self): |     def open_settings_dialog(self): | ||||||
|         dialog = QDialog(self) |         dialog = QDialog(self) | ||||||
|         dialog.setWindowTitle('Settings') |         dialog.setWindowTitle('Settings') | ||||||
|  |         dialog.setFixedSize(300, 250) | ||||||
| 
 | 
 | ||||||
|         # Make the window resizable |         # Create title label | ||||||
|         dialog.setMinimumSize(400, 300) |  | ||||||
| 
 |  | ||||||
|         # Create a Tab Widget |  | ||||||
|         tab_widget = QTabWidget() |  | ||||||
| 
 |  | ||||||
|         # Create the Settings Tab |  | ||||||
|         settings_tab = QWidget() |  | ||||||
|         settings_layout = QVBoxLayout() |  | ||||||
| 
 |  | ||||||
|         title_label = QLabel('Settings') |         title_label = QLabel('Settings') | ||||||
|         title_label.setFont(QFont("Arial", 14)) |         title_label.setFont(QFont("Arial", 14)) | ||||||
| 
 | 
 | ||||||
|         # Create checkboxes for settings tab |         # Add settings components here... | ||||||
|  |         layout = QVBoxLayout() | ||||||
|  |         layout.addWidget(title_label) | ||||||
|  | 
 | ||||||
|  |         # Create checkboxes | ||||||
|         discord_rcp_checkbox = QCheckBox('Discord RPC') |         discord_rcp_checkbox = QCheckBox('Discord RPC') | ||||||
|         discord_rcp_checkbox.setChecked(self.config.get("IsRCPenabled", False)) |         discord_rcp_checkbox.setChecked(self.config.get("IsRCPenabled", False)) | ||||||
| 
 |  | ||||||
|         check_updates_checkbox = QCheckBox('Check Updates on Start') |         check_updates_checkbox = QCheckBox('Check Updates on Start') | ||||||
|         check_updates_checkbox.setChecked(self.config.get("CheckUpdate", False)) |         check_updates_checkbox.setChecked(self.config.get("CheckUpdate", False)) | ||||||
| 
 | 
 | ||||||
|         settings_layout.addWidget(title_label) |         # Add checkboxes to layout | ||||||
|         settings_layout.addWidget(discord_rcp_checkbox) |         layout.addWidget(discord_rcp_checkbox) | ||||||
|         settings_layout.addWidget(check_updates_checkbox) |         layout.addWidget(check_updates_checkbox) | ||||||
| 
 | 
 | ||||||
|         # Add buttons in the settings tab |         # Create theme dropdown | ||||||
|  |         theme_label = QLabel('Theme:') | ||||||
|  |         layout.addWidget(theme_label) | ||||||
|  | 
 | ||||||
|  |         theme_combobox = QComboBox() | ||||||
|  |         themes = ['Dark', 'Obsidian', 'Redstone', 'Alpha', 'Strawberry', "Native", "Christmas"]  # Replace with your actual themes | ||||||
|  |         theme_combobox.addItems(themes) | ||||||
|  |         current_theme_index = themes.index(self.config.get("Palette", "Default Theme")) | ||||||
|  |         theme_combobox.setCurrentIndex(current_theme_index) | ||||||
|  |         layout.addWidget(theme_combobox) | ||||||
|  | 
 | ||||||
|  |         # Create Save button | ||||||
|  |         save_button = QPushButton('Save') | ||||||
|  |         save_button.clicked.connect(lambda: self.save_settings(discord_rcp_checkbox.isChecked(), check_updates_checkbox.isChecked(), theme_combobox.currentText())) | ||||||
|  |         layout.addWidget(save_button) | ||||||
|  | 
 | ||||||
|  |         # Create Check for updates button | ||||||
|         update_button = QPushButton('Check for updates') |         update_button = QPushButton('Check for updates') | ||||||
|         update_button.clicked.connect(self.check_for_update) |         update_button.clicked.connect(self.check_for_update) | ||||||
|  |         layout.addWidget(update_button) | ||||||
| 
 | 
 | ||||||
|  |         # Create Open game directory button | ||||||
|         open_game_directory_button = QPushButton('Open game directory') |         open_game_directory_button = QPushButton('Open game directory') | ||||||
|         open_game_directory_button.clicked.connect(self.open_game_directory) |         open_game_directory_button.clicked.connect(self.open_game_directory) | ||||||
|  |         layout.addWidget(open_game_directory_button) | ||||||
| 
 | 
 | ||||||
|  |         # Create "Stats for Nerds" button | ||||||
|         stats_button = QPushButton('Stats for Nerds') |         stats_button = QPushButton('Stats for Nerds') | ||||||
|         stats_button.clicked.connect(self.show_system_info) |         stats_button.clicked.connect(self.show_system_info) | ||||||
| 
 |         layout.addWidget(stats_button) | ||||||
|         settings_layout.addWidget(update_button) |  | ||||||
|         settings_layout.addWidget(open_game_directory_button) |  | ||||||
|         settings_layout.addWidget(stats_button) |  | ||||||
| 
 |  | ||||||
|         settings_tab.setLayout(settings_layout) |  | ||||||
| 
 |  | ||||||
|         # Create the Customization Tab |  | ||||||
|         customization_tab = QWidget() |  | ||||||
|         customization_layout = QVBoxLayout() |  | ||||||
| 
 |  | ||||||
|         # Create theme background checkbox for customization tab |  | ||||||
|         theme_background_checkbox = QCheckBox('Theme Background') |  | ||||||
|         theme_background_checkbox.setChecked(self.config.get("ThemeBackground", False)) |  | ||||||
| 
 |  | ||||||
|         # Label to show currently selected theme |  | ||||||
|         theme_filename = self.config.get('Theme', 'Default.json') |  | ||||||
|         current_theme_label = QLabel(f"Current Theme: {theme_filename}") |  | ||||||
| 
 |  | ||||||
|         # QListWidget to display available themes |  | ||||||
|         json_files_label = QLabel('Available Themes:') |  | ||||||
|         json_files_list_widget = QListWidget() |  | ||||||
| 
 |  | ||||||
|         # Track selected theme |  | ||||||
|         self.selected_theme = theme_filename  # Default to current theme |  | ||||||
| 
 |  | ||||||
|         # Path to themes folder |  | ||||||
|         themes_folder = os.path.join(os.getcwd(), "themes") |  | ||||||
|          |  | ||||||
|         def populate_themes(): |  | ||||||
|             json_files_list_widget.clear() |  | ||||||
|             if os.path.exists(themes_folder): |  | ||||||
|                 json_files = [f for f in os.listdir(themes_folder) if f.endswith('.json')] |  | ||||||
|                 for json_file in json_files: |  | ||||||
|                     json_path = os.path.join(themes_folder, json_file) |  | ||||||
|                     with open(json_path, 'r') as file: |  | ||||||
|                         theme_data = json.load(file) |  | ||||||
| 
 |  | ||||||
|                         # Get manifest details |  | ||||||
|                         manifest = theme_data.get("manifest", {}) |  | ||||||
|                         name = manifest.get("name", "Unnamed") |  | ||||||
|                         description = manifest.get("description", "No description available") |  | ||||||
|                         author = manifest.get("author", "Unknown") |  | ||||||
| 
 |  | ||||||
|                         # Create display text and list item |  | ||||||
|                         display_text = f"#{name}\n{description}\nBy: {author}" |  | ||||||
|                         list_item = QListWidgetItem(display_text) |  | ||||||
|                         list_item.setData(Qt.UserRole, json_file)  # Store the JSON filename as metadata |  | ||||||
|                         json_files_list_widget.addItem(list_item) |  | ||||||
| 
 |  | ||||||
|         # Initially populate themes |  | ||||||
|         populate_themes() |  | ||||||
| 
 |  | ||||||
|         # Update current theme label when a theme is selected |  | ||||||
|         def on_theme_selected(): |  | ||||||
|             selected_item = json_files_list_widget.currentItem() |  | ||||||
|             if selected_item: |  | ||||||
|                 self.selected_theme = selected_item.data(Qt.UserRole) |  | ||||||
|                 current_theme_label.setText(f"Current Theme: {self.selected_theme}") |  | ||||||
| 
 |  | ||||||
|         json_files_list_widget.itemClicked.connect(on_theme_selected) |  | ||||||
| 
 |  | ||||||
|         # Add widgets to the layout |  | ||||||
|         customization_layout.addWidget(theme_background_checkbox) |  | ||||||
|         customization_layout.addWidget(current_theme_label) |  | ||||||
|         customization_layout.addWidget(json_files_label) |  | ||||||
|         customization_layout.addWidget(json_files_list_widget) |  | ||||||
| 
 |  | ||||||
|         # Button to download themes |  | ||||||
|         download_themes_button = QPushButton("Download Themes") |  | ||||||
|         download_themes_button.clicked.connect(self.download_themes_window) |  | ||||||
| 
 |  | ||||||
|         customization_layout.addWidget(download_themes_button) |  | ||||||
| 
 |  | ||||||
|         customization_tab.setLayout(customization_layout) |  | ||||||
| 
 |  | ||||||
|         # Add the tabs to the TabWidget |  | ||||||
|         tab_widget.addTab(settings_tab, "Settings") |  | ||||||
|         tab_widget.addTab(customization_tab, "Customization") |  | ||||||
| 
 |  | ||||||
|         # Save button |  | ||||||
|         save_button = QPushButton('Save') |  | ||||||
|         save_button.clicked.connect( |  | ||||||
|             lambda: self.save_settings( |  | ||||||
|                 discord_rcp_checkbox.isChecked(), |  | ||||||
|                 check_updates_checkbox.isChecked(), |  | ||||||
|                 theme_background_checkbox.isChecked(), |  | ||||||
|                 self.selected_theme  # Pass the selected theme here |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|         # Main layout |  | ||||||
|         main_layout = QVBoxLayout() |  | ||||||
|         main_layout.addWidget(tab_widget) |  | ||||||
|         main_layout.addWidget(save_button) |  | ||||||
| 
 |  | ||||||
|         dialog.setLayout(main_layout) |  | ||||||
|         dialog.exec_() |  | ||||||
| 
 |  | ||||||
|         ## REPOSITORY BLOCK BEGGINS |  | ||||||
| 
 |  | ||||||
|     def download_themes_window(self): |  | ||||||
|         # Create a QDialog to open the themes window |  | ||||||
|         dialog = QDialog(self) |  | ||||||
|         dialog.setWindowTitle("Themes Repository") |  | ||||||
|         dialog.setGeometry(100, 100, 400, 300) |  | ||||||
| 
 |  | ||||||
|         # Layout setup for the new window |  | ||||||
|         layout = QVBoxLayout() |  | ||||||
| 
 |  | ||||||
|         # List widget to display themes |  | ||||||
|         self.theme_list = QListWidget(dialog) |  | ||||||
|         self.theme_list.setSelectionMode(QListWidget.SingleSelection) |  | ||||||
|         self.theme_list.clicked.connect(self.on_theme_click) |  | ||||||
|         layout.addWidget(self.theme_list) |  | ||||||
| 
 |  | ||||||
|         # Label to display the details of the selected theme |  | ||||||
|         self.details_label = QLabel(dialog)  # Define the label here |  | ||||||
|         layout.addWidget(self.details_label) |  | ||||||
| 
 |  | ||||||
|         # Download button to download the selected theme's JSON |  | ||||||
|         download_button = QPushButton("Download Theme", dialog) |  | ||||||
|         download_button.clicked.connect(self.theme_download) |  | ||||||
|         layout.addWidget(download_button) |  | ||||||
| 
 | 
 | ||||||
|         dialog.setLayout(layout) |         dialog.setLayout(layout) | ||||||
| 
 |         dialog.exec_() | ||||||
|         # Initially load themes into the list |  | ||||||
|         self.load_themes() |  | ||||||
| 
 |  | ||||||
|         dialog.exec_()  # Open the dialog as a modal window |  | ||||||
| 
 |  | ||||||
|     def fetch_themes(self): |  | ||||||
|         try: |  | ||||||
|             # Read the config.json file |  | ||||||
|             with open("config.json", "r") as config_file: |  | ||||||
|                 config = json.load(config_file) |  | ||||||
|              |  | ||||||
|             # Get the ThemeRepository value |  | ||||||
|             url = config.get("ThemeRepository") |  | ||||||
|             if not url: |  | ||||||
|                 raise ValueError("ThemeRepository is not defined in config.json") |  | ||||||
| 
 |  | ||||||
|             # Fetch themes from the specified URL |  | ||||||
|             response = requests.get(url) |  | ||||||
|             response.raise_for_status()  # Raise an exception for HTTP errors |  | ||||||
|             return response.json() |  | ||||||
|         except (FileNotFoundError, json.JSONDecodeError) as config_error: |  | ||||||
|             self.show_error_popup("Error reading configuration", f"An error occurred while reading config.json: {config_error}") |  | ||||||
|             return {} |  | ||||||
|         except requests.exceptions.RequestException as fetch_error: |  | ||||||
|             self.show_error_popup("Error fetching themes", f"An error occurred while fetching themes: {fetch_error}") |  | ||||||
|             return {} |  | ||||||
|         except ValueError as value_error: |  | ||||||
|             self.show_error_popup("Configuration Error", str(value_error)) |  | ||||||
|             return {} |  | ||||||
| 
 |  | ||||||
|     def download_theme_json(self, theme_url, theme_name): |  | ||||||
|         try: |  | ||||||
|             response = requests.get(theme_url) |  | ||||||
|             response.raise_for_status()  # Raise an exception for HTTP errors |  | ||||||
| 
 |  | ||||||
|             # Create the themes directory if it doesn't exist |  | ||||||
|             if not os.path.exists('themes'): |  | ||||||
|                 os.makedirs('themes') |  | ||||||
| 
 |  | ||||||
|             # Save the content of the theme JSON file to the 'themes' folder |  | ||||||
|             theme_filename = os.path.join('themes', f'{theme_name}.json') |  | ||||||
|             with open(theme_filename, 'wb') as f: |  | ||||||
|                 f.write(response.content) |  | ||||||
|             print(f"Downloaded {theme_name} theme to {theme_filename}") |  | ||||||
|         except requests.exceptions.RequestException as e: |  | ||||||
|             self.show_error_popup("Error downloading theme", f"An error occurred while downloading {theme_name}: {e}") |  | ||||||
| 
 |  | ||||||
|     def show_error_popup(self, title, message): |  | ||||||
|         msg = QMessageBox() |  | ||||||
|         msg.setIcon(QMessageBox.Critical) |  | ||||||
|         msg.setWindowTitle(title) |  | ||||||
|         msg.setText(message) |  | ||||||
|         msg.exec_() |  | ||||||
| 
 |  | ||||||
|     def is_theme_installed(self, theme_name): |  | ||||||
|         return os.path.exists(os.path.join('themes', f'{theme_name}.json')) |  | ||||||
| 
 |  | ||||||
|     def load_themes(self): |  | ||||||
|         theme_list = self.theme_list |  | ||||||
|         themes_data = self.fetch_themes() |  | ||||||
|         themes = themes_data.get("themes", []) |  | ||||||
| 
 |  | ||||||
|         theme_list.clear() |  | ||||||
|         for theme in themes: |  | ||||||
|             # Add "[I]" if the theme is installed |  | ||||||
|             theme_display_name = f"{theme['name']} by {theme['author']}" |  | ||||||
|             if self.is_theme_installed(theme['name']): |  | ||||||
|                 theme_display_name += " [I]"  # Mark installed themes |  | ||||||
|             theme_list.addItem(theme_display_name) |  | ||||||
| 
 |  | ||||||
|     def on_theme_click(self): |  | ||||||
|         selected_item = self.theme_list.currentItem() |  | ||||||
|         if selected_item: |  | ||||||
|             theme_name = selected_item.text().split(" by ")[0] |  | ||||||
|             theme = self.find_theme_by_name(theme_name) |  | ||||||
|             if theme: |  | ||||||
|                 # Display theme details in the QLabel (details_label) |  | ||||||
|                 self.details_label.setText( |  | ||||||
|                     f"Name: {theme['name']}\n" |  | ||||||
|                     f"Description: {theme['description']}\n" |  | ||||||
|                     f"Author: {theme['author']}\n" |  | ||||||
|                     f"License: {theme['license']}\n" |  | ||||||
|                     f"Link: {theme['link']}" |  | ||||||
|                 ) |  | ||||||
| 
 |  | ||||||
|     def find_theme_by_name(self, theme_name): |  | ||||||
|         themes_data = self.fetch_themes() |  | ||||||
|         themes = themes_data.get("themes", []) |  | ||||||
|         for theme in themes: |  | ||||||
|             if theme["name"] == theme_name: |  | ||||||
|                 return theme |  | ||||||
|         return None |  | ||||||
| 
 |  | ||||||
|     def theme_download(self): |  | ||||||
|         selected_item = self.theme_list.currentItem() |  | ||||||
|         if selected_item: |  | ||||||
|             theme_name = selected_item.text().split(" by ")[0] |  | ||||||
|             theme = self.find_theme_by_name(theme_name) |  | ||||||
|             if theme: |  | ||||||
|                 theme_url = theme["link"] |  | ||||||
|                 self.download_theme_json(theme_url, theme_name) |  | ||||||
|                 self.load_themes()  # Reload the list to show the "[I]" marker |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         ## REPOSITORY BLOCK ENDS |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     def save_settings(self, is_rcp_enabled, check_updates_on_start, theme_background, selected_theme): |  | ||||||
|         config_path = "config.json" |  | ||||||
|         updated_config = { |  | ||||||
|             "IsRCPenabled": is_rcp_enabled, |  | ||||||
|             "CheckUpdate": check_updates_on_start, |  | ||||||
|             "ThemeBackground": theme_background, |  | ||||||
|             "Theme": selected_theme |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Update config values |  | ||||||
|         self.config.update(updated_config) |  | ||||||
| 
 |  | ||||||
|         # Save updated config to file |  | ||||||
|         with open(config_path, "w") as config_file: |  | ||||||
|             json.dump(self.config, config_file, indent=4) |  | ||||||
| 
 |  | ||||||
|         QMessageBox.information( |  | ||||||
|             self,  |  | ||||||
|             "Settings Saved",  |  | ||||||
|             "Settings saved successfully!\n\nTo apply the changes, please restart the launcher." |  | ||||||
|         ) |  | ||||||
|         self.__init__() |  | ||||||
| 
 | 
 | ||||||
|     def get_palette(self, palette_type): |     def get_palette(self, palette_type): | ||||||
|         """Retrieve the corresponding palette based on the palette type.""" |         """Retrieve the corresponding palette based on the palette type.""" | ||||||
| @ -656,6 +269,23 @@ class PicomcVersionSelector(QWidget): | |||||||
|         except subprocess.CalledProcessError as e: |         except subprocess.CalledProcessError as e: | ||||||
|             print(f"Error running picomc command: {e}") |             print(f"Error running picomc command: {e}") | ||||||
| 
 | 
 | ||||||
|  |     def save_settings(self, is_rcp_enabled, check_updates_on_start, selected_theme): | ||||||
|  |         config_path = "config.json" | ||||||
|  |         updated_config = { | ||||||
|  |             "IsRCPenabled": is_rcp_enabled, | ||||||
|  |             "CheckUpdate": check_updates_on_start, | ||||||
|  |             "Palette": selected_theme | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # Update config values | ||||||
|  |         self.config.update(updated_config) | ||||||
|  | 
 | ||||||
|  |         # Save updated config to file | ||||||
|  |         with open(config_path, "w") as config_file: | ||||||
|  |             json.dump(self.config, config_file, indent=4) | ||||||
|  | 
 | ||||||
|  |         QMessageBox.information(self, "Settings Saved", "Settings saved successfully!\n\n to them to be applyed you need to restart the launcher") | ||||||
|  |         self.__init__() | ||||||
| 
 | 
 | ||||||
|     def populate_installed_versions(self): |     def populate_installed_versions(self): | ||||||
|         config_path = "config.json" |         config_path = "config.json" | ||||||
| @ -1001,6 +631,121 @@ class PicomcVersionSelector(QWidget): | |||||||
|         ) |         ) | ||||||
|         QMessageBox.about(self, "About", about_message) |         QMessageBox.about(self, "About", about_message) | ||||||
| 
 | 
 | ||||||
|  |     def create_dark_palette(self): | ||||||
|  |         palette = QPalette() | ||||||
|  |         palette.setColor(QPalette.Window, QColor(53, 53, 53)) | ||||||
|  |         palette.setColor(QPalette.WindowText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Base, QColor(25, 25, 25)) | ||||||
|  |         palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) | ||||||
|  |         palette.setColor(QPalette.ToolTipBase, Qt.white) | ||||||
|  |         palette.setColor(QPalette.ToolTipText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Text, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Button, QColor(53, 53, 53)) | ||||||
|  |         palette.setColor(QPalette.ButtonText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.BrightText, Qt.red) | ||||||
|  |         palette.setColor(QPalette.Link, QColor(42, 130, 218)) | ||||||
|  |         palette.setColor(QPalette.Highlight, QColor(75 , 182, 121)) | ||||||
|  |         palette.setColor(QPalette.HighlightedText, Qt.white) | ||||||
|  |         return palette | ||||||
|  | 
 | ||||||
|  |     def create_obsidian_palette(self): | ||||||
|  |         palette = QPalette() | ||||||
|  |         palette.setColor(QPalette.Window, QColor("#1c1c1c")) | ||||||
|  |         palette.setColor(QPalette.WindowText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Base, QColor("#1c1c1c")) | ||||||
|  |         palette.setColor(QPalette.AlternateBase, QColor("#1c1c1c")) | ||||||
|  |         palette.setColor(QPalette.ToolTipBase, QColor("#1c1c1c")) | ||||||
|  |         palette.setColor(QPalette.ToolTipText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Text, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Button, QColor("#1c1c1c")) | ||||||
|  |         palette.setColor(QPalette.ButtonText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.BrightText, Qt.red) | ||||||
|  |         palette.setColor(QPalette.Link, QColor("#6a0dad")) | ||||||
|  |         palette.setColor(QPalette.Highlight, QColor("#6200EE")) | ||||||
|  |         palette.setColor(QPalette.HighlightedText, Qt.white) | ||||||
|  |         return palette | ||||||
|  | 
 | ||||||
|  |     def create_redstone_palette(self): | ||||||
|  |         palette = QPalette() | ||||||
|  |         palette.setColor(QPalette.Window, QColor(53, 53, 53)) | ||||||
|  |         palette.setColor(QPalette.WindowText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Base, QColor(25, 25, 25)) | ||||||
|  |         palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) | ||||||
|  |         palette.setColor(QPalette.ToolTipBase, Qt.white) | ||||||
|  |         palette.setColor(QPalette.ToolTipText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Text, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Button, QColor(53, 53, 53)) | ||||||
|  |         palette.setColor(QPalette.ButtonText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.BrightText, Qt.red) | ||||||
|  |         palette.setColor(QPalette.Link, QColor(42, 130, 218)) | ||||||
|  |         palette.setColor(QPalette.Highlight, QColor(255 , 0, 0)) | ||||||
|  |         palette.setColor(QPalette.HighlightedText, Qt.white) | ||||||
|  |         return palette | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def create_alpha_palette(self): | ||||||
|  |         palette = QPalette() | ||||||
|  |         palette.setColor(QPalette.Window, QColor("#31363b")) | ||||||
|  |         palette.setColor(QPalette.WindowText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Base, QColor(25, 25, 25)) | ||||||
|  |         palette.setColor(QPalette.AlternateBase, QColor("#31363b")) | ||||||
|  |         palette.setColor(QPalette.ToolTipBase, Qt.white) | ||||||
|  |         palette.setColor(QPalette.ToolTipText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Text, Qt.white) | ||||||
|  |         palette.setColor(QPalette.Button, QColor("#31363b")) | ||||||
|  |         palette.setColor(QPalette.ButtonText, Qt.white) | ||||||
|  |         palette.setColor(QPalette.BrightText, Qt.red) | ||||||
|  |         palette.setColor(QPalette.Link, QColor(42, 130, 218)) | ||||||
|  |         palette.setColor(QPalette.Highlight, QColor(42, 130, 218)) | ||||||
|  |         palette.setColor(QPalette.HighlightedText, Qt.white) | ||||||
|  |         return palette | ||||||
|  | 
 | ||||||
|  |     def create_strawberry_palette(self): | ||||||
|  |         palette = QPalette() | ||||||
|  |         palette.setColor(QPalette.Window, QColor("#fce8e6")) | ||||||
|  |         palette.setColor(QPalette.WindowText, Qt.black) | ||||||
|  |         palette.setColor(QPalette.Base, QColor("#f8d7d5")) | ||||||
|  |         palette.setColor(QPalette.AlternateBase, QColor("#fce8e6")) | ||||||
|  |         palette.setColor(QPalette.ToolTipBase, QColor("#f8d7d5")) | ||||||
|  |         palette.setColor(QPalette.ToolTipText, Qt.black) | ||||||
|  |         palette.setColor(QPalette.Text, Qt.black) | ||||||
|  |         palette.setColor(QPalette.Button, QColor("#fce8e6")) | ||||||
|  |         palette.setColor(QPalette.ButtonText, Qt.black) | ||||||
|  |         palette.setColor(QPalette.BrightText, Qt.red) | ||||||
|  |         palette.setColor(QPalette.Link, QColor("#ff4d4d")) | ||||||
|  |         palette.setColor(QPalette.Highlight, QColor("#ff8080")) | ||||||
|  |         palette.setColor(QPalette.HighlightedText, Qt.black) | ||||||
|  |         return palette | ||||||
|  | 
 | ||||||
|  |     def create_native_palette(self): | ||||||
|  |         palette = QPalette() | ||||||
|  |         return palette | ||||||
|  | 
 | ||||||
|  |     def create_christmas_palette(self): | ||||||
|  |         palette = QPalette() | ||||||
|  |         # I know is shitty ok | ||||||
|  |         # Background colors | ||||||
|  |         palette.setColor(QPalette.Window, QColor(34, 49, 34))  # Deep evergreen | ||||||
|  |         palette.setColor(QPalette.WindowText, QColor(210, 255, 210))  # Soft, frosty green text | ||||||
|  |         palette.setColor(QPalette.Base, QColor(17, 34, 17))  # Dark forest green | ||||||
|  |         palette.setColor(QPalette.AlternateBase, QColor(25, 51, 25))  # Slightly lighter green for contrast | ||||||
|  |         palette.setColor(QPalette.ToolTipBase, QColor(245, 255, 245))  # Light green for tooltips | ||||||
|  |         palette.setColor(QPalette.ToolTipText, QColor(34, 139, 34))  # Vibrant green for tooltip text | ||||||
|  |          | ||||||
|  |         # Text colors | ||||||
|  |         palette.setColor(QPalette.Text, QColor(245, 255, 245))  # Light green for standard text | ||||||
|  |         palette.setColor(QPalette.Button, QColor(0, 100, 0))  # Dark green for buttons | ||||||
|  |         palette.setColor(QPalette.ButtonText, QColor(245, 255, 245))  # Light green button text | ||||||
|  |         palette.setColor(QPalette.BrightText, QColor(60, 179, 113))  # Bright mint green for emphasis | ||||||
|  |         palette.setColor(QPalette.Link, QColor(42, 130, 218))  # Blue links for contrast | ||||||
|  |          | ||||||
|  |         # Highlight colors | ||||||
|  |         palette.setColor(QPalette.Highlight, QColor(0, 128, 0))  # Rich pine green highlight | ||||||
|  |         palette.setColor(QPalette.HighlightedText, QColor(245, 255, 245))  # Light green text on highlights | ||||||
|  | 
 | ||||||
|  |         return palette | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     def check_for_update_start(self): |     def check_for_update_start(self): | ||||||
|         try: |         try: | ||||||
|             with open("version.json") as f: |             with open("version.json") as f: | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| { | { | ||||||
|   "version": "0.11", |   "version": "0.10.1", | ||||||
|   "links": [ |   "links": [ | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/version.json", |     "https://raw.githubusercontent.com/nixietab/picodulce/main/version.json", | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/picodulce.py", |     "https://raw.githubusercontent.com/nixietab/picodulce/main/picodulce.py", | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user