1
0
forked from Mirrors/RGSX

v1.9.9.1 - Add multi-select download feature and update UI elements

- Implemented multi-select functionality for batch downloads in the game list.
- Updated UI to reflect selected games with visual indicators.
- Removed download result popup, redirecting to history after downloads.
- Enhanced language files to include multi-select actions in controls.
This commit is contained in:
skymike03
2025-08-28 22:06:52 +02:00
parent 333967462d
commit fe19341d9a
11 changed files with 232 additions and 87 deletions

View File

@@ -15,6 +15,7 @@ The application supports multiple sources like myrient and 1fichier. These sourc
- Downloads require no authentication or account for most sources.
- Systems marked `(1fichier)` in the name will only be accessible if you provide your 1fichier API key (see below).
- **Download history** : View and re-download previous files.
- **Multi-select downloads** : Mark multiple games in the game list with the key mapped to Clear History (default X) to enqueue several downloads in one batch. Press Confirm to start batch.
- **Control customization** : Remap keyboard or controller keys to your preference with automatic button name detection from EmulationStation (beta).
- **Font size adjustment** : If you find the text too small/too large, you can change it in the menu.
- **Search mode** : Filter games by name for quick navigation with virtual keyboard on controller.
@@ -96,6 +97,7 @@ INFO: for retrobat on first launch, the application will download Python in the
- Select a platform, then a game.
- Press the confirm key (default, **Enter** or **A** button) to start the download.
- Optional: Press the key mapped to Clear History (default **X**) on several games to toggle multi-selection ([X] marker). Then press Confirm to launch a sequential batch download.
- Follow the progress in the `HISTORY` menu.
---
@@ -193,7 +195,7 @@ git checkout -b feature/your-feature-name
## ⚠️ Known issues / To implement
- Multiple download management
- (None currently listed)
---

View File

@@ -14,6 +14,7 @@ L'application prend en charge plusieurs sources comme myrient, 1fichier. Ces sou
- Les téléchargements ne nécessitent aucune authentification ni compte pour la plupart.
- Les systèmes notés `(1fichier)` dans le nom ne seront accessibles que si vous renseignez votre clé API 1fichier (voir plus bas).
- **Historique des téléchargements** : Consultez et retéléchargez les anciens fichiers.
- **Téléchargements multi-sélection** : Marquez plusieurs jeux dans la liste avec la touche associée à Vider Historique (par défaut X) pour préparer un lot. Appuyez ensuite sur Confirmer pour lancer les téléchargements en séquence.
- **Personnalisation des contrôles** : Remappez les touches du clavier ou de la manette à votre convenance avec détection automatique des noms de boutons depuis EmulationStation(beta).
- **Changement de taille de police** : Si vous trouvez les écritures trop petites/trop grosses, vous pouvez le changer dans le menu.
- **Mode recherche** : Filtrez les jeux par nom pour une navigation rapide avec clavier virtuel sur manette.
@@ -94,6 +95,7 @@ INFO : pour retrobat au premier lancement, l'application téléchargera Python d
- Sélectionnez une plateforme, puis un jeu.
- Appuyez sur la touche configurée confirm (par défaut, **Entrée** ou bouton **A**) pour lancer le téléchargement.
- Option : appuyez sur la touche Vider Historique (par défaut **X**) sur plusieurs jeux pour activer/désactiver leur sélection (marqueur [X]). Puis validez pour lancer un lot de téléchargements.
- Suivez la progression dans le menu `HISTORIQUE`.
---
@@ -187,7 +189,7 @@ git checkout -b feature/nom-de-votre-fonctionnalité
## ⚠️ Problèmes connus / À implémenter
- Gestion des téléchargements multiples
- (Aucun listé actuellement)
---

View File

@@ -11,7 +11,7 @@ import config
from display import (
init_display, draw_loading_screen, draw_error_screen, draw_platform_grid,
draw_progress_screen, draw_controls, draw_virtual_keyboard, draw_popup_result_download,
draw_progress_screen, draw_controls, draw_virtual_keyboard,
draw_extension_warning, draw_pause_menu, draw_controls_help, draw_game_list,
draw_history_list, draw_clear_history_dialog, draw_cancel_download_dialog,
draw_confirm_dialog, draw_redownload_game_cache_dialog, draw_popup, draw_gradient,
@@ -329,7 +329,7 @@ async def main():
logger.debug("Téléchargement annulé, retour à l'état précédent")
continue
if config.menu_state in ["platform", "game", "error", "confirm_exit", "download_result", "history"]:
if config.menu_state in ["platform", "game", "error", "confirm_exit", "history"]:
action = handle_controls(event, sources, joystick, screen)
config.needs_redraw = True
if action == "quit":
@@ -442,14 +442,14 @@ async def main():
config.previous_menu_state = config.menu_state
logger.debug(f"Previous menu state défini: {config.previous_menu_state}")
success, message = download_from_1fichier(url, platform, game_name, is_zip_non_supported)
# Ancien popup download_result supprimé : retour direct à l'historique
config.download_result_message = message
config.download_result_error = not success
config.download_result_start_time = pygame.time.get_ticks()
config.menu_state = "download_result"
config.download_progress.clear()
config.pending_download = None
config.menu_state = "history"
config.needs_redraw = True
logger.debug(f"Retéléchargement 1fichier terminé pour {game_name}, succès={success}, message={message}")
logger.debug(f"Retéléchargement 1fichier terminé pour {game_name}, succès={success}, message={message}, retour direct history")
else:
is_supported, message, is_zip_non_supported = check_extension_before_download(url, platform, game_name)
if not is_supported:
@@ -464,12 +464,11 @@ async def main():
success, message = download_rom(url, platform, game_name, is_zip_non_supported)
config.download_result_message = message
config.download_result_error = not success
config.download_result_start_time = pygame.time.get_ticks()
config.menu_state = "download_result"
config.download_progress.clear()
config.pending_download = None
config.menu_state = "history"
config.needs_redraw = True
logger.debug(f"Retéléchargement terminé pour {game_name}, succès={success}, message={message}")
logger.debug(f"Retéléchargement terminé pour {game_name}, succès={success}, message={message}, retour direct history")
break
elif action in ("clear_history", "delete_history") and config.menu_state == "history":
# Ouvrir le dialogue de confirmation
@@ -500,10 +499,9 @@ async def main():
break
config.download_result_message = message
config.download_result_error = not success
config.download_result_start_time = pygame.time.get_ticks()
config.menu_state = "download_result"
config.download_progress.clear()
config.pending_download = None
config.menu_state = "history"
config.needs_redraw = True
del config.download_tasks[task_id]
except Exception as e:
@@ -521,10 +519,9 @@ async def main():
break
config.download_result_message = message
config.download_result_error = True
config.download_result_start_time = pygame.time.get_ticks()
config.menu_state = "download_result"
config.download_progress.clear()
config.pending_download = None
config.menu_state = "history"
config.needs_redraw = True
del config.download_tasks[task_id]
else:
@@ -567,13 +564,7 @@ async def main():
config.needs_redraw = True
del config.download_tasks[task_id]
# Gestion de la fin du popup download_result
if config.menu_state == "download_result" and current_time - config.download_result_start_time > 3000:
config.menu_state = "history" # Rester dans l'historique après le popup
config.download_progress.clear()
config.pending_download = None
config.needs_redraw = True
logger.debug(f"Fin popup download_result, retour à history")
# Popup download_result supprimé : plus de temporisation de 3s
# Affichage
if config.needs_redraw:
@@ -588,7 +579,9 @@ async def main():
elif config.menu_state == "error":
draw_error_screen(screen)
elif config.menu_state == "update_result":
draw_popup_result_download(screen, config.update_result_message, config.update_result_error)
# Ancien popup supprimé : afficher directement l'historique
config.menu_state = "history"
draw_history_list(screen)
elif config.menu_state == "platform":
draw_platform_grid(screen)
elif config.menu_state == "game":
@@ -600,8 +593,7 @@ async def main():
draw_virtual_keyboard(screen)
elif config.menu_state == "download_progress":
draw_progress_screen(screen)
elif config.menu_state == "download_result":
draw_popup_result_download(screen, config.download_result_message, config.download_result_error)
# État download_result supprimé
elif config.menu_state == "confirm_exit":
draw_confirm_dialog(screen)
elif config.menu_state == "extension_warning":

View File

@@ -5,7 +5,7 @@ import platform
from rgsx_settings import load_rgsx_settings, save_rgsx_settings, migrate_old_settings
# Version actuelle de l'application
app_version = "1.9.9.0"
app_version = "1.9.9.1"
def get_operating_system():
"""Renvoie le nom du système d'exploitation."""
@@ -178,6 +178,10 @@ popup_timer = 0 # Temps restant pour le popup en millisecondes (0 = inactif)
last_frame_time = pygame.time.get_ticks()
current_music_name = None
music_popup_start_time = 0
selected_games = set() # Indices des jeux sélectionnés pour un téléchargement multiple (menu game)
batch_download_indices = [] # File d'attente des indices de jeux à traiter en lot
batch_in_progress = False # Indique qu'un lot est en cours
batch_pending_game = None # Données du jeu en attente de confirmation d'extension
GRID_COLS = 3 # Number of columns in the platform grid

View File

@@ -20,13 +20,16 @@ from language import _ # Import de la fonction de traduction
logger = logging.getLogger(__name__)
# Extensions d'archives pour lesquelles on ignore l'avertissement d'extension non supportée
ARCHIVE_EXTENSIONS = {'.zip', '.7z', '.rar', '.tar', '.gz', '.xz', '.bz2'}
# Variables globales pour la répétition
key_states = {} # Dictionnaire pour suivre l'état des touches
# Liste des états valides
VALID_STATES = [
"platform", "game", "download_result", "confirm_exit",
"platform", "game", "confirm_exit",
"extension_warning", "pause_menu", "controls_help", "history", "controls_mapping",
"redownload_game_cache", "restart_popup", "error", "loading", "confirm_clear_history",
"language_select"
@@ -462,6 +465,16 @@ def handle_controls(event, sources, joystick, screen):
config.menu_state = "history"
config.needs_redraw = True
logger.debug("Ouverture history depuis game")
# Bascule de sélection multiple avec la touche clear_history (réutilisée)
elif is_input_matched(event, "clear_history"):
if games:
idx = config.current_game
if idx in config.selected_games:
config.selected_games.remove(idx)
else:
config.selected_games.add(idx)
config.needs_redraw = True
logger.debug(f"Multi-select toggle index={idx}, now selected={len(config.selected_games)}")
elif is_input_matched(event, "cancel"):
config.menu_state = "platform"
config.current_game = 0
@@ -473,9 +486,68 @@ def handle_controls(event, sources, joystick, screen):
config.menu_state = "redownload_game_cache"
config.needs_redraw = True
logger.debug("Passage à redownload_game_cache depuis game")
# Sélectionner un jeu, événement confirm
# Télécharger les jeux sélectionnés (multi) ou le jeu courant
elif is_input_matched(event, "confirm"):
if games:
# Batch multi-sélection
if games and config.selected_games:
config.batch_download_indices = sorted({i for i in config.selected_games if 0 <= i < len(games)})
config.selected_games.clear()
config.batch_in_progress = True
config.batch_pending_game = None
def process_next_batch_item():
# si un jeu attend encore confirmation, ne pas avancer
if config.batch_pending_game:
return False
while config.batch_download_indices:
idx = config.batch_download_indices.pop(0)
g = games[idx]
url = g[1]
game_name = g[0]
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
logger.debug(f"Batch step: {game_name} idx={idx} restants={len(config.batch_download_indices)}")
config.pending_download = check_extension_before_download(url, platform, game_name)
if not config.pending_download:
continue # passe au suivant
is_supported = is_extension_supported(
sanitize_filename(game_name),
platform,
load_extensions_json()
)
ext = os.path.splitext(url)[1].lower()
if not is_supported and ext not in ARCHIVE_EXTENSIONS:
# Stocker comme pending sans dupliquer l'entrée
config.batch_pending_game = (url, platform, game_name, config.pending_download[3])
config.previous_menu_state = config.menu_state
config.menu_state = "extension_warning"
config.extension_confirm_selection = 0
config.needs_redraw = True
return False
# Téléchargement direct
config.history.append(add_to_history(platform, game_name, "downloading", url, 0, "Téléchargement en cours"))
config.current_history_item = len(config.history) -1
task_id = str(pygame.time.get_ticks())
if is_1fichier_url(url):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
config.history[-1]["status"] = "Erreur"
config.history[-1]["message"] = "Erreur API : Clé API 1fichier absente"
save_history(config.history)
continue
task = asyncio.create_task(download_from_1fichier(url, platform, game_name, config.pending_download[3], task_id))
else:
task = asyncio.create_task(download_rom(url, platform, game_name, config.pending_download[3], task_id))
config.download_tasks[task_id] = (task, url, game_name, platform)
# passer à l'élément suivant (boucle while)
return True # fin lot
process_next_batch_item()
# Aller à l'historique si pas d'avertissement en attente
if config.menu_state == "game" and not config.batch_pending_game:
config.menu_state = "history"
config.needs_redraw = True
action = "download"
elif games:
url = games[config.current_game][1]
game_name = games[config.current_game][0]
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
@@ -516,7 +588,8 @@ def handle_controls(event, sources, joystick, screen):
platform,
load_extensions_json()
)
if not is_supported:
ext = os.path.splitext(url)[1].lower()
if not is_supported and ext not in ARCHIVE_EXTENSIONS:
config.previous_menu_state = config.menu_state
config.menu_state = "extension_warning"
config.extension_confirm_selection = 0
@@ -548,7 +621,8 @@ def handle_controls(event, sources, joystick, screen):
platform,
load_extensions_json()
)
if not is_supported:
ext = os.path.splitext(url)[1].lower()
if not is_supported and ext not in ARCHIVE_EXTENSIONS:
config.previous_menu_state = config.menu_state
config.menu_state = "extension_warning"
config.extension_confirm_selection = 0
@@ -616,6 +690,55 @@ def handle_controls(event, sources, joystick, screen):
logger.debug(f"Téléchargement confirmé après avertissement: {game_name} pour {platform} depuis {url}, task_id={task_id}")
config.pending_download = None
action = "download"
# Reprendre batch si présent
# Reprise batch si un jeu était en attente
if config.batch_pending_game:
config.batch_pending_game = None
if config.batch_in_progress:
config.menu_state = "game"
# Relancer la progression du lot
# Appeler la fonction locale si disponible (ré-implémentation légère ici)
try:
games = config.filtered_games if config.filter_active or config.search_mode else config.games
while config.batch_download_indices and not config.batch_pending_game:
idx = config.batch_download_indices.pop(0)
if idx < 0 or idx >= len(games):
continue
g = games[idx]
url = g[1]; game_name = g[0]
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
config.pending_download = check_extension_before_download(url, platform, game_name)
if not config.pending_download:
continue
is_supported = is_extension_supported(sanitize_filename(game_name), platform, load_extensions_json())
ext = os.path.splitext(url)[1].lower()
if not is_supported and ext not in ARCHIVE_EXTENSIONS:
config.batch_pending_game = (url, platform, game_name, config.pending_download[3])
config.previous_menu_state = config.menu_state
config.menu_state = "extension_warning"
config.extension_confirm_selection = 0
config.needs_redraw = True
break
config.history.append(add_to_history(platform, game_name, "downloading", url, 0, "Téléchargement en cours"))
config.current_history_item = len(config.history) -1
task_id = str(pygame.time.get_ticks())
if is_1fichier_url(url):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
config.history[-1]["status"] = "Erreur"
config.history[-1]["message"] = "Erreur API : Clé API 1fichier absente"
save_history(config.history)
continue
task = asyncio.create_task(download_from_1fichier(url, platform, game_name, config.pending_download[3], task_id))
else:
task = asyncio.create_task(download_rom(url, platform, game_name, config.pending_download[3], task_id))
config.download_tasks[task_id] = (task, url, game_name, platform)
if not config.batch_download_indices and not config.batch_pending_game:
# Batch terminé
config.batch_in_progress = False
config.menu_state = "history"
except Exception as e:
logger.error(f"Erreur reprise batch après warning: {e}")
else:
config.menu_state = "error"
config.error_message = _("error_invalid_download_data")
@@ -628,6 +751,52 @@ def handle_controls(event, sources, joystick, screen):
config.menu_state = validate_menu_state(config.previous_menu_state)
config.needs_redraw = True
logger.debug(f"Retour à {config.menu_state} depuis extension_warning")
if config.batch_pending_game:
# Annulation de ce jeu -> on le saute
config.batch_pending_game = None
if config.batch_in_progress:
config.menu_state = "game"
# Reprise similaire à ci-dessus
try:
games = config.filtered_games if config.filter_active or config.search_mode else config.games
while config.batch_download_indices and not config.batch_pending_game:
idx = config.batch_download_indices.pop(0)
if idx < 0 or idx >= len(games):
continue
g = games[idx]
url = g[1]; game_name = g[0]
platform = config.platforms[config.current_platform]["name"] if isinstance(config.platforms[config.current_platform], dict) else config.platforms[config.current_platform]
config.pending_download = check_extension_before_download(url, platform, game_name)
if not config.pending_download:
continue
is_supported = is_extension_supported(sanitize_filename(game_name), platform, load_extensions_json())
ext = os.path.splitext(url)[1].lower()
if not is_supported and ext not in ARCHIVE_EXTENSIONS:
config.batch_pending_game = (url, platform, game_name, config.pending_download[3])
config.previous_menu_state = config.menu_state
config.menu_state = "extension_warning"
config.extension_confirm_selection = 0
config.needs_redraw = True
break
config.history.append(add_to_history(platform, game_name, "downloading", url, 0, "Téléchargement en cours"))
config.current_history_item = len(config.history) -1
task_id = str(pygame.time.get_ticks())
if is_1fichier_url(url):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
config.history[-1]["status"] = "Erreur"
config.history[-1]["message"] = "Erreur API : Clé API 1fichier absente"
save_history(config.history)
continue
task = asyncio.create_task(download_from_1fichier(url, platform, game_name, config.pending_download[3], task_id))
else:
task = asyncio.create_task(download_rom(url, platform, game_name, config.pending_download[3], task_id))
config.download_tasks[task_id] = (task, url, game_name, platform)
if not config.batch_download_indices and not config.batch_pending_game:
config.batch_in_progress = False
config.menu_state = "history"
except Exception as e:
logger.error(f"Erreur reprise batch annulation warning: {e}")
elif is_input_matched(event, "left") or is_input_matched(event, "right"):
config.extension_confirm_selection = 1 - config.extension_confirm_selection
config.needs_redraw = True
@@ -636,6 +805,10 @@ def handle_controls(event, sources, joystick, screen):
config.menu_state = validate_menu_state(config.previous_menu_state)
config.needs_redraw = True
logger.debug(f"Retour à {config.menu_state} depuis extension_warning")
if config.batch_pending_game:
config.batch_pending_game = None
if config.batch_in_progress:
config.menu_state = "game"
#Historique
elif config.menu_state == "history":
@@ -690,7 +863,7 @@ def handle_controls(event, sources, joystick, screen):
config.pending_download = check_extension_before_download(game[1], platform, game_name)
if config.pending_download:
url, platform, game_name, is_zip_non_supported = config.pending_download
if is_zip_non_supported:
if is_zip_non_supported and os.path.splitext(url)[1].lower() not in ARCHIVE_EXTENSIONS:
config.previous_menu_state = config.menu_state
config.menu_state = "extension_warning"
config.extension_confirm_selection = 0
@@ -798,14 +971,7 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
logger.debug("Annulation du vidage de l'historique, retour à history")
# Résultat téléchargement
elif config.menu_state == "download_result":
if is_input_matched(event, "confirm"):
config.menu_state = validate_menu_state(config.previous_menu_state)
config.popup_timer = 0
config.pending_download = None
config.needs_redraw = True
logger.debug(f"Retour à {config.menu_state} depuis download_result")
# État download_result supprimé
# Confirmation quitter
elif config.menu_state == "confirm_exit":

View File

@@ -308,8 +308,6 @@ def load_controls_config(path=CONTROLS_CONFIG_PATH):
data["clear_history"] = data["progress"]
changed = True
# Compléter avec des valeurs par défaut si nécessaire (facultatif selon votre implémentation)
# ...existing code de complétion si présent...
if changed:
os.makedirs(os.path.dirname(path), exist_ok=True)

View File

@@ -624,8 +624,12 @@ def draw_game_list(screen):
for i in range(config.scroll_offset, min(config.scroll_offset + items_per_page, len(games))):
game_name = games[i][0] if isinstance(games[i], (list, tuple)) else games[i]
color = THEME_COLORS["fond_lignes"] if i == config.current_game else THEME_COLORS["text"]
game_text = truncate_text_middle(game_name, config.small_font, rect_width - 40, is_filename=False)
is_marked = i in getattr(config, 'selected_games', set())
# Couleur verte si jeu sous curseur OU marqué en multi-sélection
color = THEME_COLORS["fond_lignes"] if (i == config.current_game or is_marked) else THEME_COLORS["text"]
# Préfixe ASCII pour distinguer les jeux marqués (éviter collision glyphes)
prefix = "[X] " if is_marked else " "
game_text = truncate_text_middle(prefix + game_name, config.small_font, rect_width - 40, is_filename=False)
text_surface = config.small_font.render(game_text, True, color)
text_rect = text_surface.get_rect(center=(config.screen_width // 2, rect_y + margin_top_bottom + (i - config.scroll_offset) * line_height + line_height // 2))
if i == config.current_game:
@@ -715,6 +719,13 @@ def draw_history_list(screen):
extra_margin_bottom = 80
title_height = config.title_font.get_height() + 20
# Sécuriser current_history_item pour éviter IndexError
if history:
if config.current_history_item < 0 or config.current_history_item >= len(history):
config.current_history_item = max(0, min(len(history) - 1, config.current_history_item))
else:
config.current_history_item = 0
speed = 0.0
if history and history[config.current_history_item].get("status") in ["Téléchargement", "downloading"]:
speed = history[config.current_history_item].get("speed", 0.0)
@@ -1019,37 +1030,7 @@ def draw_progress_screen(screen):
progress_width = int(bar_width * (min(100, max(0, progress_percent)) / 100))
# Écran popupsultat téléchargement
def draw_popup_result_download(screen, message, is_error):
"""Affiche une popup flottante centrée avec un message de résultat et un compte à rebours."""
if message is None:
message = _("download_canceled")
logger.debug(f"Message popup : {message}, is_error={is_error}")
screen.blit(OVERLAY, (0, 0))
popup_width = int(config.screen_width * 0.8)
line_height = config.small_font.get_height() + 10
wrapped_message = wrap_text(message, config.small_font, popup_width - 40)
text_height = len(wrapped_message) * line_height
margin_top_bottom = 20
popup_height = text_height + 2 * margin_top_bottom + line_height
popup_x = (config.screen_width - popup_width) // 2
popup_y = (config.screen_height - popup_height) // 2
pygame.draw.rect(screen, THEME_COLORS["button_idle"], (popup_x, popup_y, popup_width, popup_height), border_radius=12)
pygame.draw.rect(screen, THEME_COLORS["border"], (popup_x, popup_y, popup_width, popup_height), 2, border_radius=12)
for i, line in enumerate(wrapped_message):
text_surface = config.small_font.render(line, True, THEME_COLORS["error_text"] if is_error else THEME_COLORS["text"])
text_rect = text_surface.get_rect(center=(config.screen_width // 2, popup_y + margin_top_bottom + i * line_height + line_height // 2))
screen.blit(text_surface, text_rect)
remaining_time = 3
countdown_text = _("popup_countdown").format(remaining_time, 's' if remaining_time != 1 else '')
countdown_surface = config.small_font.render(countdown_text, True, THEME_COLORS["text"])
countdown_rect = countdown_surface.get_rect(center=(config.screen_width // 2, popup_y + margin_top_bottom + len(wrapped_message) * line_height + line_height // 2))
screen.blit(countdown_surface, countdown_rect)
## Ancienne fonction draw_popup_result_download supprimée (popup de fin de téléchargement retiré)
# Écran avertissement extension non supportée téléchargement
def draw_extension_warning(screen):
@@ -1282,7 +1263,7 @@ def draw_controls_help(screen, previous_state):
# États autorisés (même logique qu'avant)
allowed_states = {
"error", "platform", "game", "download_result", "confirm_exit",
"error", "platform", "game", "confirm_exit",
"extension_warning", "history", "clear_history"
}
if previous_state not in allowed_states:

View File

@@ -103,7 +103,7 @@
"controls_action_right": "Rechts",
"controls_action_page_up": "Vorherige Seite",
"controls_action_page_down": "Nächste Seite",
"controls_action_clear_history": "Verlauf leeren",
"controls_action_clear_history": "Mehrfachauswahl / Verlauf leeren",
"controls_action_history": "Verlauf",
"controls_action_filter": "Filtern",
"controls_action_delete": "Löschen",
@@ -118,7 +118,7 @@
"controls_desc_right": "Nach rechts navigieren",
"controls_desc_page_up": "Vorherige Seite/Schnelles Scrollen nach oben (z.B.: BildAuf, LB)",
"controls_desc_page_down": "Nächste Seite/Schnelles Scrollen nach unten (z.B.: BildAb, RB)",
"controls_desc_clear_history": "Verlauf löschen (z.B.: X)",
"controls_desc_clear_history": "Mehrfachauswahl (Spieleliste) / Verlauf löschen (Verlaufsmenü) (z.B.: X)",
"controls_desc_history": "Verlauf öffnen (z.B.: H, Y)",
"controls_desc_filter": "Filter öffnen (z.B.: F, Select)",
"controls_desc_delete": "Zeichen löschen (z.B.: LT, Entf)",
@@ -173,7 +173,7 @@
"controls_confirm_select": "Bestätigen/Auswählen",
"controls_cancel_back": "Abbrechen/Zurück",
"controls_history": "Verlauf",
"controls_clear_history": "Verlauf löschen",
"controls_clear_history": "Mehrfachauswahl / Verlauf",
"controls_filter_search": "Filtern/Suchen",
"network_download_failed": "Download nach {0} Versuchen fehlgeschlagen",
"network_api_error": "Fehler bei der API-Anfrage, der Schlüssel könnte falsch sein: {0}",

View File

@@ -103,7 +103,7 @@
"controls_action_right": "Right",
"controls_action_page_up": "Previous Page",
"controls_action_page_down": "Next Page",
"controls_action_clear_history": "Clear History",
"controls_action_clear_history": "Multi-select / Clear History",
"controls_action_history": "History",
"controls_action_filter": "Filter",
"controls_action_delete": "Delete",
@@ -118,7 +118,7 @@
"controls_desc_right": "Navigate right",
"controls_desc_page_up": "Previous page/Fast scroll up (e.g. PageUp, LB)",
"controls_desc_page_down": "Next page/Fast scroll down (e.g. PageDown, RB)",
"controls_desc_clear_history": "Clear History (e.g. X)",
"controls_desc_clear_history": "Multi-select (game list) / Clear history (history menu) (e.g. X)",
"controls_desc_history": "Open history (e.g. H, Y)",
"controls_desc_filter": "Open filter (e.g. F, Select)",
"controls_desc_delete": "Delete character (e.g. LT, Delete)",
@@ -184,7 +184,7 @@
"controls_confirm_select": "Confirm/Select",
"controls_cancel_back": "Cancel/Back",
"controls_history": "History",
"controls_clear_history": "Clear History",
"controls_clear_history": "Multi-select / History",
"controls_filter_search": "Filter/Search",
"menu_symlink_option": "Symlink Option",

View File

@@ -104,7 +104,7 @@
"controls_action_right": "Derecha",
"controls_action_page_up": "Página anterior",
"controls_action_page_down": "Página siguiente",
"controls_action_clear_history": "Vaciar Historial",
"controls_action_clear_history": "Multi-selección / Vaciar historial",
"controls_action_history": "Historial",
"controls_action_filter": "Filtrar",
"controls_action_delete": "Eliminar",
@@ -119,7 +119,7 @@
"controls_desc_right": "Navegar a derecha",
"controls_desc_page_up": "Página anterior/Desplazamiento rápido arriba (ej: RePág, LB)",
"controls_desc_page_down": "Página siguiente/Desplazamiento rápido abajo (ej: AvPág, RB)",
"controls_desc_clear_history": "Borrar Historial (ej: X)",
"controls_desc_clear_history": "Multi-selección (lista juegos) / Vaciar historial (menú historial) (ej: X)",
"controls_desc_history": "Abrir historial (ej: H, Y)",
"controls_desc_filter": "Abrir filtro (ej: F, Select)",
"controls_desc_delete": "Eliminar carácter (ej: LT, Supr)",
@@ -174,7 +174,7 @@
"controls_confirm_select": "Confirmar/Seleccionar",
"controls_cancel_back": "Cancelar/Volver",
"controls_history": "Historial",
"controls_clear_history": "Vaciar historial",
"controls_clear_history": "Multi-selección / Historial",
"controls_filter_search": "Filtrar/Buscar",
"network_download_failed": "Error en la descarga tras {0} intentos",
"network_api_error": "Error en la solicitud de API, la clave puede ser incorrecta: {0}",

View File

@@ -100,7 +100,7 @@
"controls_action_right": "Droite",
"controls_action_page_up": "Page Précédente",
"controls_action_page_down": "Page Suivante",
"controls_action_clear_history": "Vider Historique",
"controls_action_clear_history": "Multi-sélection / Vider Historique",
"controls_action_history": "Historique",
"controls_action_filter": "Filtrer",
"controls_action_delete": "Supprimer",
@@ -116,7 +116,7 @@
"controls_desc_page_up": "Défilement Rapide - (ex: PageUp, LB)",
"controls_desc_page_down": "Défilement Rapide + (ex: PageDown, RB)",
"controls_desc_history": "Ouvrir l'historique (ex: H, Y)",
"controls_desc_clear_history": "Effacer Historique (ex: X)",
"controls_desc_clear_history": "Multi-sélection (liste jeux) / Vider historique (menu historique) (ex: X)",
"controls_desc_filter": "Mode Filtre : Ouvrir/Valider (ex: F, Select)",
"controls_desc_delete": "Mode Filtre : Supprimer caractère (ex: LT, Suppr)",
"controls_desc_space": "Mode Filtre : Ajouter espace (ex: RT, Espace)",
@@ -170,7 +170,7 @@
"controls_confirm_select": "Confirmer/Sélectionner",
"controls_cancel_back": "Annuler/Retour",
"controls_history": "Historique",
"controls_clear_history": "Effacer historique",
"controls_clear_history": "Multi-sélection / Historique",
"controls_filter_search": "Filtrer/Rechercher",
"network_download_failed": "Échec du téléchargement après {0} tentatives",
"network_api_error": "Erreur lors de la requête API, la clé est peut-être incorrecte: {0}",