From 08c3d373e3a2a418e6a657bf66557be93169f867 Mon Sep 17 00:00:00 2001 From: najeeb Date: Sat, 9 May 2026 01:51:13 +0500 Subject: [PATCH] feat: Add GUI v1.1 features (drag-and-drop, persistence, export logs, open output) --- CHANGELOG.md | 12 ++++- README.md | 20 +++++-- kobackupdec_gui.py | 129 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f612c7..74afe1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,17 @@ All notable changes to this project will be documented in this file. -## [GUI Edition] — 2026-05-08 +## [GUI_v1.1] — 2026-05-08 + +### Added +- **Drag-and-Drop:** Added `tkinterdnd2` support allowing users to drag backup folders directly into the application. +- **Settings Persistence:** Created `config.json` integration to save and automatically load user preferences and selected directories across sessions. +- **Log Exporting:** Added an "Export Log" button to save the current terminal output to a text file for auditing. +- **Output Folder Quick Access:** Added an "Open Output" button that becomes clickable after a successful decryption to instantly view the extracted files. + +--- + +## [GUI_v1.0] — 2026-05-08 ### Added - **Full GUI application** (`kobackupdec_gui.py`) with modern dark theme diff --git a/README.md b/README.md index f7092d4..3fdec46 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@

🔐 KoBackup Decryptor

Decrypt Huawei HiSuite & KoBackup encrypted backups
- CLI + Modern GUI • Selective Folder Decryption • Password Verification + CLI + Modern GUI • Selective Folder Decryption • Drag & Drop • Password Verification

Python 3.7+ MIT License - Version + Version

@@ -39,7 +39,11 @@ This fork adds a **full-featured graphical interface** built with tkinter, bring | Decrypt full backups | ✅ | ✅ | | Password verification before decrypt | — | ✅ | | **Selective folder decryption** | — | ✅ | +| **Drag and Drop support** | — | ✅ | +| **Settings persistence** | — | ✅ | | Pause / Resume / Stop controls | — | ✅ | +| Export decryption logs | — | ✅ | +| Open Output folder button | — | ✅ | | Real-time color-coded log output | — | ✅ | | Progress tracking with status updates | — | ✅ | | Responsive dark-themed interface | — | ✅ | @@ -69,6 +73,7 @@ pip install -r requirements.txt | Package | Purpose | |---|---| | `pycryptodome` | AES / PBKDF2 / HMAC cryptographic operations | +| `tkinterdnd2` | Drag and drop functionality for the GUI | | `tkinter` | GUI framework (bundled with Python on most platforms) | > **Note:** On some Linux distributions, tkinter may need to be installed separately: @@ -95,11 +100,12 @@ python kobackupdec_gui.py #### GUI Workflow 1. **Enter Password** — Type your backup password (toggle visibility with 👁) -2. **Select Backup Folder** — Browse to the Huawei backup directory +2. **Select Backup Folder** — Drag and drop your Huawei backup directory right into the application, or click **Browse** 3. **Select Destination** — Choose where to save decrypted files (pick a parent, name the output folder) 4. **Configure Options** — Toggle TAR expansion, writable permissions, and log verbosity -5. **Select Folders** — After setting the backup path, click **🔍 Scan** or it auto-scans to show available folders. Check/uncheck individual folders (pictures, video, audios, etc.) +5. **Select Folders** — After setting the backup path, check/uncheck individual folders (pictures, video, audios, etc.) to decrypt only what you need 6. **Start Decryption** — Click **🔓 Start Decryption** +7. **Open Output** — When finished, click **📂 Open Output** to view your files immediately #### GUI Controls @@ -108,6 +114,8 @@ python kobackupdec_gui.py | 🔓 **Start Decryption** | Verifies password first, then begins decryption | | ⏸ **Pause / ▶ Resume** | Temporarily halt and resume the process | | ⏹ **Stop** | Cancel the decryption (partially decrypted files are kept) | +| 📂 **Open Output** | Opens destination folder in Windows Explorer (enabled after success) | +| **Export Log** | Save decryption logs to a text file for auditing | | **Select All / Deselect All** | Quickly toggle all folder checkboxes | | **🔍 Scan** | Re-scan backup directory for available folders | | **Clear Log** | Clear the log output panel | @@ -116,7 +124,9 @@ python kobackupdec_gui.py - **🔑 Password Verification** — Validates the password against `info.xml` before starting decryption. Wrong passwords are caught instantly. - **📂 Selective Folder Decryption** — Only decrypt what you need (e.g., just pictures and contacts, skip video and apps). -- **📊 Real-Time Progress** — Status bar shows current phase and folder being processed. +- **💾 Settings Persistence** — The app remembers your selected folders and checkboxes across launches via `config.json`. +- **🖱️ Drag and Drop** — Seamlessly drop backup folders into the app instead of browsing manually. +- **📊 Real-Time Progress & Logs** — Status bar shows current phase. Export logs anytime. - **🎨 Dark Theme** — Modern, responsive dark interface with color-coded log levels (green=info, yellow=warning, red=error). - **📐 Responsive Layout** — Resizes gracefully from 600×500 to fullscreen. Folder checkboxes reflow automatically. diff --git a/kobackupdec_gui.py b/kobackupdec_gui.py index 3be4cd6..a26df63 100644 --- a/kobackupdec_gui.py +++ b/kobackupdec_gui.py @@ -16,6 +16,9 @@ import tkinter as tk from tkinter import filedialog, messagebox, simpledialog, ttk import queue import time +import json +import subprocess +from tkinterdnd2 import TkinterDnD, DND_FILES # --------------------------------------------------------------------------- # Logging handler that forwards records into a thread-safe queue @@ -36,7 +39,7 @@ class QueueHandler(logging.Handler): # Main GUI Application # --------------------------------------------------------------------------- -class KoBackupDecGUI(tk.Tk): +class KoBackupDecGUI(TkinterDnD.Tk): """Tkinter-based GUI for the Huawei KoBackup decryptor.""" # -- Colour palette (dark mode) ---------------------------------------- @@ -112,6 +115,12 @@ class KoBackupDecGUI(tk.Tk): # Bind resize to reflow folder checkboxes self.bind("", self._on_resize) + # Load saved settings + self._load_config() + + # Save config on exit + self.protocol("WM_DELETE_WINDOW", self._on_closing) + # Start polling the log queue self._poll_log_queue() @@ -245,6 +254,10 @@ class KoBackupDecGUI(tk.Tk): highlightcolor=self.ACCENT) entry.pack(side="left", fill="x", expand=True, ipady=7, padx=(0, 8)) + # Enable Drag and Drop + entry.drop_target_register(DND_FILES) + entry.dnd_bind('<>', lambda e, v=var, t=tag: self._on_drop(e, v, t)) + btn = tk.Button(row, text="Browse", font=("Segoe UI", 9, "bold"), bg=self.ACCENT, fg="#ffffff", activebackground=self.ACCENT_HOVER, @@ -517,6 +530,37 @@ class KoBackupDecGUI(tk.Tk): ) self.stop_btn.pack(side="left", padx=(10, 0)) + self.open_output_btn = tk.Button( + btn_row, + text="📂 Open Output", + font=("Segoe UI", 9), + bg=self.SUCCESS, + fg="#1a1a2e", + activebackground="#10b981", + activeforeground="#1a1a2e", + relief="flat", bd=0, + cursor="hand2", + padx=14, pady=8, + state="disabled", + command=self._open_output_folder + ) + self.open_output_btn.pack(side="right", padx=(10, 0)) + + self.export_log_btn = tk.Button( + btn_row, + text="Export Log", + font=("Segoe UI", 9), + bg=self.BG_INPUT, + fg=self.FG_DIM, + activebackground=self.BG_HOVER, + activeforeground=self.FG, + relief="flat", bd=0, + cursor="hand2", + padx=14, pady=8, + command=self._export_log + ) + self.export_log_btn.pack(side="right", padx=(10, 0)) + self.clear_log_btn = tk.Button( btn_row, text="Clear Log", @@ -919,12 +963,14 @@ class KoBackupDecGUI(tk.Tk): self._running = False self.progress.stop() self._set_controls_running(False) + self.open_output_btn.configure(state="disabled") if stopped: self.status_var.set('⏹ Decryption stopped by user') self._append_log('') self._append_log('WARNING: ⏹ Decryption was stopped by the user.') elif success: + self.open_output_btn.configure(state="normal") self.status_var.set('✅ Decryption completed successfully!') self._append_log('') self._append_log('=' * 50) @@ -939,6 +985,87 @@ class KoBackupDecGUI(tk.Tk): 'Decryption failed.\n' 'Check the log output for details.') + # ----------------------------------------------------------------- + # New Utilities + # ----------------------------------------------------------------- + + def _on_drop(self, event, var, tag): + path = event.data + if path.startswith('{') and path.endswith('}'): + path = path[1:-1] + var.set(path) + if tag == "backup": + self._scan_backup_folders() + + def _export_log(self): + log_content = self.log_text.get("1.0", "end-1c") + if not log_content.strip(): + messagebox.showinfo("Export Log", "The log is empty.") + return + filepath = filedialog.asksaveasfilename( + defaultextension=".txt", + filetypes=[("Text files", "*.txt"), ("All files", "*.*")], + title="Save Log Output" + ) + if filepath: + try: + with open(filepath, "w", encoding="utf-8") as f: + f.write(log_content) + messagebox.showinfo("Success", "Log exported successfully.") + except Exception as e: + messagebox.showerror("Error", f"Failed to save log:\n{e}") + + def _open_output_folder(self): + path = self.dest_var.get().strip() + if os.path.isdir(path): + if sys.platform == "win32": + os.startfile(path) + elif sys.platform == "darwin": + subprocess.Popen(["open", path]) + else: + subprocess.Popen(["xdg-open", path]) + + def _get_config_path(self): + return os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json") + + def _load_config(self): + config_path = self._get_config_path() + if os.path.exists(config_path): + try: + with open(config_path, "r", encoding="utf-8") as f: + data = json.load(f) + if "backup_path" in data: + self.backup_var.set(data["backup_path"]) + self._scan_backup_folders() + if "dest_path" in data: + self.dest_var.set(data["dest_path"]) + if "expandtar" in data: + self.expandtar_var.set(data["expandtar"]) + if "writable" in data: + self.writable_var.set(data["writable"]) + if "verbose" in data: + self.verbose_var.set(data["verbose"]) + except Exception as e: + logging.error(f"Failed to load config: {e}") + + def _save_config(self): + config_path = self._get_config_path() + data = { + "backup_path": self.backup_var.get(), + "dest_path": self.dest_var.get(), + "expandtar": self.expandtar_var.get(), + "writable": self.writable_var.get(), + "verbose": self.verbose_var.get() + } + try: + with open(config_path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=4) + except Exception as e: + logging.error(f"Failed to save config: {e}") + + def _on_closing(self): + self._save_config() + self.destroy() # --------------------------------------------------------------------------- # Entry point