feat: Add GUI v1.1 features (drag-and-drop, persistence, export logs, open output)

This commit is contained in:
najeeb 2026-05-09 01:51:13 +05:00
parent 04512877e9
commit 08c3d373e3
3 changed files with 154 additions and 7 deletions

View File

@ -2,7 +2,17 @@
All notable changes to this project will be documented in this file. 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 ### Added
- **Full GUI application** (`kobackupdec_gui.py`) with modern dark theme - **Full GUI application** (`kobackupdec_gui.py`) with modern dark theme

View File

@ -2,12 +2,12 @@
<h1 align="center">🔐 KoBackup Decryptor</h1> <h1 align="center">🔐 KoBackup Decryptor</h1>
<p align="center"> <p align="center">
<strong>Decrypt Huawei HiSuite &amp; KoBackup encrypted backups</strong><br> <strong>Decrypt Huawei HiSuite &amp; KoBackup encrypted backups</strong><br>
CLI + Modern GUI &bull; Selective Folder Decryption &bull; Password Verification CLI + Modern GUI &bull; Selective Folder Decryption &bull; Drag & Drop &bull; Password Verification
</p> </p>
<p align="center"> <p align="center">
<a href="#-installation"><img src="https://img.shields.io/badge/python-3.7%2B-blue?logo=python&logoColor=white" alt="Python 3.7+"></a> <a href="#-installation"><img src="https://img.shields.io/badge/python-3.7%2B-blue?logo=python&logoColor=white" alt="Python 3.7+"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="MIT License"></a> <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="MIT License"></a>
<a href="#-changelog"><img src="https://img.shields.io/badge/version-20200705--GUI-purple" alt="Version"></a> <a href="#-changelog"><img src="https://img.shields.io/badge/version-GUI_v1.1-purple" alt="Version"></a>
</p> </p>
</p> </p>
@ -39,7 +39,11 @@ This fork adds a **full-featured graphical interface** built with tkinter, bring
| Decrypt full backups | ✅ | ✅ | | Decrypt full backups | ✅ | ✅ |
| Password verification before decrypt | — | ✅ | | Password verification before decrypt | — | ✅ |
| **Selective folder decryption** | — | ✅ | | **Selective folder decryption** | — | ✅ |
| **Drag and Drop support** | — | ✅ |
| **Settings persistence** | — | ✅ |
| Pause / Resume / Stop controls | — | ✅ | | Pause / Resume / Stop controls | — | ✅ |
| Export decryption logs | — | ✅ |
| Open Output folder button | — | ✅ |
| Real-time color-coded log output | — | ✅ | | Real-time color-coded log output | — | ✅ |
| Progress tracking with status updates | — | ✅ | | Progress tracking with status updates | — | ✅ |
| Responsive dark-themed interface | — | ✅ | | Responsive dark-themed interface | — | ✅ |
@ -69,6 +73,7 @@ pip install -r requirements.txt
| Package | Purpose | | Package | Purpose |
|---|---| |---|---|
| `pycryptodome` | AES / PBKDF2 / HMAC cryptographic operations | | `pycryptodome` | AES / PBKDF2 / HMAC cryptographic operations |
| `tkinterdnd2` | Drag and drop functionality for the GUI |
| `tkinter` | GUI framework (bundled with Python on most platforms) | | `tkinter` | GUI framework (bundled with Python on most platforms) |
> **Note:** On some Linux distributions, tkinter may need to be installed separately: > **Note:** On some Linux distributions, tkinter may need to be installed separately:
@ -95,11 +100,12 @@ python kobackupdec_gui.py
#### GUI Workflow #### GUI Workflow
1. **Enter Password** — Type your backup password (toggle visibility with 👁) 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) 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 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** 6. **Start Decryption** — Click **🔓 Start Decryption**
7. **Open Output** — When finished, click **📂 Open Output** to view your files immediately
#### GUI Controls #### GUI Controls
@ -108,6 +114,8 @@ python kobackupdec_gui.py
| 🔓 **Start Decryption** | Verifies password first, then begins decryption | | 🔓 **Start Decryption** | Verifies password first, then begins decryption |
| ⏸ **Pause / ▶ Resume** | Temporarily halt and resume the process | | ⏸ **Pause / ▶ Resume** | Temporarily halt and resume the process |
| ⏹ **Stop** | Cancel the decryption (partially decrypted files are kept) | | ⏹ **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 | | **Select All / Deselect All** | Quickly toggle all folder checkboxes |
| **🔍 Scan** | Re-scan backup directory for available folders | | **🔍 Scan** | Re-scan backup directory for available folders |
| **Clear Log** | Clear the log output panel | | **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. - **🔑 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). - **📂 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). - **🎨 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. - **📐 Responsive Layout** — Resizes gracefully from 600×500 to fullscreen. Folder checkboxes reflow automatically.

View File

@ -16,6 +16,9 @@ import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, ttk from tkinter import filedialog, messagebox, simpledialog, ttk
import queue import queue
import time import time
import json
import subprocess
from tkinterdnd2 import TkinterDnD, DND_FILES
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Logging handler that forwards records into a thread-safe queue # Logging handler that forwards records into a thread-safe queue
@ -36,7 +39,7 @@ class QueueHandler(logging.Handler):
# Main GUI Application # Main GUI Application
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
class KoBackupDecGUI(tk.Tk): class KoBackupDecGUI(TkinterDnD.Tk):
"""Tkinter-based GUI for the Huawei KoBackup decryptor.""" """Tkinter-based GUI for the Huawei KoBackup decryptor."""
# -- Colour palette (dark mode) ---------------------------------------- # -- Colour palette (dark mode) ----------------------------------------
@ -112,6 +115,12 @@ class KoBackupDecGUI(tk.Tk):
# Bind resize to reflow folder checkboxes # Bind resize to reflow folder checkboxes
self.bind("<Configure>", self._on_resize) self.bind("<Configure>", 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 # Start polling the log queue
self._poll_log_queue() self._poll_log_queue()
@ -245,6 +254,10 @@ class KoBackupDecGUI(tk.Tk):
highlightcolor=self.ACCENT) highlightcolor=self.ACCENT)
entry.pack(side="left", fill="x", expand=True, ipady=7, padx=(0, 8)) 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('<<Drop>>', lambda e, v=var, t=tag: self._on_drop(e, v, t))
btn = tk.Button(row, text="Browse", font=("Segoe UI", 9, "bold"), btn = tk.Button(row, text="Browse", font=("Segoe UI", 9, "bold"),
bg=self.ACCENT, fg="#ffffff", bg=self.ACCENT, fg="#ffffff",
activebackground=self.ACCENT_HOVER, activebackground=self.ACCENT_HOVER,
@ -517,6 +530,37 @@ class KoBackupDecGUI(tk.Tk):
) )
self.stop_btn.pack(side="left", padx=(10, 0)) 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( self.clear_log_btn = tk.Button(
btn_row, btn_row,
text="Clear Log", text="Clear Log",
@ -919,12 +963,14 @@ class KoBackupDecGUI(tk.Tk):
self._running = False self._running = False
self.progress.stop() self.progress.stop()
self._set_controls_running(False) self._set_controls_running(False)
self.open_output_btn.configure(state="disabled")
if stopped: if stopped:
self.status_var.set('⏹ Decryption stopped by user') self.status_var.set('⏹ Decryption stopped by user')
self._append_log('') self._append_log('')
self._append_log('WARNING: ⏹ Decryption was stopped by the user.') self._append_log('WARNING: ⏹ Decryption was stopped by the user.')
elif success: elif success:
self.open_output_btn.configure(state="normal")
self.status_var.set('✅ Decryption completed successfully!') self.status_var.set('✅ Decryption completed successfully!')
self._append_log('') self._append_log('')
self._append_log('=' * 50) self._append_log('=' * 50)
@ -939,6 +985,87 @@ class KoBackupDecGUI(tk.Tk):
'Decryption failed.\n' 'Decryption failed.\n'
'Check the log output for details.') '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 # Entry point