From 8cdab88446fcc09d0279d03faa5a40ec1ff29947 Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 08:15:50 +0000 Subject: [PATCH 01/10] Bump version to 2.0-dev --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 719a69d..9f30793 100644 --- a/main.py +++ b/main.py @@ -281,7 +281,7 @@ def generate_battery_report(self) -> str: return f"Erreur : {str(e)}" # --- Configuration de l'application --- -APP_VERSION = "1.0" +APP_VERSION = "2.0-dev" UPDATE_URL = "https://api.github.com/repos/Unfeeling3573/RepairToolkit/releases/latest" # Remplacer TON_PSEUDO par ton vrai pseudo GitHub # --- 2. Interface Graphique (Le Frontend) --- From 252e465659c250bc432465a1631f52245cbdecd4 Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 08:20:08 +0000 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20Pr=C3=A9paration=20de=20la=20V2?= =?UTF-8?q?=20et=20mise=20=C3=A0=20jour=20du=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 39cde85..f3ecd67 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: Build Windows EXE on: push: - branches: [main] + branches: [main, v2-dev] workflow_dispatch: permissions: From faea73d268dd94e296568de3c7ff04ce63e459ae Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 10:38:07 +0200 Subject: [PATCH 03/10] Improve error message for update check failure --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 9f30793..cab3a4f 100644 --- a/main.py +++ b/main.py @@ -494,7 +494,7 @@ def thread_target(): else: self.log_message("Vous utilisez déjà la dernière version disponible.", "success") except Exception as e: - self.log_message("Impossible de vérifier les mises à jour. Le repo est-il public ?", "error") + self.log_message(f"Erreur de mise à jour : {str(e)}\nAvez-vous publié une 'Release' sur GitHub ?", "error") self.btn_update.configure(state="normal") threading.Thread(target=thread_target, daemon=True).start() From 223cd422bbcdd85afee304b5f4e94de61ce07855 Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 10:41:12 +0200 Subject: [PATCH 04/10] Implement SSL context for secure requests on macOS Add SSL context to bypass certificate verification on macOS. --- main.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index cab3a4f..5704a3b 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,7 @@ import json import webbrowser from fpdf import FPDF +import ssl # Importation conditionnelle pour éviter que le code ne crashe sur Mac if platform.system() == "Windows": @@ -482,8 +483,13 @@ def check_update(self): def thread_target(): try: + # Contournement de l'erreur de certificat SSL (très fréquente sur macOS) + ssl_context = ssl.create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + req = urllib.request.Request(UPDATE_URL, headers={'User-Agent': 'RepairToolkit'}) - with urllib.request.urlopen(req, timeout=5) as response: + with urllib.request.urlopen(req, timeout=5, context=ssl_context) as response: data = json.loads(response.read().decode()) latest_version = data.get("tag_name", "").replace("v", "") From 29b6f5c693b9042c3e6e80a0e4312bbec979ba4c Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 10:50:14 +0200 Subject: [PATCH 05/10] Implement version check from GitHub source Added regex extraction for remote version check. --- main.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/main.py b/main.py index 5704a3b..3469be5 100644 --- a/main.py +++ b/main.py @@ -10,6 +10,7 @@ import urllib.request import json import webbrowser +import re from fpdf import FPDF import ssl @@ -283,7 +284,6 @@ def generate_battery_report(self) -> str: # --- Configuration de l'application --- APP_VERSION = "2.0-dev" -UPDATE_URL = "https://api.github.com/repos/Unfeeling3573/RepairToolkit/releases/latest" # Remplacer TON_PSEUDO par ton vrai pseudo GitHub # --- 2. Interface Graphique (Le Frontend) --- class RepairApp(ctk.CTk): @@ -488,19 +488,27 @@ def thread_target(): ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE - req = urllib.request.Request(UPDATE_URL, headers={'User-Agent': 'RepairToolkit'}) - with urllib.request.urlopen(req, timeout=5, context=ssl_context) as response: - data = json.loads(response.read().decode()) - latest_version = data.get("tag_name", "").replace("v", "") - - if latest_version and latest_version != APP_VERSION: - if messagebox.askyesno("Mise à jour disponible", f"La version {latest_version} est disponible !\n\nVous utilisez actuellement la version {APP_VERSION}.\nVoulez-vous ouvrir la page de téléchargement ?"): - webbrowser.open(data.get("html_url", "")) - self.log_message(f"Ouverture du navigateur pour télécharger la v{latest_version}.", "success") + # Lecture directe du code source sur GitHub (l'astuce 'nocache' force GitHub à donner la version la plus récente) + RAW_URL = f"https://raw.githubusercontent.com/Unfeeling3573/RepairToolkit/v2-dev/main.py?nocache={int(time.time())}" + req = urllib.request.Request(RAW_URL, headers={'User-Agent': 'RepairToolkit'}) + + with urllib.request.urlopen(req, timeout=8, context=ssl_context) as response: + content = response.read().decode('utf-8') + + # Extraction intelligente du numéro de version dans le code distant + match = re.search(r'APP_VERSION\s*=\s*["\']([^"\']+)["\']', content) + if match: + remote_version = match.group(1) + if remote_version != APP_VERSION: + if messagebox.askyesno("Mise à jour disponible", f"Une nouveauté a été détectée sur GitHub (v{remote_version}) !\n\nVous avez la v{APP_VERSION}.\nVoulez-vous ouvrir la page du projet ?"): + webbrowser.open("https://github.com/Unfeeling3573/RepairToolkit") + self.log_message("Ouverture de GitHub pour la mise à jour.", "success") + else: + self.log_message("Vous utilisez déjà la dernière version.", "success") else: - self.log_message("Vous utilisez déjà la dernière version disponible.", "success") + self.log_message("Impossible de lire la version sur GitHub.", "error") except Exception as e: - self.log_message(f"Erreur de mise à jour : {str(e)}\nAvez-vous publié une 'Release' sur GitHub ?", "error") + self.log_message(f"Erreur réseau : {str(e)}", "error") self.btn_update.configure(state="normal") threading.Thread(target=thread_target, daemon=True).start() From b318f51604d3344ba8fab15cfc4202d797fff070 Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 08:57:38 +0000 Subject: [PATCH 06/10] =?UTF-8?q?feat:=20Ajout=20onglet=20optimisation=20e?= =?UTF-8?q?t=20anti-t=C3=A9l=C3=A9m=C3=A9trie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 9f30793..88d1bf2 100644 --- a/main.py +++ b/main.py @@ -280,8 +280,54 @@ def generate_battery_report(self) -> str: except Exception as e: return f"Erreur : {str(e)}" + def reset_network(self) -> str: + if not self.is_windows: + time.sleep(2) + return "[Mac Mode] Simulation : Carte réseau réinitialisée (Winsock/IP)." + try: + res1 = self.execute_command(["netsh", "winsock", "reset"]) + self.execute_command(["ipconfig", "/renew"]) + return f"🌐 Réseau réinitialisé avec succès.\n{res1}\n(Un redémarrage peut être nécessaire)" + except Exception as e: + return f"Erreur lors de la réinitialisation réseau : {str(e)}" + + def get_detailed_sysinfo(self) -> str: + if not self.is_windows: + time.sleep(1) + return "[Mac Mode] Simulation :\nCarte Mère : Apple M-Series\nGPU : Apple Silicon 16-core" + try: + mobo = self.execute_command(["powershell", "-Command", "(Get-WmiObject win32_baseboard).Product"]).strip() + gpu = self.execute_command(["powershell", "-Command", "(Get-WmiObject win32_VideoController).Name"]).strip() + return f"📊 Informations Détaillées :\nCarte Mère : {mobo}\nCarte Graphique : {gpu}" + except Exception as e: + return f"Erreur lors de la récupération des infos : {str(e)}" + + def disable_telemetry(self) -> str: + if not self.is_windows: + time.sleep(2) + return "[Mac Mode] Simulation : Télémétrie et collecte de données désactivées." + try: + # Désactiver le service de télémétrie Windows + self.execute_command(["sc", "config", "DiagTrack", "start=", "disabled"]) + self.execute_command(["sc", "stop", "DiagTrack"]) + # Clé de registre pour bloquer la télémétrie + self.execute_command(["reg", "add", "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\DataCollection", "/v", "AllowTelemetry", "/t", "REG_DWORD", "/d", "0", "/f"]) + return "🛑 Télémétrie Windows désactivée avec succès (Service DiagTrack arrêté)." + except Exception as e: + return f"Erreur lors de la désactivation de la télémétrie : {str(e)}" + + def disable_background_apps(self) -> str: + if not self.is_windows: + time.sleep(1) + return "[Mac Mode] Simulation : Applications en arrière-plan bloquées." + try: + self.execute_command(["reg", "add", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\BackgroundAccessApplications", "/v", "GlobalUserDisabled", "/t", "REG_DWORD", "/d", "1", "/f"]) + return "🛑 Exécution des applications en arrière-plan désactivée pour économiser les ressources." + except Exception as e: + return f"Erreur lors de la désactivation des apps en arrière-plan : {str(e)}" + # --- Configuration de l'application --- -APP_VERSION = "2.0-dev" +APP_VERSION = "2.0-dev1" UPDATE_URL = "https://api.github.com/repos/Unfeeling3573/RepairToolkit/releases/latest" # Remplacer TON_PSEUDO par ton vrai pseudo GitHub # --- 2. Interface Graphique (Le Frontend) --- @@ -325,10 +371,15 @@ def __init__(self): self.btn_update = ctk.CTkButton(self.sidebar_frame, text="🔄 Mises à jour", command=self.check_update, fg_color="transparent", border_width=1, text_color=("gray10", "#DCE4EE")) self.btn_update.grid(row=4, column=0, padx=20, pady=10) + # Switch Thème Clair/Sombre + self.appearance_mode_switch = ctk.CTkSwitch(self.sidebar_frame, text="Mode Sombre", command=self.change_appearance_mode_event) + self.appearance_mode_switch.grid(row=5, column=0, padx=20, pady=20) + self.appearance_mode_switch.select() # Coché par défaut (Sombre) + # Indicateur de version self.version_label = ctk.CTkLabel(self.sidebar_frame, text=f"v{APP_VERSION} Pro Edition", font=ctk.CTkFont(size=10), text_color="#555555") - self.version_label.grid(row=6, column=0, pady=20, sticky="s") - self.sidebar_frame.grid_rowconfigure(5, weight=1) + self.version_label.grid(row=7, column=0, pady=20, sticky="s") + self.sidebar_frame.grid_rowconfigure(6, weight=1) # Raccourcis clavier (UX) self.bind("", self.clear_logs) @@ -339,12 +390,14 @@ def __init__(self): self.tabview.grid(row=0, column=1, padx=20, pady=(10, 5), sticky="nsew") self.tab_sys = self.tabview.add("🛠️ Système") + self.tab_opti = self.tabview.add("⚡ Optimisation") self.tab_sec = self.tabview.add("🛡️ Sécurité") self.tab_net = self.tabview.add("🌐 Réseau & Nettoyage") self.tab_utils = self.tabview.add("🧰 Utilitaires") # Layout des onglets self.tab_sys.grid_columnconfigure((0, 1, 2), weight=1) + self.tab_opti.grid_columnconfigure((0, 1), weight=1) self.tab_sec.grid_columnconfigure((0, 1, 2), weight=1) self.tab_net.grid_columnconfigure((0, 1), weight=1) self.tab_utils.grid_columnconfigure((0, 1), weight=1) @@ -355,6 +408,9 @@ def __init__(self): self.btn_restore = self.create_action_card(self.tab_sys, 0, 2, "3. Point Restauration", "Crée une sauvegarde système (recommandé avant réparation).", self.start_restore_point) self.btn_explorer = self.create_action_card(self.tab_sys, 1, 0, "Réparer Explorateur", "Redémarre l'explorateur Windows (Menu Démarrer bloqué, icônes invisibles).", self.start_repair_explorer, colspan=3) + self.btn_telemetry = self.create_action_card(self.tab_opti, 0, 0, "Désactiver Télémétrie", "Bloque la collecte de données et le pistage par Microsoft (DiagTrack).", self.start_disable_telemetry, "#2C3E50", "#1A252F") + self.btn_bg_apps = self.create_action_card(self.tab_opti, 0, 1, "Bloquer Apps Arrière-plan", "Empêche les applications inutiles de tourner en tâche de fond.", self.start_disable_background_apps, "#2C3E50", "#1A252F") + self.btn_malware = self.create_action_card(self.tab_sec, 0, 0, "Scan Malware", "Recherche des scripts et exécutables cachés dans Temp et Downloads.", self.start_malware_scan, "#8B0000", "#5C0000") self.btn_pdf_trace = self.create_action_card(self.tab_sec, 0, 1, "Traces PDF Vérolé", "Détecte les doubles extensions et les faux PDF laissés par les virus.", self.start_pdf_trace_scan, "#8B0000", "#5C0000") self.btn_registry = self.create_action_card(self.tab_sec, 0, 2, "Scan Registre", "Vérifie les clés Run/RunOnce pour débusquer les virus au démarrage.", self.start_registry_scan, "#8B0000", "#5C0000") @@ -367,9 +423,12 @@ def __init__(self): self.btn_temp = self.create_action_card(self.tab_net, 1, 0, "Nettoyage Temp", "Libère de l'espace disque en supprimant les fichiers temporaires inutiles.", self.start_clean_temp) self.btn_downloads = self.create_action_card(self.tab_net, 1, 1, "Vider Téléchargements", "Supprime définitivement le contenu du dossier Téléchargements.", self.start_clean_downloads) + self.btn_net_reset = self.create_action_card(self.tab_net, 2, 0, "Réinitialiser Réseau", "Renouvelle l'adresse IP et réinitialise la carte réseau (Winsock).", self.start_network_reset, colspan=2) + self.btn_license = self.create_action_card(self.tab_utils, 0, 0, "Clé de Licence", "Récupère la clé de produit Windows originale intégrée à la carte mère.", self.start_license_check) self.btn_disk = self.create_action_card(self.tab_utils, 0, 1, "Santé des Disques", "Vérifie l'état de santé S.M.A.R.T de vos disques durs et SSD.", self.start_disk_check) self.btn_battery = self.create_action_card(self.tab_utils, 1, 0, "Rapport Batterie", "Génère un rapport HTML complet sur l'état et l'usure de votre batterie.", self.start_battery_report, colspan=2) + self.btn_sysinfo = self.create_action_card(self.tab_utils, 2, 0, "Infos Système", "Affiche des informations matérielles détaillées (Carte Mère, GPU).", self.start_detailed_sysinfo, colspan=2) # -- Zone de Statut et Barre de Progression (Nouvelle Feature UX) -- self.status_frame = ctk.CTkFrame(self, height=30, fg_color="transparent") @@ -531,6 +590,12 @@ def thread_target(): threading.Thread(target=thread_target, daemon=True).start() # --- Lancement des tâches --- + def change_appearance_mode_event(self): + if self.appearance_mode_switch.get() == 1: + ctk.set_appearance_mode("dark") + else: + ctk.set_appearance_mode("light") + def start_sfc_scan(self): self.run_async_task(self.btn_sfc, self.repair_manager.run_sfc_scan, "Démarrage du scan SFC (Vérification des fichiers système)...") @@ -578,6 +643,19 @@ def start_kill_switch(self): def start_hosts_restore(self): self.run_async_task(self.btn_hosts, self.repair_manager.check_and_restore_hosts, "Restauration du fichier HOSTS de Windows...") + def start_network_reset(self): + self.run_async_task(self.btn_net_reset, self.repair_manager.reset_network, "Réinitialisation matérielle de la carte réseau...") + + def start_detailed_sysinfo(self): + self.run_async_task(self.btn_sysinfo, self.repair_manager.get_detailed_sysinfo, "Analyse du matériel en cours...") + + def start_disable_telemetry(self): + if messagebox.askyesno("Optimisation", "Désactiver la télémétrie bloquera l'envoi de vos données de diagnostic à Microsoft.\n\nVoulez-vous continuer ?"): + self.run_async_task(self.btn_telemetry, self.repair_manager.disable_telemetry, "Désactivation de la télémétrie Windows (DiagTrack)...") + + def start_disable_background_apps(self): + self.run_async_task(self.btn_bg_apps, self.repair_manager.disable_background_apps, "Désactivation globale des applications en arrière-plan...") + # Point d'entrée de l'application if __name__ == "__main__": app = RepairApp() From 323986358763b9de8695e4725820a3f60ad381f1 Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 09:11:41 +0000 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20Ajout=20d'un=20outil=20pour=20d?= =?UTF-8?q?=C3=A9sactiver=20OneDrive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index 39d0b9c..e7d8d5e 100644 --- a/main.py +++ b/main.py @@ -328,8 +328,22 @@ def disable_background_apps(self) -> str: except Exception as e: return f"Erreur lors de la désactivation des apps en arrière-plan : {str(e)}" + def disable_onedrive(self) -> str: + if not self.is_windows: + time.sleep(1) + return "[Mac Mode] Simulation : OneDrive désactivé." + try: + # Arrêter le processus + self.execute_command(["taskkill", "/f", "/im", "OneDrive.exe"]) + # Désactiver via le Registre (Stratégie de groupe) + self.execute_command(["reg", "add", "HKLM\\Software\\Policies\\Microsoft\\Windows\\OneDrive", "/v", "DisableFileSyncNGSC", "/t", "REG_DWORD", "/d", "1", "/f"]) + self.execute_command(["reg", "delete", "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "/v", "OneDrive", "/f"]) + return "☁️🚫 OneDrive a été arrêté et désactivé du système." + except Exception as e: + return f"Erreur lors de la désactivation de OneDrive : {str(e)}" + # --- Configuration de l'application --- -APP_VERSION = "2.0-dev1" +APP_VERSION = "2.0-dev2" # --- 2. Interface Graphique (Le Frontend) --- class RepairApp(ctk.CTk): @@ -412,6 +426,8 @@ def __init__(self): self.btn_telemetry = self.create_action_card(self.tab_opti, 0, 0, "Désactiver Télémétrie", "Bloque la collecte de données et le pistage par Microsoft (DiagTrack).", self.start_disable_telemetry, "#2C3E50", "#1A252F") self.btn_bg_apps = self.create_action_card(self.tab_opti, 0, 1, "Bloquer Apps Arrière-plan", "Empêche les applications inutiles de tourner en tâche de fond.", self.start_disable_background_apps, "#2C3E50", "#1A252F") + self.btn_onedrive = self.create_action_card(self.tab_opti, 1, 0, "Désactiver OneDrive", "Arrête la synchronisation et retire OneDrive du démarrage.", self.start_disable_onedrive, "#2C3E50", "#1A252F", colspan=2) + self.btn_malware = self.create_action_card(self.tab_sec, 0, 0, "Scan Malware", "Recherche des scripts et exécutables cachés dans Temp et Downloads.", self.start_malware_scan, "#8B0000", "#5C0000") self.btn_pdf_trace = self.create_action_card(self.tab_sec, 0, 1, "Traces PDF Vérolé", "Détecte les doubles extensions et les faux PDF laissés par les virus.", self.start_pdf_trace_scan, "#8B0000", "#5C0000") self.btn_registry = self.create_action_card(self.tab_sec, 0, 2, "Scan Registre", "Vérifie les clés Run/RunOnce pour débusquer les virus au démarrage.", self.start_registry_scan, "#8B0000", "#5C0000") @@ -670,6 +686,10 @@ def start_disable_telemetry(self): def start_disable_background_apps(self): self.run_async_task(self.btn_bg_apps, self.repair_manager.disable_background_apps, "Désactivation globale des applications en arrière-plan...") + def start_disable_onedrive(self): + if messagebox.askyesno("Optimisation", "Voulez-vous vraiment désactiver complètement OneDrive ?\n\nVos fichiers locaux ne seront plus synchronisés avec le cloud."): + self.run_async_task(self.btn_onedrive, self.repair_manager.disable_onedrive, "Désactivation de Microsoft OneDrive...") + # Point d'entrée de l'application if __name__ == "__main__": app = RepairApp() From e83ca67c7471bf7e50530ed8987d11e328e1b648 Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 09:39:57 +0000 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20Ajout=20du=20syst=C3=A8me=20de=20?= =?UTF-8?q?t=C3=A9l=C3=A9chargement=20de=20packs=20de=20langue=20dynamique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- langs/en.json | 18 +++++++++ main.py | 101 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 102 insertions(+), 17 deletions(-) create mode 100644 langs/en.json diff --git a/langs/en.json b/langs/en.json new file mode 100644 index 0000000..706d948 --- /dev/null +++ b/langs/en.json @@ -0,0 +1,18 @@ +{ + "🗑️ Effacer la console": "🗑️ Clear console", + "💾 Exporter Rapport": "💾 Export Report", + "🔄 Mises à jour": "🔄 Check Updates", + "Mode Sombre": "Dark Mode", + "🛠️ Système": "🛠️ System", + "⚡ Optimisation": "⚡ Optimization", + "🛡️ Sécurité": "🛡️ Security", + "🌐 Réseau & Nettoyage": "🌐 Network & Cleanup", + "🧰 Utilitaires": "🧰 Utilities", + "✅ Prêt à analyser": "✅ Ready to analyze", + "Bienvenue dans Windows Repair Toolkit - Édition Pro.": "Welcome to Windows Repair Toolkit - Pro Edition.", + "Initialisation terminée. Choisissez une action dans les onglets ci-dessus.": "Initialization complete. Choose an action from the tabs above.", + "1. Scan SFC": "1. SFC Scan", + "Vérifie l'intégrité et répare les fichiers système corrompus de Windows.": "Checks integrity and repairs corrupted Windows system files.", + "2. Réparer Image (DISM)": "2. Repair Image (DISM)", + "Répare l'image système globale de Windows via Windows Update.": "Repairs the overall Windows system image via Windows Update." +} diff --git a/main.py b/main.py index e7d8d5e..d748e7d 100644 --- a/main.py +++ b/main.py @@ -343,7 +343,7 @@ def disable_onedrive(self) -> str: return f"Erreur lors de la désactivation de OneDrive : {str(e)}" # --- Configuration de l'application --- -APP_VERSION = "2.0-dev2" +APP_VERSION = "2.0-dev3" # --- 2. Interface Graphique (Le Frontend) --- class RepairApp(ctk.CTk): @@ -352,6 +352,24 @@ def __init__(self): self.repair_manager = SystemRepairManager() + # --- Système de Langue --- + self.config = {"lang": "fr"} + if os.path.exists("config.json"): + try: + with open("config.json", "r", encoding="utf-8") as f: + self.config = json.load(f) + except: + pass + + self.translations = {} + lang_file = f"langs/{self.config['lang']}.json" + if os.path.exists(lang_file): + try: + with open(lang_file, "r", encoding="utf-8") as f: + self.translations = json.load(f) + except: + pass + # Configuration de la fenêtre principale self.title("Windows Repair Toolkit - Édition Pro") self.geometry("1000x700") # Fenêtre agrandie pour plus de confort @@ -377,24 +395,30 @@ def __init__(self): self.hw_label.grid(row=1, column=0, padx=10, pady=(0, 30)) # Bouton utilitaire dans la sidebar - self.btn_clear_log = ctk.CTkButton(self.sidebar_frame, text="🗑️ Effacer la console", command=self.clear_logs, fg_color="transparent", border_width=1, text_color=("gray10", "#DCE4EE")) + self.btn_clear_log = ctk.CTkButton(self.sidebar_frame, text=self._("🗑️ Effacer la console"), command=self.clear_logs, fg_color="transparent", border_width=1, text_color=("gray10", "#DCE4EE")) self.btn_clear_log.grid(row=2, column=0, padx=20, pady=10) - self.btn_export_log = ctk.CTkButton(self.sidebar_frame, text="💾 Exporter Rapport", command=self.export_report, fg_color="transparent", border_width=1, text_color=("gray10", "#DCE4EE")) + self.btn_export_log = ctk.CTkButton(self.sidebar_frame, text=self._("💾 Exporter Rapport"), command=self.export_report, fg_color="transparent", border_width=1, text_color=("gray10", "#DCE4EE")) self.btn_export_log.grid(row=3, column=0, padx=20, pady=10) - self.btn_update = ctk.CTkButton(self.sidebar_frame, text="🔄 Mises à jour", command=self.check_update, fg_color="transparent", border_width=1, text_color=("gray10", "#DCE4EE")) + self.btn_update = ctk.CTkButton(self.sidebar_frame, text=self._("🔄 Mises à jour"), command=self.check_update, fg_color="transparent", border_width=1, text_color=("gray10", "#DCE4EE")) self.btn_update.grid(row=4, column=0, padx=20, pady=10) # Switch Thème Clair/Sombre - self.appearance_mode_switch = ctk.CTkSwitch(self.sidebar_frame, text="Mode Sombre", command=self.change_appearance_mode_event) + self.appearance_mode_switch = ctk.CTkSwitch(self.sidebar_frame, text=self._("Mode Sombre"), command=self.change_appearance_mode_event) self.appearance_mode_switch.grid(row=5, column=0, padx=20, pady=20) self.appearance_mode_switch.select() # Coché par défaut (Sombre) + # Menu de Sélection de la Langue + current_lang = "Français" if self.config.get("lang", "fr") == "fr" else "English" + self.btn_lang = ctk.CTkOptionMenu(self.sidebar_frame, values=["Français", "English"], command=self.change_language_event) + self.btn_lang.set(current_lang) + self.btn_lang.grid(row=6, column=0, padx=20, pady=10) + # Indicateur de version self.version_label = ctk.CTkLabel(self.sidebar_frame, text=f"v{APP_VERSION} Pro Edition", font=ctk.CTkFont(size=10), text_color="#555555") - self.version_label.grid(row=7, column=0, pady=20, sticky="s") - self.sidebar_frame.grid_rowconfigure(6, weight=1) + self.version_label.grid(row=8, column=0, pady=20, sticky="s") + self.sidebar_frame.grid_rowconfigure(7, weight=1) # Raccourcis clavier (UX) self.bind("", self.clear_logs) @@ -404,11 +428,11 @@ def __init__(self): self.tabview = ctk.CTkTabview(self) self.tabview.grid(row=0, column=1, padx=20, pady=(10, 5), sticky="nsew") - self.tab_sys = self.tabview.add("🛠️ Système") - self.tab_opti = self.tabview.add("⚡ Optimisation") - self.tab_sec = self.tabview.add("🛡️ Sécurité") - self.tab_net = self.tabview.add("🌐 Réseau & Nettoyage") - self.tab_utils = self.tabview.add("🧰 Utilitaires") + self.tab_sys = self.tabview.add(self._("🛠️ Système")) + self.tab_opti = self.tabview.add(self._("⚡ Optimisation")) + self.tab_sec = self.tabview.add(self._("🛡️ Sécurité")) + self.tab_net = self.tabview.add(self._("🌐 Réseau & Nettoyage")) + self.tab_utils = self.tabview.add(self._("🧰 Utilitaires")) # Layout des onglets self.tab_sys.grid_columnconfigure((0, 1, 2), weight=1) @@ -451,7 +475,7 @@ def __init__(self): self.status_frame = ctk.CTkFrame(self, height=30, fg_color="transparent") self.status_frame.grid(row=1, column=1, padx=20, pady=(5, 5), sticky="ew") - self.status_label = ctk.CTkLabel(self.status_frame, text="✅ Prêt à analyser", font=ctk.CTkFont(weight="bold", size=13)) + self.status_label = ctk.CTkLabel(self.status_frame, text=self._("✅ Prêt à analyser"), font=ctk.CTkFont(weight="bold", size=13)) self.status_label.pack(side="left", padx=5) self.progress_bar = ctk.CTkProgressBar(self.status_frame, mode="indeterminate", height=6) @@ -468,23 +492,27 @@ def __init__(self): self.console_textbox.tag_config("warning", foreground="#F1C40F") self.console_textbox.tag_config("error", foreground="#E74C3C") - self.log_message("Bienvenue dans Windows Repair Toolkit - Édition Pro.", "info") - self.log_message("Initialisation terminée. Choisissez une action dans les onglets ci-dessus.\n" + "="*70, "success") + self.log_message(self._("Bienvenue dans Windows Repair Toolkit - Édition Pro."), "info") + self.log_message(self._("Initialisation terminée. Choisissez une action dans les onglets ci-dessus.") + "\n" + "="*70, "success") # --- Fonctions UI/UX --- + def _(self, text): + """Fonction de traduction à la volée. Renvoie le texte d'origine si non trouvé.""" + return self.translations.get(text, text) + def create_action_card(self, parent, row, col, title, desc, command, btn_color=None, hover_color=None, colspan=1): """Crée une carte visuelle élégante pour contenir un bouton et sa description.""" frame = ctk.CTkFrame(parent, corner_radius=8, border_width=1, border_color="#333333") frame.grid(row=row, column=col, columnspan=colspan, padx=10, pady=10, sticky="nsew") - btn = ctk.CTkButton(frame, text=title, command=command, font=ctk.CTkFont(weight="bold")) + btn = ctk.CTkButton(frame, text=self._(title), command=command, font=ctk.CTkFont(weight="bold")) if btn_color: btn.configure(fg_color=btn_color) if hover_color: btn.configure(hover_color=hover_color) btn.pack(pady=(15, 5), padx=15, fill="x") - lbl = ctk.CTkLabel(frame, text=desc, font=ctk.CTkFont(size=11), text_color="#AAAAAA", wraplength=210, justify="center") + lbl = ctk.CTkLabel(frame, text=self._(desc), font=ctk.CTkFont(size=11), text_color="#AAAAAA", wraplength=210, justify="center") lbl.pack(pady=(0, 15), padx=10, fill="both", expand=True) return btn @@ -620,6 +648,45 @@ def thread_target(): threading.Thread(target=thread_target, daemon=True).start() # --- Lancement des tâches --- + def change_language_event(self, new_lang_name): + lang_map = {"Français": "fr", "English": "en"} + lang_code = lang_map.get(new_lang_name, "fr") + + if lang_code == self.config.get("lang", "fr"): + return + + self.btn_lang.configure(state="disabled") + self.log_message(f"Téléchargement du pack de langue '{lang_code}' depuis GitHub...", "info") + + def thread_target(): + try: + if not os.path.exists("langs"): + os.makedirs("langs") + + url = f"https://raw.githubusercontent.com/Unfeeling3573/RepairToolkit/v2-dev/langs/{lang_code}.json?nocache={int(time.time())}" + ssl_context = ssl.create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + + req = urllib.request.Request(url, headers={'User-Agent': 'RepairToolkit'}) + with urllib.request.urlopen(req, timeout=8, context=ssl_context) as response: + data = response.read().decode('utf-8') + with open(f"langs/{lang_code}.json", "w", encoding="utf-8") as f: + f.write(data) + + self.config["lang"] = lang_code + with open("config.json", "w", encoding="utf-8") as f: + json.dump(self.config, f) + + self.log_message(f"Pack de langue '{lang_code}' appliqué ! Veuillez redémarrer l'application.", "success") + messagebox.showinfo("Redémarrage requis", "Le kit de langue a été téléchargé avec succès.\n\nVeuillez redémarrer l'application pour appliquer la traduction.") + except Exception as e: + self.log_message(f"Erreur de téléchargement : {str(e)}\nLe fichier 'langs/{lang_code}.json' existe-t-il sur GitHub ?", "error") + finally: + self.btn_lang.configure(state="normal") + + threading.Thread(target=thread_target, daemon=True).start() + def change_appearance_mode_event(self): if self.appearance_mode_switch.get() == 1: ctk.set_appearance_mode("dark") From b91ef0c0bde2d9eaf3c71227b5359d50ee3a2f97 Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 09:44:55 +0000 Subject: [PATCH 09/10] =?UTF-8?q?feat:=20T=C3=A9l=C3=A9chargement=20du=20p?= =?UTF-8?q?ack=20de=20langue=20par=20d=C3=A9faut=20en=20arri=C3=A8re-plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- langs/fr.json | 1 + main.py | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 langs/fr.json diff --git a/langs/fr.json b/langs/fr.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/langs/fr.json @@ -0,0 +1 @@ +{} diff --git a/main.py b/main.py index d748e7d..6bc7c04 100644 --- a/main.py +++ b/main.py @@ -343,7 +343,7 @@ def disable_onedrive(self) -> str: return f"Erreur lors de la désactivation de OneDrive : {str(e)}" # --- Configuration de l'application --- -APP_VERSION = "2.0-dev3" +APP_VERSION = "2.0-dev4" # --- 2. Interface Graphique (Le Frontend) --- class RepairApp(ctk.CTk): @@ -495,6 +495,11 @@ def __init__(self): self.log_message(self._("Bienvenue dans Windows Repair Toolkit - Édition Pro."), "info") self.log_message(self._("Initialisation terminée. Choisissez une action dans les onglets ci-dessus.") + "\n" + "="*70, "success") + # --- Téléchargement silencieux si la langue par défaut n'est pas installée --- + if not os.path.exists(lang_file): + self.log_message(f"Téléchargement du pack de langue par défaut ({self.config['lang']}) en arrière-plan...", "info") + self.download_language_pack(self.config['lang'], quiet=True) + # --- Fonctions UI/UX --- def _(self, text): """Fonction de traduction à la volée. Renvoie le texte d'origine si non trouvé.""" @@ -652,12 +657,14 @@ def change_language_event(self, new_lang_name): lang_map = {"Français": "fr", "English": "en"} lang_code = lang_map.get(new_lang_name, "fr") - if lang_code == self.config.get("lang", "fr"): + if lang_code == self.config.get("lang", "fr") and os.path.exists(f"langs/{lang_code}.json"): return self.btn_lang.configure(state="disabled") self.log_message(f"Téléchargement du pack de langue '{lang_code}' depuis GitHub...", "info") + self.download_language_pack(lang_code, quiet=False) + def download_language_pack(self, lang_code, quiet=False): def thread_target(): try: if not os.path.exists("langs"): @@ -678,12 +685,19 @@ def thread_target(): with open("config.json", "w", encoding="utf-8") as f: json.dump(self.config, f) - self.log_message(f"Pack de langue '{lang_code}' appliqué ! Veuillez redémarrer l'application.", "success") - messagebox.showinfo("Redémarrage requis", "Le kit de langue a été téléchargé avec succès.\n\nVeuillez redémarrer l'application pour appliquer la traduction.") + if not quiet: + self.log_message(f"Pack de langue '{lang_code}' appliqué ! Veuillez redémarrer l'application.", "success") + messagebox.showinfo("Redémarrage requis", "Le kit de langue a été téléchargé avec succès.\n\nVeuillez redémarrer l'application pour appliquer la traduction.") + else: + self.log_message(f"Le pack de langue '{lang_code}' a été téléchargé avec succès en arrière-plan.", "success") except Exception as e: - self.log_message(f"Erreur de téléchargement : {str(e)}\nLe fichier 'langs/{lang_code}.json' existe-t-il sur GitHub ?", "error") + if not quiet: + self.log_message(f"Erreur de téléchargement : {str(e)}\nLe fichier 'langs/{lang_code}.json' existe-t-il sur GitHub ?", "error") + else: + self.log_message(f"Impossible de télécharger la langue par défaut : {str(e)}", "warning") finally: - self.btn_lang.configure(state="normal") + if not quiet and hasattr(self, 'btn_lang'): + self.btn_lang.configure(state="normal") threading.Thread(target=thread_target, daemon=True).start() From 140d76a3b917ebee9171a239cfe7187b7a69b95b Mon Sep 17 00:00:00 2001 From: NXStudio Date: Thu, 9 Apr 2026 10:09:13 +0000 Subject: [PATCH 10/10] style: refonte de l'interface et ajout du template ui_spec.json --- main.py | 24 ++- ui_spec.json | 451 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 466 insertions(+), 9 deletions(-) create mode 100644 ui_spec.json diff --git a/main.py b/main.py index 6bc7c04..7a6d39c 100644 --- a/main.py +++ b/main.py @@ -385,7 +385,6 @@ def __init__(self): # -- Menu latéral (Sidebar) -- self.sidebar_frame = ctk.CTkFrame(self, width=220, corner_radius=0) self.sidebar_frame.grid(row=0, column=0, rowspan=3, sticky="nsew") - self.sidebar_frame.grid_rowconfigure(3, weight=1) # Espace vide poussant la version vers le bas self.logo_label = ctk.CTkLabel(self.sidebar_frame, text="Repair Toolkit", font=ctk.CTkFont(size=24, weight="bold")) self.logo_label.grid(row=0, column=0, padx=20, pady=(30, 5)) @@ -441,23 +440,30 @@ def __init__(self): self.tab_net.grid_columnconfigure((0, 1), weight=1) self.tab_utils.grid_columnconfigure((0, 1), weight=1) + # Thèmes de couleurs des cartes extraits de ui_spec.json + card_themes = { + "dark_theme": {"btn_color": "#2C3E50", "hover_color": "#1A252F"}, + "danger": {"btn_color": "#8B0000", "hover_color": "#5C0000"}, + "kill_switch": {"btn_color": "#C0392B", "hover_color": "#922B21"} + } + # Création des Cartes d'Actions (UI Premium) self.btn_sfc = self.create_action_card(self.tab_sys, 0, 0, "1. Scan SFC", "Vérifie l'intégrité et répare les fichiers système corrompus de Windows.", self.start_sfc_scan) self.btn_dism = self.create_action_card(self.tab_sys, 0, 1, "2. Réparer Image (DISM)", "Répare l'image système globale de Windows via Windows Update.", self.start_dism_scan) self.btn_restore = self.create_action_card(self.tab_sys, 0, 2, "3. Point Restauration", "Crée une sauvegarde système (recommandé avant réparation).", self.start_restore_point) self.btn_explorer = self.create_action_card(self.tab_sys, 1, 0, "Réparer Explorateur", "Redémarre l'explorateur Windows (Menu Démarrer bloqué, icônes invisibles).", self.start_repair_explorer, colspan=3) - self.btn_telemetry = self.create_action_card(self.tab_opti, 0, 0, "Désactiver Télémétrie", "Bloque la collecte de données et le pistage par Microsoft (DiagTrack).", self.start_disable_telemetry, "#2C3E50", "#1A252F") - self.btn_bg_apps = self.create_action_card(self.tab_opti, 0, 1, "Bloquer Apps Arrière-plan", "Empêche les applications inutiles de tourner en tâche de fond.", self.start_disable_background_apps, "#2C3E50", "#1A252F") + self.btn_telemetry = self.create_action_card(self.tab_opti, 0, 0, "Désactiver Télémétrie", "Bloque la collecte de données et le pistage par Microsoft (DiagTrack).", self.start_disable_telemetry, **card_themes["dark_theme"]) + self.btn_bg_apps = self.create_action_card(self.tab_opti, 0, 1, "Bloquer Apps Arrière-plan", "Empêche les applications inutiles de tourner en tâche de fond.", self.start_disable_background_apps, **card_themes["dark_theme"]) - self.btn_onedrive = self.create_action_card(self.tab_opti, 1, 0, "Désactiver OneDrive", "Arrête la synchronisation et retire OneDrive du démarrage.", self.start_disable_onedrive, "#2C3E50", "#1A252F", colspan=2) + self.btn_onedrive = self.create_action_card(self.tab_opti, 1, 0, "Désactiver OneDrive", "Arrête la synchronisation et retire OneDrive du démarrage.", self.start_disable_onedrive, **card_themes["dark_theme"], colspan=2) - self.btn_malware = self.create_action_card(self.tab_sec, 0, 0, "Scan Malware", "Recherche des scripts et exécutables cachés dans Temp et Downloads.", self.start_malware_scan, "#8B0000", "#5C0000") - self.btn_pdf_trace = self.create_action_card(self.tab_sec, 0, 1, "Traces PDF Vérolé", "Détecte les doubles extensions et les faux PDF laissés par les virus.", self.start_pdf_trace_scan, "#8B0000", "#5C0000") - self.btn_registry = self.create_action_card(self.tab_sec, 0, 2, "Scan Registre", "Vérifie les clés Run/RunOnce pour débusquer les virus au démarrage.", self.start_registry_scan, "#8B0000", "#5C0000") + self.btn_malware = self.create_action_card(self.tab_sec, 0, 0, "Scan Malware", "Recherche des scripts et exécutables cachés dans Temp et Downloads.", self.start_malware_scan, **card_themes["danger"]) + self.btn_pdf_trace = self.create_action_card(self.tab_sec, 0, 1, "Traces PDF Vérolé", "Détecte les doubles extensions et les faux PDF laissés par les virus.", self.start_pdf_trace_scan, **card_themes["danger"]) + self.btn_registry = self.create_action_card(self.tab_sec, 0, 2, "Scan Registre", "Vérifie les clés Run/RunOnce pour débusquer les virus au démarrage.", self.start_registry_scan, **card_themes["danger"]) # Bouton Kill Switch (Prend toute la largeur de la ligne en dessous) - self.btn_kill = self.create_action_card(self.tab_sec, 1, 0, "🚨 KILL SWITCH (Suppression)", "Arrêt d'urgence des processus suspects en mémoire et suppression forcée des charges utiles.", self.start_kill_switch, "#C0392B", "#922B21", colspan=3) + self.btn_kill = self.create_action_card(self.tab_sec, 1, 0, "🚨 KILL SWITCH (Suppression)", "Arrêt d'urgence des processus suspects en mémoire et suppression forcée des charges utiles.", self.start_kill_switch, **card_themes["kill_switch"], colspan=3) self.btn_dns = self.create_action_card(self.tab_net, 0, 0, "Vider Cache DNS", "Résout la plupart des problèmes de connexion aux sites internet.", self.start_flush_dns) self.btn_hosts = self.create_action_card(self.tab_net, 0, 1, "Restaurer HOSTS", "Réinitialise le fichier HOSTS pour bloquer les redirections malveillantes.", self.start_hosts_restore) @@ -493,7 +499,7 @@ def __init__(self): self.console_textbox.tag_config("error", foreground="#E74C3C") self.log_message(self._("Bienvenue dans Windows Repair Toolkit - Édition Pro."), "info") - self.log_message(self._("Initialisation terminée. Choisissez une action dans les onglets ci-dessus.") + "\n" + "="*70, "success") + self.log_message(self._("Initialisation terminée. Choisissez une action dans les onglets ci-dessus.\n======================================================================"), "success") # --- Téléchargement silencieux si la langue par défaut n'est pas installée --- if not os.path.exists(lang_file): diff --git a/ui_spec.json b/ui_spec.json new file mode 100644 index 0000000..8c88b5d --- /dev/null +++ b/ui_spec.json @@ -0,0 +1,451 @@ +{ + "_meta": { + "description": "UI specification for Windows Repair Toolkit — Pro Edition. Use this file to regenerate the full customtkinter interface. Every widget, style value, layout parameter and color is extracted directly from main.py.", + "framework": "customtkinter", + "python_version": "3.11+", + "app_version": "2.0-dev4", + "dependencies": ["customtkinter", "fpdf", "pyinstaller"], + "entry_class": "RepairApp", + "base_class": "ctk.CTk" + }, + + "window": { + "title": "Windows Repair Toolkit - Édition Pro", + "geometry": "1000x700", + "appearance_mode": "dark", + "default_color_theme": "blue", + "grid": { + "columns": [ + { "index": 0, "weight": 0, "note": "sidebar — fixed width 220px" }, + { "index": 1, "weight": 1, "note": "main area — expands" } + ], + "rows": [ + { "index": 0, "weight": 3, "note": "tab zone" }, + { "index": 1, "weight": 0, "note": "status bar" }, + { "index": 2, "weight": 2, "note": "console log" } + ] + }, + "keyboard_shortcuts": [ + { "binding": "", "command": "clear_logs" }, + { "binding": "", "command": "export_report" } + ] + }, + + "theme": { + "sidebar_bg": "default_ctk_dark", + "titlebar_bg": "#1a1a2e", + "card_border": "#333333", + "console_border": "#333333", + "console_font_family": "Consolas", + "console_font_size": 13, + "version_text_color": "#555555", + "hw_label_color": "gray", + "sidebar_button_text_color_light": "gray10", + "sidebar_button_text_color_dark": "#DCE4EE", + "console_tags": { + "info": { "foreground": "#5DADE2" }, + "success": { "foreground": "#2ECC71" }, + "warning": { "foreground": "#F1C40F" }, + "error": { "foreground": "#E74C3C" } + }, + "action_card_colors": { + "default": { "fg_color": null, "hover_color": null }, + "dark_theme": { "fg_color": "#2C3E50", "hover_color": "#1A252F" }, + "danger": { "fg_color": "#8B0000", "hover_color": "#5C0000" }, + "kill_switch": { "fg_color": "#C0392B", "hover_color": "#922B21" } + } + }, + + "sidebar": { + "widget": "CTkFrame", + "width": 220, + "corner_radius": 0, + "grid": { "row": 0, "column": 0, "rowspan": 3, "sticky": "nsew" }, + "row_weight": { "index": 7, "weight": 1, "note": "pushes version label to bottom" }, + "children": [ + { + "id": "logo_label", + "widget": "CTkLabel", + "text": "Repair Toolkit", + "font": { "size": 24, "weight": "bold" }, + "grid": { "row": 0, "column": 0, "padx": 20, "pady": [30, 5] } + }, + { + "id": "hw_label", + "widget": "CTkLabel", + "text": "dynamic — from SystemRepairManager.get_hardware_info()", + "font": { "size": 11 }, + "text_color": "gray", + "justify": "center", + "grid": { "row": 1, "column": 0, "padx": 10, "pady": [0, 30] } + }, + { + "id": "btn_clear_log", + "widget": "CTkButton", + "text": "🗑️ Effacer la console", + "text_i18n_key": "🗑️ Effacer la console", + "command": "clear_logs", + "fg_color": "transparent", + "border_width": 1, + "text_color": ["gray10", "#DCE4EE"], + "grid": { "row": 2, "column": 0, "padx": 20, "pady": 10 } + }, + { + "id": "btn_export_log", + "widget": "CTkButton", + "text": "💾 Exporter Rapport", + "text_i18n_key": "💾 Exporter Rapport", + "command": "export_report", + "fg_color": "transparent", + "border_width": 1, + "text_color": ["gray10", "#DCE4EE"], + "grid": { "row": 3, "column": 0, "padx": 20, "pady": 10 } + }, + { + "id": "btn_update", + "widget": "CTkButton", + "text": "🔄 Mises à jour", + "text_i18n_key": "🔄 Mises à jour", + "command": "check_update", + "fg_color": "transparent", + "border_width": 1, + "text_color": ["gray10", "#DCE4EE"], + "grid": { "row": 4, "column": 0, "padx": 20, "pady": 10 } + }, + { + "id": "appearance_mode_switch", + "widget": "CTkSwitch", + "text": "Mode Sombre", + "text_i18n_key": "Mode Sombre", + "command": "change_appearance_mode_event", + "default_state": "selected", + "grid": { "row": 5, "column": 0, "padx": 20, "pady": 20 } + }, + { + "id": "btn_lang", + "widget": "CTkOptionMenu", + "values": ["Français", "English"], + "command": "change_language_event", + "default_value": "Français", + "grid": { "row": 6, "column": 0, "padx": 20, "pady": 10 } + }, + { + "id": "version_label", + "widget": "CTkLabel", + "text": "v{APP_VERSION} Pro Edition", + "font": { "size": 10 }, + "text_color": "#555555", + "grid": { "row": 8, "column": 0, "pady": 20, "sticky": "s" } + } + ] + }, + + "tabview": { + "widget": "CTkTabview", + "grid": { "row": 0, "column": 1, "padx": 20, "pady": [10, 5], "sticky": "nsew" }, + "tabs": [ + { + "id": "tab_sys", + "label": "🛠️ Système", + "i18n_key": "🛠️ Système", + "columns": [0, 1, 2], + "column_weight": 1, + "cards": [ + { + "id": "btn_sfc", + "title": "1. Scan SFC", + "description": "Vérifie l'intégrité et répare les fichiers système corrompus de Windows.", + "command": "start_sfc_scan", + "grid": { "row": 0, "col": 0, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_dism", + "title": "2. Réparer Image (DISM)", + "description": "Répare l'image système globale de Windows via Windows Update.", + "command": "start_dism_scan", + "grid": { "row": 0, "col": 1, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_restore", + "title": "3. Point Restauration", + "description": "Crée une sauvegarde système (recommandé avant réparation).", + "command": "start_restore_point", + "grid": { "row": 0, "col": 2, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_explorer", + "title": "Réparer Explorateur", + "description": "Redémarre l'explorateur Windows (Menu Démarrer bloqué, icônes invisibles).", + "command": "start_repair_explorer", + "grid": { "row": 1, "col": 0, "colspan": 3 }, + "color_theme": "default" + } + ] + }, + { + "id": "tab_opti", + "label": "⚡ Optimisation", + "i18n_key": "⚡ Optimisation", + "columns": [0, 1], + "column_weight": 1, + "cards": [ + { + "id": "btn_telemetry", + "title": "Désactiver Télémétrie", + "description": "Bloque la collecte de données et le pistage par Microsoft (DiagTrack).", + "command": "start_disable_telemetry", + "grid": { "row": 0, "col": 0, "colspan": 1 }, + "color_theme": "dark_theme" + }, + { + "id": "btn_bg_apps", + "title": "Bloquer Apps Arrière-plan", + "description": "Empêche les applications inutiles de tourner en tâche de fond.", + "command": "start_disable_background_apps", + "grid": { "row": 0, "col": 1, "colspan": 1 }, + "color_theme": "dark_theme" + }, + { + "id": "btn_onedrive", + "title": "Désactiver OneDrive", + "description": "Arrête la synchronisation et retire OneDrive du démarrage.", + "command": "start_disable_onedrive", + "grid": { "row": 1, "col": 0, "colspan": 2 }, + "color_theme": "dark_theme" + } + ] + }, + { + "id": "tab_sec", + "label": "🛡️ Sécurité", + "i18n_key": "🛡️ Sécurité", + "columns": [0, 1, 2], + "column_weight": 1, + "cards": [ + { + "id": "btn_malware", + "title": "Scan Malware", + "description": "Recherche des scripts et exécutables cachés dans Temp et Downloads.", + "command": "start_malware_scan", + "grid": { "row": 0, "col": 0, "colspan": 1 }, + "color_theme": "danger" + }, + { + "id": "btn_pdf_trace", + "title": "Traces PDF Vérolé", + "description": "Détecte les doubles extensions et les faux PDF laissés par les virus.", + "command": "start_pdf_trace_scan", + "grid": { "row": 0, "col": 1, "colspan": 1 }, + "color_theme": "danger" + }, + { + "id": "btn_registry", + "title": "Scan Registre", + "description": "Vérifie les clés Run/RunOnce pour débusquer les virus au démarrage.", + "command": "start_registry_scan", + "grid": { "row": 0, "col": 2, "colspan": 1 }, + "color_theme": "danger" + }, + { + "id": "btn_kill", + "title": "🚨 KILL SWITCH (Suppression)", + "description": "Arrêt d'urgence des processus suspects en mémoire et suppression forcée des charges utiles.", + "command": "start_kill_switch", + "grid": { "row": 1, "col": 0, "colspan": 3 }, + "color_theme": "kill_switch" + } + ] + }, + { + "id": "tab_net", + "label": "🌐 Réseau & Nettoyage", + "i18n_key": "🌐 Réseau & Nettoyage", + "columns": [0, 1], + "column_weight": 1, + "cards": [ + { + "id": "btn_dns", + "title": "Vider Cache DNS", + "description": "Résout la plupart des problèmes de connexion aux sites internet.", + "command": "start_flush_dns", + "grid": { "row": 0, "col": 0, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_hosts", + "title": "Restaurer HOSTS", + "description": "Réinitialise le fichier HOSTS pour bloquer les redirections malveillantes.", + "command": "start_hosts_restore", + "grid": { "row": 0, "col": 1, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_temp", + "title": "Nettoyage Temp", + "description": "Libère de l'espace disque en supprimant les fichiers temporaires inutiles.", + "command": "start_clean_temp", + "grid": { "row": 1, "col": 0, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_downloads", + "title": "Vider Téléchargements", + "description": "Supprime définitivement le contenu du dossier Téléchargements.", + "command": "start_clean_downloads", + "grid": { "row": 1, "col": 1, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_net_reset", + "title": "Réinitialiser Réseau", + "description": "Renouvelle l'adresse IP et réinitialise la carte réseau (Winsock).", + "command": "start_network_reset", + "grid": { "row": 2, "col": 0, "colspan": 2 }, + "color_theme": "default" + } + ] + }, + { + "id": "tab_utils", + "label": "🧰 Utilitaires", + "i18n_key": "🧰 Utilitaires", + "columns": [0, 1], + "column_weight": 1, + "cards": [ + { + "id": "btn_license", + "title": "Clé de Licence", + "description": "Récupère la clé de produit Windows originale intégrée à la carte mère.", + "command": "start_license_check", + "grid": { "row": 0, "col": 0, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_disk", + "title": "Santé des Disques", + "description": "Vérifie l'état de santé S.M.A.R.T de vos disques durs et SSD.", + "command": "start_disk_check", + "grid": { "row": 0, "col": 1, "colspan": 1 }, + "color_theme": "default" + }, + { + "id": "btn_battery", + "title": "Rapport Batterie", + "description": "Génère un rapport HTML complet sur l'état et l'usure de votre batterie.", + "command": "start_battery_report", + "grid": { "row": 1, "col": 0, "colspan": 2 }, + "color_theme": "default" + }, + { + "id": "btn_sysinfo", + "title": "Infos Système", + "description": "Affiche des informations matérielles détaillées (Carte Mère, GPU).", + "command": "start_detailed_sysinfo", + "grid": { "row": 2, "col": 0, "colspan": 2 }, + "color_theme": "default" + } + ] + } + ] + }, + + "status_bar": { + "widget": "CTkFrame", + "height": 30, + "fg_color": "transparent", + "grid": { "row": 1, "column": 1, "padx": 20, "pady": [5, 5], "sticky": "ew" }, + "children": [ + { + "id": "status_label", + "widget": "CTkLabel", + "text": "✅ Prêt à analyser", + "i18n_key": "✅ Prêt à analyser", + "font": { "weight": "bold", "size": 13 }, + "pack": { "side": "left", "padx": 5 } + }, + { + "id": "progress_bar", + "widget": "CTkProgressBar", + "mode": "indeterminate", + "height": 6, + "default_value": 0, + "pack": { "side": "right", "fill": "x", "expand": true, "padx": [20, 5] } + } + ] + }, + + "console": { + "id": "console_textbox", + "widget": "CTkTextbox", + "font": { "family": "Consolas", "size": 13 }, + "corner_radius": 10, + "border_width": 1, + "border_color": "#333333", + "grid": { "row": 2, "column": 1, "padx": 20, "pady": [0, 20], "sticky": "nsew" }, + "tags": { + "info": { "foreground": "#5DADE2" }, + "success": { "foreground": "#2ECC71" }, + "warning": { "foreground": "#F1C40F" }, + "error": { "foreground": "#E74C3C" } + }, + "startup_messages": [ + { "text": "Bienvenue dans Windows Repair Toolkit - Édition Pro.", "tag": "info" }, + { "text": "Initialisation terminée. Choisissez une action dans les onglets ci-dessus.\n======================================================================", "tag": "success" } + ] + }, + + "action_card_template": { + "note": "This is the create_action_card() factory method signature and behavior", + "method": "create_action_card", + "signature": "create_action_card(parent, row, col, title, desc, command, btn_color=None, hover_color=None, colspan=1)", + "frame": { + "widget": "CTkFrame", + "corner_radius": 8, + "border_width": 1, + "border_color": "#333333", + "grid": "row=row, column=col, columnspan=colspan, padx=10, pady=10, sticky='nsew'" + }, + "button": { + "widget": "CTkButton", + "text": "translated title", + "font": { "weight": "bold" }, + "pack": { "pady": [15, 5], "padx": 15, "fill": "x" }, + "optional_overrides": ["fg_color", "hover_color"] + }, + "label": { + "widget": "CTkLabel", + "text": "translated description", + "font": { "size": 11 }, + "text_color": "#AAAAAA", + "wraplength": 210, + "justify": "center", + "pack": { "pady": [0, 15], "padx": 10, "fill": "both", "expand": true } + } + }, + + "i18n": { + "supported_languages": ["fr", "en"], + "config_file": "config.json", + "lang_dir": "langs/", + "default_lang": "fr", + "translation_keys": { + "🗑️ Effacer la console": "🗑️ Clear console", + "💾 Exporter Rapport": "💾 Export Report", + "🔄 Mises à jour": "🔄 Check Updates", + "Mode Sombre": "Dark Mode", + "🛠️ Système": "🛠️ System", + "⚡ Optimisation": "⚡ Optimization", + "🛡️ Sécurité": "🛡️ Security", + "🌐 Réseau & Nettoyage": "🌐 Network & Cleanup", + "🧰 Utilitaires": "🧰 Utilities", + "✅ Prêt à analyser": "✅ Ready to analyze", + "1. Scan SFC": "1. SFC Scan", + "2. Réparer Image (DISM)": "2. Repair Image (DISM)" + } + }, + + "gemini_prompt": "Using this JSON specification, regenerate the RepairApp class in customtkinter Python. Reproduce: (1) the exact window layout with sidebar + tabview + status bar + console, (2) the create_action_card() factory method, (3) all 5 tabs with their cards at the correct grid positions and color themes from theme.action_card_colors, (4) the console color tags, (5) the i18n translation system. Keep all widget IDs from this spec. Do not regenerate the backend logic (SystemRepairManager), only the UI layer." +}