From 3c36dd2e0219a39522d79eaa8a487090af5da58f Mon Sep 17 00:00:00 2001 From: skymike03 Date: Fri, 12 Sep 2025 03:41:59 +0200 Subject: [PATCH] v2.2.2.1 - add toggle for hiding premium systems needing an api key - add new font for better accessibility --- ports/RGSX/config.py | 91 +++++++++++++++++++++++++++--------- ports/RGSX/controls.py | 62 ++++++++++++++++++++---- ports/RGSX/display.py | 73 ++++++++++++++++++++++++----- ports/RGSX/languages/de.json | 7 ++- ports/RGSX/languages/en.json | 7 ++- ports/RGSX/languages/es.json | 7 ++- ports/RGSX/languages/fr.json | 7 ++- ports/RGSX/languages/it.json | 7 ++- ports/RGSX/languages/pt.json | 7 ++- ports/RGSX/rgsx_settings.py | 31 +++++++++++- 10 files changed, 251 insertions(+), 48 deletions(-) diff --git a/ports/RGSX/config.py b/ports/RGSX/config.py index b96cada..5cca260 100644 --- a/ports/RGSX/config.py +++ b/ports/RGSX/config.py @@ -13,7 +13,7 @@ except Exception: pygame = None # type: ignore # Version actuelle de l'application -app_version = "2.2.2.0" +app_version = "2.2.2.1" def get_application_root(): @@ -173,6 +173,16 @@ batch_download_indices = [] # File d'attente des indices de jeux à traiter en 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 +# --- Premium systems filtering --- +# Liste des marqueurs (substrings) indiquant qu'un système/plateforme requiert un compte premium ou une clé API. +# On teste la présence (case-insensitive) de ces marqueurs dans le nom du système (ex: "Microsoft Windows (1Fichier)"). +# Ajoutez librement d'autres valeurs (ex: 'RealDebrid', 'AllDebrid') si de futurs systèmes nécessitent un compte. +PREMIUM_HOST_MARKERS = [ + "1Fichier", +] +# Flag runtime contrôlant le masquage des systèmes premium dans le menu pause > games. +hide_premium_systems = False + # Indicateurs d'entrée (détectés au démarrage) joystick = False keyboard = False @@ -215,34 +225,71 @@ search_font = None small_font = None """Police pour les petits textes.""" -def init_font(): - """Initialise les polices après pygame.init().""" +# Liste des familles de polices disponibles (identifiants logiques) +FONT_FAMILIES = [ + "pixel", # police rétro Pixel-UniCode.ttf + "dejavu" # police plus standard lisible petites tailles +] +current_font_family_index = 0 # 0=pixel par défaut +# Après définition de FONT_FAMILIES et current_font_family_index, tenter de charger la famille depuis les settings +try: + from rgsx_settings import get_font_family # import tardif pour éviter dépendances circulaires lors de l'exécution initiale + saved_family = get_font_family() + if saved_family in FONT_FAMILIES: + current_font_family_index = FONT_FAMILIES.index(saved_family) +except Exception as e: + logging.getLogger(__name__).debug(f"Impossible de charger la famille de police sauvegardée: {e}") + +def init_font(): + """Initialise les polices après pygame.init() en fonction de la famille choisie.""" global font, progress_font, title_font, search_font, small_font font_scale = accessibility_settings.get("font_scale", 1.0) + + # Déterminer la famille sélectionnée + family_id = FONT_FAMILIES[current_font_family_index] if 0 <= current_font_family_index < len(FONT_FAMILIES) else "pixel" + + + def load_family(fam: str): + """Retourne un tuple (font, title_font, search_font, progress_font, small_font).""" + base_size = 36 + title_size = 48 + search_size = 48 + small_size = 28 + if fam == "pixel": + path = os.path.join(APP_FOLDER, "assets", "Pixel-UniCode.ttf") + f = pygame.font.Font(path, int(base_size * font_scale)) + t = pygame.font.Font(path, int(title_size * font_scale)) + s = pygame.font.Font(path, int(search_size * font_scale)) + p = pygame.font.Font(path, int(base_size * font_scale)) + sm = pygame.font.Font(path, int(small_size * font_scale)) + return f, t, s, p, sm + elif fam == "dejavu": + try: + f = pygame.font.SysFont("dejavusans", int(base_size * font_scale)) + t = pygame.font.SysFont("dejavusans", int(title_size * font_scale)) + s = pygame.font.SysFont("dejavusans", int(search_size * font_scale)) + p = pygame.font.SysFont("dejavusans", int(base_size * font_scale)) + sm = pygame.font.SysFont("dejavusans", int(small_size * font_scale)) + except Exception: + f = pygame.font.SysFont("dejavu sans", int(base_size * font_scale)) + t = pygame.font.SysFont("dejavu sans", int(title_size * font_scale)) + s = pygame.font.SysFont("dejavu sans", int(search_size * font_scale)) + p = pygame.font.SysFont("dejavu sans", int(base_size * font_scale)) + sm = pygame.font.SysFont("dejavu sans", int(small_size * font_scale)) + return f, t, s, p, sm + + try: - font_path = os.path.join(APP_FOLDER, "assets", "Pixel-UniCode.ttf") - font = pygame.font.Font(font_path, int(36 * font_scale)) - title_font = pygame.font.Font(font_path, int(48 * font_scale)) - search_font = pygame.font.Font(font_path, int(48 * font_scale)) - progress_font = pygame.font.Font(font_path, int(36 * font_scale)) - small_font = pygame.font.Font(font_path, int(28 * font_scale)) - logger.debug(f"Polices Pixel-UniCode initialisées (font_scale: {font_scale})") + font, title_font, search_font, progress_font, small_font = load_family(family_id) + logger.debug(f"Polices initialisées (famille={family_id}, scale={font_scale})") except Exception as e: + logger.error(f"Erreur chargement famille {family_id}: {e}, fallback dejavu") try: - font = pygame.font.SysFont("arial", int(48 * font_scale)) - title_font = pygame.font.SysFont("arial", int(60 * font_scale)) - search_font = pygame.font.SysFont("arial", int(60 * font_scale)) - progress_font = pygame.font.SysFont("arial", int(36 * font_scale)) - small_font = pygame.font.SysFont("arial", int(28 * font_scale)) - logger.debug(f"Polices Arial initialisées (font_scale: {font_scale})") + font, title_font, search_font, progress_font, small_font = load_family("dejavu") except Exception as e2: - logger.error(f"Erreur lors de l'initialisation des polices : {e2}") - font = None - progress_font = None - title_font = None - search_font = None - small_font = None + logger.error(f"Erreur fallback dejavu: {e2}") + font = title_font = search_font = progress_font = small_font = None # Indique si une vérification/installation des mises à jour a déjà été effectuée au démarrage update_checked = False diff --git a/ports/RGSX/controls.py b/ports/RGSX/controls.py index 0ae1702..98157c1 100644 --- a/ports/RGSX/controls.py +++ b/ports/RGSX/controls.py @@ -1157,7 +1157,7 @@ def handle_controls(event, sources, joystick, screen): # Sous-menu Display elif config.menu_state == "pause_display_menu": sel = getattr(config, 'pause_display_selection', 0) - total = 6 # layout, font, unsupported, unknown, filter, back + total = 8 # layout, font size, font family, unsupported, unknown, hide premium, filter, back if is_input_matched(event, "up"): config.pause_display_selection = (sel - 1) % total config.needs_redraw = True @@ -1211,8 +1211,43 @@ def handle_controls(event, sources, joystick, screen): except Exception as e: logger.error(f"Erreur init polices: {e}") config.needs_redraw = True - # 2 unsupported toggle + # 2 font family cycle elif sel == 2 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")): + try: + from rgsx_settings import get_font_family, set_font_family + families = getattr(config, 'FONT_FAMILIES', ["pixel"]) or ["pixel"] + current = get_font_family() + try: + fam_index = families.index(current) + except ValueError: + fam_index = 0 + direction = 1 if (is_input_matched(event, "right") or is_input_matched(event, "confirm")) else -1 + fam_index = (fam_index + direction) % len(families) + new_family = families[fam_index] + set_font_family(new_family) + config.current_font_family_index = fam_index + init_font_func = getattr(config, 'init_font', None) + if callable(init_font_func): + init_font_func() + # popup + if _: + try: + # Vérifier proprement la présence de la clé i18n + fmt = _("popup_font_family_changed") if 'popup_font_family_changed' in getattr(_, 'translations', {}) else None + except Exception: + fmt = None + if fmt: + config.popup_message = fmt.format(new_family) + else: + config.popup_message = f"Font: {new_family}" + else: + config.popup_message = f"Font: {new_family}" + config.popup_timer = 2500 + config.needs_redraw = True + except Exception as e: + logger.error(f"Erreur changement font family: {e}") + # 3 unsupported toggle + elif sel == 3 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")): try: from rgsx_settings import get_show_unsupported_platforms, set_show_unsupported_platforms current = get_show_unsupported_platforms() @@ -1224,8 +1259,8 @@ def handle_controls(event, sources, joystick, screen): config.needs_redraw = True except Exception as e: logger.error(f"Erreur toggle unsupported: {e}") - # 3 allow unknown extensions - elif sel == 3 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")): + # 4 allow unknown extensions + elif sel == 4 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")): try: from rgsx_settings import get_allow_unknown_extensions, set_allow_unknown_extensions current = get_allow_unknown_extensions() @@ -1235,15 +1270,26 @@ def handle_controls(event, sources, joystick, screen): config.needs_redraw = True except Exception as e: logger.error(f"Erreur toggle allow_unknown_extensions: {e}") - # 4 filter platforms - elif sel == 4 and (is_input_matched(event, "confirm") or is_input_matched(event, "right")): + # 5 hide premium systems + elif sel == 5 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")): + try: + from rgsx_settings import get_hide_premium_systems, set_hide_premium_systems + cur = get_hide_premium_systems() + new_val = set_hide_premium_systems(not cur) + config.popup_message = ("Premium hidden" if new_val else "Premium visible") if _ is None else (_("popup_hide_premium_on") if new_val else _("popup_hide_premium_off")) + config.popup_timer = 2500 + config.needs_redraw = True + except Exception as e: + logger.error(f"Erreur toggle hide_premium_systems: {e}") + # 6 filter platforms + elif sel == 6 and (is_input_matched(event, "confirm") or is_input_matched(event, "right")): config.filter_return_to = "pause_display_menu" config.menu_state = "filter_platforms" config.selected_filter_index = 0 config.filter_platforms_scroll_offset = 0 config.needs_redraw = True - # 5 back - elif sel == 5 and (is_input_matched(event, "confirm")): + # 7 back + elif sel == 7 and (is_input_matched(event, "confirm")): config.menu_state = "pause_menu" config.last_state_change_time = pygame.time.get_ticks() config.needs_redraw = True diff --git a/ports/RGSX/display.py b/ports/RGSX/display.py index 789f5fd..9908da6 100644 --- a/ports/RGSX/display.py +++ b/ports/RGSX/display.py @@ -475,8 +475,28 @@ def draw_platform_grid(screen): x_positions = [margin_left + col_width * i + col_width // 2 for i in range(num_cols)] y_positions = [margin_top + row_height * i + row_height // 2 for i in range(num_rows)] - # Affichage des indicateurs de page si nécessaire - total_pages = (len(config.platforms) + systems_per_page - 1) // systems_per_page + # Filtrage éventuel des systèmes premium selon réglage + try: + from rgsx_settings import get_hide_premium_systems + hide_premium = get_hide_premium_systems() + except Exception: + hide_premium = False + premium_markers = getattr(config, 'PREMIUM_HOST_MARKERS', []) + if hide_premium and premium_markers: + visible_platforms = [p for p in config.platforms if not any(m.lower() in p.lower() for m in premium_markers)] + else: + visible_platforms = list(config.platforms) + + # Ajuster selected_platform et current_platform/page si liste réduite + if config.selected_platform >= len(visible_platforms): + config.selected_platform = max(0, len(visible_platforms) - 1) + # Recalcule la page courante en fonction de selected_platform + systems_per_page = num_cols * num_rows + if systems_per_page <= 0: + systems_per_page = 1 + config.current_page = config.selected_platform // systems_per_page if systems_per_page else 0 + + total_pages = (len(visible_platforms) + systems_per_page - 1) // systems_per_page if total_pages > 1: page_indicator_text = _("platform_page").format(config.current_page + 1, total_pages) page_indicator = config.small_font.render(page_indicator_text, True, THEME_COLORS["text"]) @@ -490,7 +510,7 @@ def draw_platform_grid(screen): # Pré-calcul des images pour optimiser le rendu start_idx = config.current_page * systems_per_page for idx in range(start_idx, start_idx + systems_per_page): - if idx >= len(config.platforms): + if idx >= len(visible_platforms): break grid_idx = idx - start_idx row = grid_idx // num_cols @@ -504,12 +524,16 @@ def draw_platform_grid(screen): scale = scale_base + pulse if is_selected else scale_base # Récupération robuste du dict via nom - display_name = config.platforms[idx] + display_name = visible_platforms[idx] platform_dict = getattr(config, 'platform_dict_by_name', {}).get(display_name) if not platform_dict: # Fallback index brut - if idx < len(config.platform_dicts): - platform_dict = config.platform_dicts[idx] + # Chercher en parcourant platform_dicts pour correspondance nom + for pd in config.platform_dicts: + n = pd.get("platform_name") or pd.get("platform") + if n == display_name: + platform_dict = pd + break else: continue platform_id = platform_dict.get("platform_name") or platform_dict.get("platform") or display_name @@ -1351,10 +1375,18 @@ def draw_language_menu(screen): text_rect = text_surface.get_rect(center=(button_x + button_width // 2, button_y + button_height // 2)) screen.blit(text_surface, text_rect) - # Instructions + # Instructions (placer juste au-dessus du footer sans chevauchement) instruction_text = _("language_select_instruction") instruction_surface = config.small_font.render(instruction_text, True, THEME_COLORS["text"]) - instruction_rect = instruction_surface.get_rect(center=(config.screen_width // 2, config.screen_height - 50)) + footer_reserved = 72 # hauteur approximative footer (barre bas) + marge + bottom_margin = 12 + instruction_y = config.screen_height - footer_reserved - bottom_margin + # Empêcher un chevauchement avec les derniers boutons si espace réduit + last_button_bottom = start_y + (len(available_languages) - 1) * (button_height + button_spacing) + button_height + min_gap = 16 + if instruction_y - last_button_bottom < min_gap: + instruction_y = last_button_bottom + min_gap + instruction_rect = instruction_surface.get_rect(center=(config.screen_width // 2, instruction_y)) screen.blit(instruction_surface, instruction_rect) def draw_display_menu(screen): @@ -1499,7 +1531,12 @@ def draw_pause_controls_menu(screen, selected_index): _draw_submenu_generic(screen, _("menu_controls") if _ else "Controls", options, selected_index) def draw_pause_display_menu(screen, selected_index): - from rgsx_settings import get_show_unsupported_platforms, get_allow_unknown_extensions + from rgsx_settings import ( + get_show_unsupported_platforms, + get_allow_unknown_extensions, + get_hide_premium_systems, + get_font_family + ) # Layout label layouts = [(3,3),(3,4),(4,3),(4,4)] try: @@ -1513,6 +1550,16 @@ def draw_pause_display_menu(screen, selected_index): cur_idx = getattr(config, 'current_font_scale_index', 1) font_value = f"{opts[cur_idx]}x" font_txt = f"{_('submenu_display_font_size') if _ else 'Font Size'}: < {font_value} >" + # Font family + current_family = get_font_family() + # Nom user-friendly + family_map = { + "pixel": "Pixel", + "dejavu": "DejaVu Sans" + } + fam_label = family_map.get(current_family, current_family) + font_family_txt = f"{_('submenu_display_font_family') if _ else 'Font'}: < {fam_label} >" + unsupported = get_show_unsupported_platforms() status_unsupported = _('status_on') if unsupported else _('status_off') # Construire label sans statut pour insérer les chevrons proprement @@ -1527,9 +1574,14 @@ def draw_pause_display_menu(screen, selected_index): if '{status}' in raw_unknown_label: raw_unknown_label = raw_unknown_label.split('{status}')[0].rstrip(' :') unknown_txt = f"{raw_unknown_label}: < {status_unknown} >" + # Hide premium systems + hide_premium = get_hide_premium_systems() + status_hide_premium = _('status_on') if hide_premium else _('status_off') + hide_premium_label = _('menu_hide_premium_systems') if _ else 'Hide Premium systems' + hide_premium_txt = f"{hide_premium_label}: < {status_hide_premium} >" filter_txt = _("submenu_display_filter_platforms") if _ else "Filter Platforms" back_txt = _("menu_back") if _ else "Back" - options = [layout_txt, font_txt, unsupported_txt, unknown_txt, filter_txt, back_txt] + options = [layout_txt, font_txt, font_family_txt, unsupported_txt, unknown_txt, hide_premium_txt, filter_txt, back_txt] _draw_submenu_generic(screen, _("menu_display"), options, selected_index) def draw_pause_games_menu(screen, selected_index): @@ -1538,7 +1590,6 @@ def draw_pause_games_menu(screen, selected_index): source_label = _("games_source_rgsx") if mode == "rgsx" else _("games_source_custom") source_txt = f"{_('menu_games_source_prefix')}: < {source_label} >" update_txt = _("menu_redownload_cache") - # Première entrée: Historique des téléchargements (utiliser la clé menu_history) history_txt = _("menu_history") if _ else "History" back_txt = _("menu_back") if _ else "Back" options = [history_txt, source_txt, update_txt, back_txt] diff --git a/ports/RGSX/languages/de.json b/ports/RGSX/languages/de.json index 32c1e51..97d378b 100644 --- a/ports/RGSX/languages/de.json +++ b/ports/RGSX/languages/de.json @@ -149,5 +149,10 @@ "api_keys_status_title": "Status der API-Schlüssel", "menu_games": "Spiele", "api_keys_hint_manage": "Legen Sie Ihre Schlüssel in {path}", - "api_key_empty_suffix": "leer" + "api_key_empty_suffix": "leer", + "menu_hide_premium_systems": "Premium-Systeme ausblenden", + "popup_hide_premium_on": "Premium-Systeme ausgeblendet", + "popup_hide_premium_off": "Premium-Systeme sichtbar" + ,"submenu_display_font_family": "Schrift" + ,"popup_font_family_changed": "Schrift geändert: {0}" } \ No newline at end of file diff --git a/ports/RGSX/languages/en.json b/ports/RGSX/languages/en.json index fda30b3..eab9ef0 100644 --- a/ports/RGSX/languages/en.json +++ b/ports/RGSX/languages/en.json @@ -149,5 +149,10 @@ "api_keys_status_title": "API Keys Status", "menu_games": "Games", "api_keys_hint_manage": "Put your keys in {path}", - "api_key_empty_suffix": "empty" + "api_key_empty_suffix": "empty", + "menu_hide_premium_systems": "Hide Premium systems" + ,"popup_hide_premium_on": "Premium systems hidden" + ,"popup_hide_premium_off": "Premium systems visible" + ,"submenu_display_font_family": "Font" + ,"popup_font_family_changed": "Font changed: {0}" } \ No newline at end of file diff --git a/ports/RGSX/languages/es.json b/ports/RGSX/languages/es.json index c437d12..641b3bd 100644 --- a/ports/RGSX/languages/es.json +++ b/ports/RGSX/languages/es.json @@ -149,5 +149,10 @@ "api_keys_status_title": "Estado de las claves API", "menu_games": "Juegos", "api_keys_hint_manage": "Coloca tus claves en {path}", - "api_key_empty_suffix": "vacío" + "api_key_empty_suffix": "vacío", + "menu_hide_premium_systems": "Ocultar sistemas Premium", + "popup_hide_premium_on": "Sistemas Premium ocultos", + "popup_hide_premium_off": "Sistemas Premium visibles" + ,"submenu_display_font_family": "Fuente" + ,"popup_font_family_changed": "Fuente cambiada: {0}" } \ No newline at end of file diff --git a/ports/RGSX/languages/fr.json b/ports/RGSX/languages/fr.json index 1033d97..94b072d 100644 --- a/ports/RGSX/languages/fr.json +++ b/ports/RGSX/languages/fr.json @@ -149,5 +149,10 @@ "api_keys_status_title": "Statut des clés API", "menu_games": "Jeux", "api_keys_hint_manage": "Placez vos clés dans {path}", - "api_key_empty_suffix": "vide" + "api_key_empty_suffix": "vide", + "menu_hide_premium_systems": "Masquer systèmes Premium", + "popup_hide_premium_on": "Systèmes Premium masqués", + "popup_hide_premium_off": "Systèmes Premium visibles" + ,"submenu_display_font_family": "Police" + ,"popup_font_family_changed": "Police changée : {0}" } \ No newline at end of file diff --git a/ports/RGSX/languages/it.json b/ports/RGSX/languages/it.json index e6e73c8..c1835ab 100644 --- a/ports/RGSX/languages/it.json +++ b/ports/RGSX/languages/it.json @@ -149,5 +149,10 @@ "api_keys_status_title": "Stato delle chiavi API", "menu_games": "Giochi", "api_keys_hint_manage": "Metti le tue chiavi in {path}", - "api_key_empty_suffix": "vuoto" + "api_key_empty_suffix": "vuoto", + "menu_hide_premium_systems": "Nascondi sistemi Premium", + "popup_hide_premium_on": "Sistemi Premium nascosti", + "popup_hide_premium_off": "Sistemi Premium visibili" + ,"submenu_display_font_family": "Font" + ,"popup_font_family_changed": "Font cambiato: {0}" } \ No newline at end of file diff --git a/ports/RGSX/languages/pt.json b/ports/RGSX/languages/pt.json index 5537094..9a6c692 100644 --- a/ports/RGSX/languages/pt.json +++ b/ports/RGSX/languages/pt.json @@ -149,5 +149,10 @@ "api_keys_status_title": "Status das chaves API", "menu_games": "Jogos", "api_keys_hint_manage": "Coloque suas chaves em {path}", - "api_key_empty_suffix": "vazio" + "api_key_empty_suffix": "vazio", + "menu_hide_premium_systems": "Ocultar sistemas Premium", + "popup_hide_premium_on": "Sistemas Premium ocultos", + "popup_hide_premium_off": "Sistemas Premium visíveis" + ,"submenu_display_font_family": "Fonte" + ,"popup_font_family_changed": "Fonte alterada: {0}" } \ No newline at end of file diff --git a/ports/RGSX/rgsx_settings.py b/ports/RGSX/rgsx_settings.py index c02ce44..b41411d 100644 --- a/ports/RGSX/rgsx_settings.py +++ b/ports/RGSX/rgsx_settings.py @@ -56,7 +56,8 @@ def load_rgsx_settings(): "font_scale": 1.0 }, "display": { - "grid": "3x4" + "grid": "3x4", + "font_family": "pixel" }, "symlink": { "enabled": False, @@ -228,6 +229,22 @@ def set_allow_unknown_extensions(enabled: bool) -> bool: save_rgsx_settings(settings) return settings["allow_unknown_extensions"] +# ----------------------- Hide premium systems toggle ----------------------- # + +def get_hide_premium_systems(settings=None) -> bool: + """Retourne True si le masquage des systèmes premium est activé.""" + if settings is None: + settings = load_rgsx_settings() + return bool(settings.get("hide_premium_systems", False)) + + +def set_hide_premium_systems(enabled: bool) -> bool: + """Active/désactive le masquage des systèmes premium et sauvegarde.""" + settings = load_rgsx_settings() + settings["hide_premium_systems"] = bool(enabled) + save_rgsx_settings(settings) + return settings["hide_premium_systems"] + # ----------------------- Display layout (grid) ----------------------- # def get_display_grid(settings=None): @@ -252,3 +269,15 @@ def set_display_grid(cols: int, rows: int): disp["grid"] = f"{cols}x{rows}" save_rgsx_settings(settings) return cols, rows + +def get_font_family(settings=None): + if settings is None: + settings = load_rgsx_settings() + return settings.get("display", {}).get("font_family", "pixel") + +def set_font_family(family: str): + settings = load_rgsx_settings() + disp = settings.setdefault("display", {}) + disp["font_family"] = family + save_rgsx_settings(settings) + return family