mirror of
https://github.com/nixietab/picodulce.git
synced 2025-04-10 10:28:56 +01:00
Added full custom theme support
commit 100! yay!
This commit is contained in:
parent
33d85e4cb2
commit
fc6b45a394
625
picodulce.py
625
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
|
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.QtGui import QFont, QIcon, QColor, QPalette, QMovie, QPixmap, QDesktopServices
|
from PyQt5.QtGui import QFont, QIcon, QColor, QPalette, QMovie, QPixmap, QDesktopServices, QBrush
|
||||||
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread, QUrl, QMetaObject, Q_ARG
|
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread, QUrl, QMetaObject, Q_ARG, QByteArray, QSize
|
||||||
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,10 +20,27 @@ class PicomcVersionSelector(QWidget):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.current_state = "menu"
|
self.current_state = "menu"
|
||||||
self.open_dialogs = []
|
self.open_dialogs = []
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self.init_ui()
|
|
||||||
self.check_config_file()
|
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__()
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
if self.config.get("CheckUpdate", False):
|
if self.config.get("CheckUpdate", False):
|
||||||
self.check_for_update_start()
|
self.check_for_update_start()
|
||||||
|
|
||||||
@ -32,6 +49,98 @@ 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()
|
||||||
@ -40,16 +149,35 @@ 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 palette
|
# Set application style and theme
|
||||||
QApplication.setStyle("Fusion")
|
QApplication.setStyle("Fusion")
|
||||||
self.check_config_file()
|
with open("config.json", "r") as config_file:
|
||||||
palette_type = self.config.get("Palette", "Dark")
|
config = json.load(config_file)
|
||||||
palette = self.get_palette(palette_type)
|
|
||||||
QApplication.instance().setPalette(palette)
|
if config.get("ThemeBackground", False): # Default to False if ThemeBackground is missing
|
||||||
|
# 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))
|
||||||
@ -135,77 +263,336 @@ class PicomcVersionSelector(QWidget):
|
|||||||
"IsRCPenabled": False,
|
"IsRCPenabled": False,
|
||||||
"CheckUpdate": False,
|
"CheckUpdate": False,
|
||||||
"LastPlayed": "",
|
"LastPlayed": "",
|
||||||
"Palette": "Dark"
|
"Theme": "Dark.json",
|
||||||
|
"ThemeBackground": True,
|
||||||
|
"ThemeRepository": "https://raw.githubusercontent.com/nixietab/picodulce-themes/main/repo.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if config file exists
|
# Step 1: Check if the file exists; if not, create it with default values
|
||||||
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.check_config_file()
|
self.config = default_config
|
||||||
|
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
|
||||||
|
|
||||||
# Load config from file
|
# Step 3: Check for missing keys and add defaults if necessary
|
||||||
with open(config_path, "r") as config_file:
|
updated = False
|
||||||
self.config = json.load(config_file)
|
for key, value in default_config.items():
|
||||||
|
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)
|
|
||||||
|
|
||||||
# Create title label
|
# Make the window resizable
|
||||||
|
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))
|
||||||
|
|
||||||
# Add settings components here...
|
# Create checkboxes for settings tab
|
||||||
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))
|
||||||
|
|
||||||
# Add checkboxes to layout
|
settings_layout.addWidget(title_label)
|
||||||
layout.addWidget(discord_rcp_checkbox)
|
settings_layout.addWidget(discord_rcp_checkbox)
|
||||||
layout.addWidget(check_updates_checkbox)
|
settings_layout.addWidget(check_updates_checkbox)
|
||||||
|
|
||||||
# Create theme dropdown
|
# Add buttons in the settings tab
|
||||||
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."""
|
||||||
@ -269,23 +656,6 @@ 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"
|
||||||
@ -631,121 +1001,6 @@ 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:
|
||||||
|
Loading…
Reference in New Issue
Block a user