mirror of
https://github.com/RetroGameSets/RGSX.git
synced 2026-03-27 10:54:46 +01:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05a8df5933 |
@@ -13,7 +13,7 @@ except Exception:
|
||||
pygame = None # type: ignore
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "2.3.2.5"
|
||||
app_version = "2.3.2.6"
|
||||
|
||||
|
||||
def get_application_root():
|
||||
|
||||
@@ -8,7 +8,7 @@ from utils import truncate_text_middle, wrap_text, load_system_image, truncate_t
|
||||
import logging
|
||||
import math
|
||||
from history import load_history, is_game_downloaded
|
||||
from language import _
|
||||
from language import _, get_size_units, get_speed_unit
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -956,15 +956,16 @@ def draw_game_scrollbar(screen, scroll_offset, total_items, visible_items, x, y,
|
||||
pygame.draw.rect(screen, THEME_COLORS["fond_lignes"], (x, scrollbar_y, 15, scrollbar_height), border_radius=4)
|
||||
|
||||
def format_size(size):
|
||||
"""Convertit une taille en octets en format lisible."""
|
||||
"""Convertit une taille en octets en format lisible avec unités adaptées à la langue."""
|
||||
if not isinstance(size, (int, float)) or size == 0:
|
||||
return "N/A"
|
||||
|
||||
for unit in ['o', 'Ko', 'Mo', 'Go', 'To']:
|
||||
units = get_size_units()
|
||||
for unit in units[:-1]: # Tous sauf le dernier (Po/PB)
|
||||
if size < 1024.0:
|
||||
return f"{size:.1f} {unit}"
|
||||
size /= 1024.0
|
||||
return f"{size:.1f} Po"
|
||||
return f"{size:.1f} {units[-1]}" # Dernier niveau (Po/PB)
|
||||
|
||||
|
||||
def draw_history_list(screen):
|
||||
@@ -991,7 +992,7 @@ def draw_history_list(screen):
|
||||
if entry.get("status") in ["Téléchargement", "Downloading"]:
|
||||
speed = entry.get("speed", 0.0)
|
||||
if speed and speed > 0:
|
||||
speed_str = f" - {speed:.2f} Mo/s"
|
||||
speed_str = f" - {speed:.2f} {get_speed_unit()}"
|
||||
break
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
@@ -1036,7 +1037,7 @@ def draw_history_list(screen):
|
||||
if history and history[current_history_item_inverted].get("status") in ["Téléchargement", "Downloading"]:
|
||||
speed = history[current_history_item_inverted].get("speed", 0.0)
|
||||
if speed > 0:
|
||||
speed_str = f"{speed:.2f} Mo/s"
|
||||
speed_str = f"{speed:.2f} {get_speed_unit()}"
|
||||
title_text = _("history_title").format(history_count) + f" {speed_str}"
|
||||
else:
|
||||
title_text = _("history_title").format(history_count)
|
||||
|
||||
@@ -67,6 +67,28 @@ def load_language(lang_code=None):
|
||||
return load_language(DEFAULT_LANGUAGE)
|
||||
return False
|
||||
|
||||
def get_size_units():
|
||||
"""Retourne les unités de taille adaptées à la langue courante.
|
||||
|
||||
Français utilise l'octet (o, Ko, Mo, Go, To, Po)
|
||||
Autres langues utilisent byte (B, KB, MB, GB, TB, PB)
|
||||
"""
|
||||
if current_language == "fr":
|
||||
return ['o', 'Ko', 'Mo', 'Go', 'To', 'Po']
|
||||
else:
|
||||
return ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
|
||||
|
||||
def get_speed_unit():
|
||||
"""Retourne l'unité de vitesse adaptée à la langue courante.
|
||||
|
||||
Français utilise Mo/s
|
||||
Autres langues utilisent MB/s
|
||||
"""
|
||||
if current_language == "fr":
|
||||
return "Mo/s"
|
||||
else:
|
||||
return "MB/s"
|
||||
|
||||
def get_text(key, default=None):
|
||||
"""Récupère la traduction correspondant à la clé en garantissant une chaîne.
|
||||
|
||||
|
||||
@@ -371,6 +371,13 @@
|
||||
"filter_none": "Alles abwählen",
|
||||
"filter_apply": "Filter anwenden",
|
||||
"filter_back": "Zurück",
|
||||
"accessibility_footer_font_size": "Fußzeilen-Schriftgröße: {0}",
|
||||
"popup_layout_changed_restart": "Layout geändert auf {0}x{1}. Bitte starten Sie die App neu."
|
||||
"accessibility_footer_font_size": "Fußzeilenschriftgröße: {0}",
|
||||
"popup_layout_changed_restart": "Layout geändert auf {0}x{1}. Bitte starten Sie die App neu.",
|
||||
"web_started": "Gestartet",
|
||||
"web_downloading": "Download",
|
||||
"web_in_progress": "In Bearbeitung",
|
||||
"web_added_to_queue": "zur Warteschlange hinzugefügt",
|
||||
"web_download_success": "erfolgreich heruntergeladen!",
|
||||
"web_download_error_for": "Fehler beim Herunterladen von",
|
||||
"web_already_present": "war bereits vorhanden"
|
||||
}
|
||||
@@ -372,5 +372,12 @@
|
||||
"filter_apply": "Apply Filter",
|
||||
"filter_back": "Back",
|
||||
"accessibility_footer_font_size": "Footer font size: {0}",
|
||||
"popup_layout_changed_restart": "Layout changed to {0}x{1}. Please restart the app to apply."
|
||||
"popup_layout_changed_restart": "Layout changed to {0}x{1}. Please restart the app to apply.",
|
||||
"web_started": "Started",
|
||||
"web_downloading": "Download",
|
||||
"web_in_progress": "In progress",
|
||||
"web_added_to_queue": "added to queue",
|
||||
"web_download_success": "downloaded successfully!",
|
||||
"web_download_error_for": "Error downloading",
|
||||
"web_already_present": "was already present"
|
||||
}
|
||||
@@ -372,5 +372,12 @@
|
||||
"filter_apply": "Aplicar filtro",
|
||||
"filter_back": "Volver",
|
||||
"accessibility_footer_font_size": "Tamaño fuente pie de página: {0}",
|
||||
"popup_layout_changed_restart": "Diseño cambiado a {0}x{1}. Reinicie la app para aplicar."
|
||||
"popup_layout_changed_restart": "Diseño cambiado a {0}x{1}. Reinicie la app para aplicar.",
|
||||
"web_started": "Iniciado",
|
||||
"web_downloading": "Descarga",
|
||||
"web_in_progress": "En curso",
|
||||
"web_added_to_queue": "añadido a la cola",
|
||||
"web_download_success": "¡descargado con éxito!",
|
||||
"web_download_error_for": "Error al descargar",
|
||||
"web_already_present": "ya estaba presente"
|
||||
}
|
||||
@@ -372,5 +372,12 @@
|
||||
"filter_apply": "Appliquer filtre",
|
||||
"filter_back": "Retour",
|
||||
"accessibility_footer_font_size": "Taille police pied de page : {0}",
|
||||
"popup_layout_changed_restart": "Disposition changée en {0}x{1}. Veuillez redémarrer l'app pour appliquer."
|
||||
"popup_layout_changed_restart": "Disposition changée en {0}x{1}. Veuillez redémarrer l'app pour appliquer.",
|
||||
"web_started": "Démarré",
|
||||
"web_downloading": "Téléchargement",
|
||||
"web_in_progress": "En cours",
|
||||
"web_added_to_queue": "ajouté à la queue",
|
||||
"web_download_success": "téléchargé avec succès!",
|
||||
"web_download_error_for": "Erreur lors du téléchargement de",
|
||||
"web_already_present": "était déjà présent"
|
||||
}
|
||||
@@ -372,5 +372,12 @@
|
||||
"filter_apply": "Applica filtro",
|
||||
"filter_back": "Indietro",
|
||||
"accessibility_footer_font_size": "Dimensione carattere piè di pagina: {0}",
|
||||
"popup_layout_changed_restart": "Layout cambiato in {0}x{1}. Riavviare l'app per applicare."
|
||||
"popup_layout_changed_restart": "Layout cambiato a {0}x{1}. Riavvia l'app per applicare.",
|
||||
"web_started": "Avviato",
|
||||
"web_downloading": "Download",
|
||||
"web_in_progress": "In corso",
|
||||
"web_added_to_queue": "aggiunto alla coda",
|
||||
"web_download_success": "scaricato con successo!",
|
||||
"web_download_error_for": "Errore durante il download di",
|
||||
"web_already_present": "era già presente"
|
||||
}
|
||||
@@ -371,6 +371,13 @@
|
||||
"filter_none": "Desmarcar tudo",
|
||||
"filter_apply": "Aplicar filtro",
|
||||
"filter_back": "Voltar",
|
||||
"accessibility_footer_font_size": "Tamanho fonte rodapé: {0}",
|
||||
"popup_layout_changed_restart": "Layout alterado para {0}x{1}. Reinicie o app para aplicar."
|
||||
"accessibility_footer_font_size": "Tamanho da fonte do rodapé: {0}",
|
||||
"popup_layout_changed_restart": "Layout alterado para {0}x{1}. Reinicie o app para aplicar.",
|
||||
"web_started": "Iniciado",
|
||||
"web_downloading": "Download",
|
||||
"web_in_progress": "Em andamento",
|
||||
"web_added_to_queue": "adicionado à fila",
|
||||
"web_download_success": "baixado com sucesso!",
|
||||
"web_download_error_for": "Erro ao baixar",
|
||||
"web_already_present": "já estava presente"
|
||||
}
|
||||
@@ -460,8 +460,13 @@ class RGSXHandler(BaseHTTPRequestHandler):
|
||||
|
||||
def _send_html(self, html, status=200, etag=None, last_modified=None):
|
||||
"""Envoie une réponse HTML"""
|
||||
self._set_headers('text/html; charset=utf-8', status, etag=etag, last_modified=last_modified)
|
||||
self.wfile.write(html.encode('utf-8'))
|
||||
try:
|
||||
self._set_headers('text/html; charset=utf-8', status, etag=etag, last_modified=last_modified)
|
||||
self.wfile.write(html.encode('utf-8'))
|
||||
except (ConnectionAbortedError, BrokenPipeError) as e:
|
||||
# La connexion a été fermée par le client, ce n'est pas une erreur critique
|
||||
logger.debug(f"Connexion fermée par le client pendant l'envoi HTML: {e}")
|
||||
pass
|
||||
|
||||
def _send_not_found(self):
|
||||
"""Répond avec un 404 générique."""
|
||||
@@ -703,10 +708,13 @@ class RGSXHandler(BaseHTTPRequestHandler):
|
||||
|
||||
# Route: API - Traductions
|
||||
elif path == '/api/translations':
|
||||
# Ajouter le code de langue dans les traductions pour que JS puisse l'utiliser
|
||||
translations_with_lang = TRANSLATIONS.copy()
|
||||
translations_with_lang['_language'] = get_language()
|
||||
self._send_json({
|
||||
'success': True,
|
||||
'language': get_language(),
|
||||
'translations': TRANSLATIONS
|
||||
'translations': translations_with_lang
|
||||
})
|
||||
|
||||
# Route: API - Liste des jeux d'une plateforme
|
||||
|
||||
@@ -401,6 +401,55 @@ header p { opacity: 0.9; font-size: 1.1em; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Amélioration de la lisibilité des settings */
|
||||
#settings-content label {
|
||||
display: block;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#settings-content select,
|
||||
#settings-content input[type="text"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
background-color: #f8f8f8;
|
||||
color: #000;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
#settings-content select:focus,
|
||||
#settings-content input[type="text"]:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
#settings-content input[type="checkbox"] {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#settings-content label.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#settings-content label.checkbox-label span {
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#settings-content button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
header h1 {
|
||||
font-size: 1.5em;
|
||||
|
||||
@@ -135,6 +135,34 @@
|
||||
return text;
|
||||
}
|
||||
|
||||
// Fonction pour obtenir les unités de taille selon la langue
|
||||
function getSizeUnits() {
|
||||
// Détecter la langue depuis les traductions chargées ou le navigateur
|
||||
const lang = translations['_language'] || navigator.language.substring(0, 2);
|
||||
// Français utilise o, Ko, Mo, Go, To
|
||||
// Autres langues utilisent B, KB, MB, GB, TB
|
||||
return lang === 'fr' ? ['o', 'Ko', 'Mo', 'Go', 'To', 'Po'] : ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||
}
|
||||
|
||||
// Fonction pour obtenir l'unité de vitesse selon la langue
|
||||
function getSpeedUnit() {
|
||||
const lang = translations['_language'] || navigator.language.substring(0, 2);
|
||||
return lang === 'fr' ? 'Mo/s' : 'MB/s';
|
||||
}
|
||||
|
||||
// Fonction pour formater une taille en octets
|
||||
function formatSize(bytes) {
|
||||
if (!bytes || bytes === 0) return 'N/A';
|
||||
const units = getSizeUnits();
|
||||
let size = bytes;
|
||||
let unitIndex = 0;
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
size /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
// Appliquer les traductions à tous les éléments marqués
|
||||
function applyTranslations() {
|
||||
// Mettre à jour le titre de la page
|
||||
@@ -1102,8 +1130,8 @@
|
||||
|
||||
// Afficher un toast de succès (pas de redirection de page)
|
||||
const toastMsg = mode === 'queue'
|
||||
? `📋 "${gameName}" ajouté à la queue`
|
||||
: `⬇️ Téléchargement de "${gameName}" lancé`;
|
||||
? `📋 "${gameName}" ${t('web_added_to_queue')}`
|
||||
: `⬇️ ${t('web_downloading')}: "${gameName}"`;
|
||||
showToast(toastMsg, 'success', 3000);
|
||||
|
||||
} else {
|
||||
@@ -1198,7 +1226,7 @@
|
||||
const speed = info.speed || 0;
|
||||
|
||||
// Utiliser game_name si disponible, sinon extraire de l'URL
|
||||
let fileName = info.game_name || 'Téléchargement';
|
||||
let fileName = info.game_name || t('web_downloading');
|
||||
if (!info.game_name) {
|
||||
try {
|
||||
fileName = decodeURIComponent(url.split('/').pop());
|
||||
@@ -1224,11 +1252,11 @@
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 0.9em;">
|
||||
<span>${status} - ${percent.toFixed(1)}%</span>
|
||||
<span>${speed > 0 ? speed.toFixed(2) + ' Mo/s' : ''}</span>
|
||||
<span>${speed > 0 ? speed.toFixed(2) + ' ' + getSpeedUnit() : ''}</span>
|
||||
</div>
|
||||
${total > 0 ? `<div style="font-size: 0.85em; color: #666;">${(downloaded / 1024 / 1024).toFixed(1)} Mo / ${(total / 1024 / 1024).toFixed(1)} Mo</div>` : ''}
|
||||
${total > 0 ? `<div style="font-size: 0.85em; color: #666;">${formatSize(downloaded)} / ${formatSize(total)}</div>` : ''}
|
||||
<div style="margin-top: 3px; font-size: 0.85em; color: #666;">
|
||||
📅 Démarré: ${info.timestamp || 'N/A'}
|
||||
📅 ${t('web_started')}: ${info.timestamp || 'N/A'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1264,10 +1292,10 @@
|
||||
const percent = info.progress_percent || 0;
|
||||
const downloaded = info.downloaded_size || 0;
|
||||
const total = info.total_size || 0;
|
||||
const status = info.status || 'En cours';
|
||||
const status = info.status || t('web_in_progress');
|
||||
const speed = info.speed || 0;
|
||||
|
||||
let fileName = info.game_name || 'Téléchargement';
|
||||
let fileName = info.game_name || t('web_downloading');
|
||||
if (!info.game_name) {
|
||||
try {
|
||||
fileName = decodeURIComponent(url.split('/').pop());
|
||||
@@ -1292,11 +1320,11 @@
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 0.9em;">
|
||||
<span>${status} - ${percent.toFixed(1)}%</span>
|
||||
<span>${speed > 0 ? speed.toFixed(2) + ' Mo/s' : ''}</span>
|
||||
<span>${speed > 0 ? speed.toFixed(2) + ' ' + getSpeedUnit() : ''}</span>
|
||||
</div>
|
||||
${total > 0 ? `<div style="font-size: 0.85em; color: #666;">${(downloaded / 1024 / 1024).toFixed(1)} Mo / ${(total / 1024 / 1024).toFixed(1)} Mo</div>` : ''}
|
||||
${total > 0 ? `<div style="font-size: 0.85em; color: #666;">${formatSize(downloaded)} / ${formatSize(total)}</div>` : ''}
|
||||
<div style="margin-top: 3px; font-size: 0.85em; color: #666;">
|
||||
📅 Démarré: ${info.timestamp || 'N/A'}
|
||||
📅 ${t('web_started')}: ${info.timestamp || 'N/A'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1446,13 +1474,13 @@
|
||||
// Si ce téléchargement n'était pas tracké et il est maintenant complété/erreur/etc
|
||||
if (!trackedDownloads[gameKey]) {
|
||||
if (status === 'Download_OK' || status === 'Completed') {
|
||||
showToast(`✅ "${entry.game_name}" téléchargé avec succès!`, 'success', 4000);
|
||||
showToast(`✅ "${entry.game_name}" ${t('web_download_success')}`, 'success', 4000);
|
||||
trackedDownloads[gameKey] = 'completed';
|
||||
} else if (status === 'Erreur' || status === 'error') {
|
||||
showToast(`❌ Erreur lors du téléchargement de "${entry.game_name}"`, 'error', 5000);
|
||||
showToast(`❌ ${t('web_download_error_for')} "${entry.game_name}"`, 'error', 5000);
|
||||
trackedDownloads[gameKey] = 'error';
|
||||
} else if (status === 'Already_Present') {
|
||||
showToast(`ℹ️ "${entry.game_name}" était déjà présent`, 'info', 3000);
|
||||
showToast(`ℹ️ "${entry.game_name}" ${t('web_already_present')}`, 'info', 3000);
|
||||
trackedDownloads[gameKey] = 'already_present';
|
||||
} else if (status === 'Canceled') {
|
||||
// Ne pas afficher de toast pour les téléchargements annulés
|
||||
@@ -1510,8 +1538,8 @@
|
||||
const isCanceled = status === 'Canceled';
|
||||
const isAlreadyPresent = status === 'Already_Present';
|
||||
const isQueued = status === 'Queued';
|
||||
const isDownloading = status === 'Downloading' || status === 'Téléchargement' || status === 'Downloading' ||
|
||||
status === 'Connecting' || status === 'Extracting' || status.startsWith('Try ');
|
||||
const isDownloading = status === 'Downloading' || status === 'Connecting' ||
|
||||
status === 'Extracting' || status.startsWith('Try ');
|
||||
const isSuccess = status === 'Download_OK' || status === 'Completed';
|
||||
|
||||
// Déterminer l'icône et la couleur
|
||||
@@ -1541,7 +1569,7 @@
|
||||
statusText = statusDownloading;
|
||||
}
|
||||
|
||||
const totalMo = h.total_size ? (h.total_size / 1024 / 1024).toFixed(1) : 'N/A';
|
||||
const sizeFormatted = h.total_size ? formatSize(h.total_size) : 'N/A';
|
||||
const platform = h.platform || 'N/A';
|
||||
const timestamp = h.timestamp || 'N/A';
|
||||
|
||||
@@ -1559,7 +1587,7 @@
|
||||
📦 ${platformLabel}: ${platform}
|
||||
</div>
|
||||
<div style="margin-top: 3px; font-size: 0.85em; color: #666;">
|
||||
💾 ${sizeLabel}: ${totalMo} Mo
|
||||
💾 ${sizeLabel}: ${sizeFormatted}
|
||||
</div>
|
||||
<div style="margin-top: 3px; font-size: 0.85em; color: #666;">
|
||||
📅 Date: ${timestamp}
|
||||
@@ -1744,12 +1772,12 @@
|
||||
<h3 style="margin-top: 30px; margin-bottom: 15px;">RGSX Configuration ⚙️</h3>
|
||||
|
||||
<div style="margin-bottom: 20px; background: #f0f8ff; padding: 15px; border-radius: 8px; border: 2px solid #007bff;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 10px; font-size: 1.1em;">📁 ${t('web_settings_roms_folder')}</label>
|
||||
<label style="display: block; margin-bottom: 10px; font-size: 1.1em;">📁 ${t('web_settings_roms_folder')}</label>
|
||||
<div style="display: flex; gap: 10px; margin-bottom: 8px; flex-wrap: wrap;">
|
||||
<input type="text" id="setting-roms-folder" value="${settings.roms_folder || ''}"
|
||||
data-translate-placeholder="web_settings_roms_placeholder"
|
||||
placeholder="${t('web_settings_roms_placeholder')}"
|
||||
style="flex: 1; min-width: 200px; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px;">
|
||||
style="flex: 1; min-width: 200px;">
|
||||
<button onclick="browseRomsFolder()"
|
||||
style="background: linear-gradient(135deg, #007bff 0%, #0056b3 100%); color: white; border: none; padding: 10px 20px; border-radius: 5px; font-weight: bold; cursor: pointer; white-space: nowrap; flex-shrink: 0;">
|
||||
📂 ${t('web_settings_browse')}
|
||||
@@ -1764,8 +1792,8 @@
|
||||
|
||||
<div style="background: #f9f9f9; padding: 20px; border-radius: 8px;">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 5px;">🌍 ${t('web_settings_language')}</label>
|
||||
<select id="setting-language" style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px;">
|
||||
<label>🌍 ${t('web_settings_language')}</label>
|
||||
<select id="setting-language">
|
||||
<option value="en" ${settings.language === 'en' ? 'selected' : ''}>English</option>
|
||||
<option value="fr" ${settings.language === 'fr' ? 'selected' : ''}>Français</option>
|
||||
<option value="es" ${settings.language === 'es' ? 'selected' : ''}>Español</option>
|
||||
@@ -1776,23 +1804,22 @@
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="checkbox" id="setting-music" ${settings.music_enabled ? 'checked' : ''}
|
||||
style="width: 20px; height: 20px; margin-right: 10px;">
|
||||
<span style="font-weight: bold;">🎵 ${t('web_settings_music')}</span>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="setting-music" ${settings.music_enabled ? 'checked' : ''}>
|
||||
<span>🎵 ${t('web_settings_music')}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 5px;">🔤 ${t('web_settings_font_scale')} (${settings.accessibility?.font_scale || 1.0})</label>
|
||||
<label>🔤 ${t('web_settings_font_scale')} (${settings.accessibility?.font_scale || 1.0})</label>
|
||||
<input type="range" id="setting-font-scale" min="0.5" max="2.0" step="0.1"
|
||||
value="${settings.accessibility?.font_scale || 1.0}"
|
||||
style="width: 100%;">
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 5px;">📐 ${t('web_settings_grid')}</label>
|
||||
<select id="setting-grid" style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px;">
|
||||
<label>📐 ${t('web_settings_grid')}</label>
|
||||
<select id="setting-grid">
|
||||
<option value="3x3" ${settings.display?.grid === '3x3' ? 'selected' : ''}>3x3</option>
|
||||
<option value="3x4" ${settings.display?.grid === '3x4' ? 'selected' : ''}>3x4</option>
|
||||
<option value="4x3" ${settings.display?.grid === '4x3' ? 'selected' : ''}>4x3</option>
|
||||
@@ -1801,54 +1828,50 @@
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 5px;">🖋️ ${t('web_settings_font_family')}</label>
|
||||
<select id="setting-font-family" style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px;">
|
||||
<label>🖋️ ${t('web_settings_font_family')}</label>
|
||||
<select id="setting-font-family">
|
||||
<option value="pixel" ${settings.display?.font_family === 'pixel' ? 'selected' : ''}>Pixel</option>
|
||||
<option value="dejavu" ${settings.display?.font_family === 'dejavu' ? 'selected' : ''}>DejaVu</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="checkbox" id="setting-symlink" ${settings.symlink?.enabled ? 'checked' : ''}
|
||||
style="width: 20px; height: 20px; margin-right: 10px;">
|
||||
<span style="font-weight: bold;">🔗 ${t('web_settings_symlink')}</span>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="setting-symlink" ${settings.symlink?.enabled ? 'checked' : ''}>
|
||||
<span>🔗 ${t('web_settings_symlink')}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 5px;">📦 ${t('web_settings_source_mode')}</label>
|
||||
<select id="setting-sources-mode" style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px;">
|
||||
<label>📦 ${t('web_settings_source_mode')}</label>
|
||||
<select id="setting-sources-mode">
|
||||
<option value="rgsx" ${settings.sources?.mode === 'rgsx' ? 'selected' : ''}>RGSX (default)</option>
|
||||
<option value="custom" ${settings.sources?.mode === 'custom' ? 'selected' : ''}>Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 5px;">🔗 ${t('web_settings_custom_url')}</label>
|
||||
<label>🔗 ${t('web_settings_custom_url')}</label>
|
||||
<input type="text" id="setting-custom-url" value="${settings.sources?.custom_url || ''}"
|
||||
data-translate-placeholder="web_settings_custom_url_placeholder"
|
||||
placeholder="${t('web_settings_custom_url_placeholder')}"
|
||||
style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px;">
|
||||
placeholder="${t('web_settings_custom_url_placeholder')}">
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="checkbox" id="setting-show-unsupported" ${settings.show_unsupported_platforms ? 'checked' : ''}
|
||||
style="width: 20px; height: 20px; margin-right: 10px;">
|
||||
<span style="font-weight: bold;">👀 ${showUnsupportedLabel}</span>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="setting-show-unsupported" ${settings.show_unsupported_platforms ? 'checked' : ''}>
|
||||
<span>👀 ${showUnsupportedLabel}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="checkbox" id="setting-allow-unknown" ${settings.allow_unknown_extensions ? 'checked' : ''}
|
||||
style="width: 20px; height: 20px; margin-right: 10px;">
|
||||
<span style="font-weight: bold;">⚠️ ${allowUnknownLabel}</span>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="setting-allow-unknown" ${settings.allow_unknown_extensions ? 'checked' : ''}>
|
||||
<span>⚠️ ${allowUnknownLabel}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button onclick="saveSettings()" style="width: 100%; background: linear-gradient(135deg, #28a745 0%, #20c997 100%); color: white; border: none; padding: 15px; border-radius: 8px; font-size: 18px; font-weight: bold; cursor: pointer; margin-top: 10px;">
|
||||
<button id="save-settings-btn" style="width: 100%; background: linear-gradient(135deg, #28a745 0%, #20c997 100%); color: white; border: none; padding: 15px; border-radius: 8px; font-size: 18px; font-weight: bold; cursor: pointer; margin-top: 10px;">
|
||||
💾 ${t('web_settings_save')}
|
||||
</button>
|
||||
</div>
|
||||
@@ -1860,13 +1883,24 @@
|
||||
label.textContent = `🔤 ${t('web_settings_font_scale')} (${e.target.value})`;
|
||||
});
|
||||
|
||||
// Attacher l'événement de sauvegarde au bouton
|
||||
document.getElementById('save-settings-btn').addEventListener('click', saveSettings);
|
||||
|
||||
} catch (error) {
|
||||
container.innerHTML = `<p style="color:red;">${t('web_error')}: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
// Sauvegarder les settings
|
||||
async function saveSettings() {
|
||||
async function saveSettings(event) {
|
||||
// Désactiver le bouton pendant la sauvegarde
|
||||
const saveButton = event?.target;
|
||||
const originalText = saveButton?.textContent;
|
||||
if (saveButton) {
|
||||
saveButton.disabled = true;
|
||||
saveButton.textContent = '⏳ Saving...';
|
||||
}
|
||||
|
||||
try {
|
||||
const settings = {
|
||||
language: document.getElementById('setting-language').value,
|
||||
@@ -1899,13 +1933,23 @@
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// Réactiver le bouton
|
||||
if (saveButton) {
|
||||
saveButton.disabled = false;
|
||||
saveButton.textContent = originalText;
|
||||
}
|
||||
// Afficher le dialogue de confirmation de redémarrage
|
||||
showRestartDialog();
|
||||
} else {
|
||||
throw new Error(data.error || t('web_error_unknown'));
|
||||
}
|
||||
} catch (error) {
|
||||
alert('❌ ' + t('web_error_save_settings', error.message));
|
||||
// Réactiver le bouton en cas d'erreur
|
||||
if (saveButton) {
|
||||
saveButton.disabled = false;
|
||||
saveButton.textContent = originalText;
|
||||
}
|
||||
alert('❌ ' + t('web_error_save_settings') + ': ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "2.3.2.5"
|
||||
"version": "2.3.2.6"
|
||||
}
|
||||
Reference in New Issue
Block a user