Skip to main content

Overview

The UI class (core/ui.py:31) provides a beautiful, consistent terminal interface using the Rich library. It handles all visual output including headers, menus, tables, progress bars, and formatted messages with custom theming.

Class Definition

core/ui.py
class UI:
    def __init__(self):
        self.console = console
        self._status = {
            "device": "None",
            "mode": "ADB",
            "os": f"{platform.system()} {platform.release()}",
            "python": platform.python_version(),
            "key": "Not Loaded"
        }
Singleton Pattern:
  • A global ui instance is created at module level: ui = UI()
  • Use the global instance throughout your application

Constructor

__init__()

Initializes the UI with system information and status tracking. Attributes:
  • console: Rich Console instance with custom theme
  • _status: Dictionary tracking application state:
    • device: Connected device identifier
    • mode: Operation mode (“ADB” or “Termux”)
    • os: Operating system and version
    • python: Python version
    • key: Encryption key status

Status Management

update_status()

Updates a status field displayed in the header.
def update_status(self, key: str, value: str)
key
str
required
Status field name (“device”, “mode”, “os”, “python”, “key”)
value
str
required
New value for the status field
Example:
from core.ui import ui

ui.update_status("device", "RF8N70PQRST")
ui.update_status("key", "Loaded")

Display Methods

Displays the application header with title and system information panel.
def print_header(self)
Features:
  • Clears screen automatically
  • Shows “WhatsApp Backup Forensic Tool v2.0” title
  • Displays system info panel with:
    • OS and Python version
    • Operation mode (ADB/Termux)
    • Connected device
    • Encryption key status with color coding
Example:
from core.ui import ui

ui.print_header()
Displays a formatted menu with numbered options in a Rich table.
def print_menu(self, title: str, options: List[str])
title
str
required
Menu title displayed in panel border
options
List[str]
required
List of menu option descriptions (auto-numbered starting from 1)
Example:
ui.print_menu("Main Menu", [
    "Connect Device",
    "Dump Backup Files",
    "Decrypt Database",
    "View Chats",
    "Export Data",
    "Exit"
])
Displays data in a formatted Rich table.
def print_table(self, title: str, headers: List[str], rows: List[List[str]])
title
str
required
Table title
headers
List[str]
required
Column header names
rows
List[List[str]]
required
List of row data (each row is a list of strings)
Example:
ui.print_table(
    "Available Chats",
    ["ID", "Name", "Messages", "Last Active"],
    [
        ["1", "John Doe", "453", "2024-03-05"],
        ["2", "Work Group", "1204", "2024-03-04"],
        ["3", "Mom", "2891", "2024-03-05"]
    ]
)

Message Output

Displays an informational message with cyan “[INFO]” prefix.
def print_info(self, msg: str)
msg
str
required
Information message to display
Example:
ui.print_info("Connecting to device...")
Displays a success message with green “[SUCCESS]” prefix.
def print_success(self, msg: str)
msg
str
required
Success message to display
Example:
ui.print_success("Database decrypted successfully!")
Displays a warning message with yellow “[WARNING]” prefix.
def print_warning(self, msg: str)
msg
str
required
Warning message to display
Example:
ui.print_warning("No encryption key found for this device")
Displays an error message in a prominent red panel.
def print_error(self, msg: str)
msg
str
required
Error message to display
Example:
ui.print_error("Failed to connect to device. Check ADB connection.")

Interactive Input

ask()

Prompts the user for text input with optional default value and choices.
def ask(self, question: str, default: str = None, choices: List[str] = None) -> str
question
str
required
Question prompt displayed to user
default
str
default:"None"
Default value if user presses Enter without input
choices
List[str]
default:"None"
List of valid choices. User input will be validated against this list.
return
str
User’s input string
Example:
# Simple text input
name = ui.ask("Enter device name")

# With default value
package = ui.ask("WhatsApp package", default="com.whatsapp")

# With choices (validated)
format_choice = ui.ask(
    "Select export format",
    choices=["csv", "json", "html", "txt"]
)

confirm()

Prompts the user for a yes/no confirmation.
def confirm(self, question: str, default: bool = True) -> bool
question
str
required
Confirmation question
default
bool
default:"True"
Default answer if user presses Enter
return
bool
True if user confirmed, False otherwise
Example:
if ui.confirm("Overwrite existing file?", default=False):
    # User confirmed
    save_file()
else:
    # User declined
    ui.print_info("Operation cancelled")

Progress Indicators

create_progress()

Creates a Rich Progress bar for tracking long-running operations.
def create_progress(self, desc: str, total: int = None) -> Progress
desc
str
required
Description displayed next to progress bar
total
int
default:"None"
Total number of items (None for indeterminate progress)
return
Progress
Rich Progress instance with spinner, bar, percentage, and time remaining
Example:
with ui.create_progress("Dumping files", total=100) as progress:
    task = progress.add_task("Processing", total=100)
    
    for i in range(100):
        # Do work
        time.sleep(0.1)
        progress.update(task, advance=1)

spinner()

Creates a spinner context manager for operations without progress tracking.
def spinner(self, text: str)
text
str
required
Status text displayed with spinner
Returns: Context manager that displays an animated spinner Example:
with ui.spinner("Connecting to device..."):
    device.connect()
    time.sleep(2)

ui.print_success("Connected!")

Chat Display

Displays a WhatsApp message with formatted timestamp and sender.
def print_message(self, msg: Dict[str, Any])
msg
Dict[str, Any]
required
Message dictionary containing:
  • from_me (bool): Whether message was sent by user
  • timestamp (int): Unix timestamp
  • sender (str): Sender name
  • text (str): Message content
Formatting:
  • Sent messages: Green color, right-aligned
  • Received messages: Cyan sender name, left-aligned
  • Timestamp automatically formatted as “HH:MM DD/MM”
Example:
messages = viewer.get_messages(chat_id, chat_jid, limit=50)

for msg in messages:
    ui.print_message(msg)
Displays a summary panel with session statistics.
def print_session_summary(self, summary: Dict)
summary
Dict
required
Summary dictionary containing:
  • dumped (int): Number of files dumped
  • decrypted (int): Number of databases decrypted
  • exports (int): Number of exports created
Example:
summary = {
    "dumped": 15,
    "decrypted": 3,
    "exports": 2
}

ui.print_session_summary(summary)

Utility Methods

clear()

Clears the terminal screen.
def clear(self)
Example:
ui.clear()

Custom Theme

The UI uses a custom Rich theme with predefined styles:
custom_theme = Theme({
    "info": "cyan",
    "warning": "yellow",
    "error": "bold red",
    "success": "bold green",
    "header": "bold white on blue",
    "highlight": "bold magenta",
    "border": "blue",
    "key": "bold yellow"
})

Complete Usage Example

from core.ui import ui
import time

# Display header
ui.print_header()

# Update status
ui.update_status("device", "RF8N70PQRST")
ui.update_status("key", "Loaded")

# Show menu
ui.print_menu("Main Menu", [
    "Dump Backup Files",
    "Decrypt Database",
    "View Chats",
    "Export Data",
    "Exit"
])

# Get user choice
choice = ui.ask("Select option", choices=["1", "2", "3", "4", "5"])

if choice == "1":
    # Show spinner for connection
    with ui.spinner("Connecting to device..."):
        time.sleep(2)
    
    ui.print_success("Connected successfully!")
    
    # Show progress for file transfer
    files = [f"file{i}.db" for i in range(10)]
    with ui.create_progress("Dumping files", total=len(files)) as progress:
        task = progress.add_task("Copying", total=len(files))
        
        for file in files:
            # Transfer file
            time.sleep(0.5)
            progress.update(task, advance=1)
    
    ui.print_success(f"Dumped {len(files)} files")

elif choice == "3":
    # Display chat list
    ui.print_table(
        "Available Chats",
        ["ID", "Name", "Messages"],
        [
            ["1", "John Doe", "453"],
            ["2", "Work Group", "1204"],
            ["3", "Mom", "2891"]
        ]
    )
    
    # Get selection
    chat_id = ui.ask("Enter chat ID to view")
    
    # Display messages
    ui.print_info(f"Viewing chat {chat_id}")
    
    # Sample messages
    messages = [
        {
            "from_me": False,
            "timestamp": 1709654400000,
            "sender": "John Doe",
            "text": "Hey, how are you?"
        },
        {
            "from_me": True,
            "timestamp": 1709654460000,
            "sender": "Me",
            "text": "I'm good, thanks!"
        }
    ]
    
    for msg in messages:
        ui.print_message(msg)

elif choice == "5":
    if ui.confirm("Are you sure you want to exit?"):
        ui.print_info("Goodbye!")
        exit(0)

# Show session summary
summary = {
    "dumped": 15,
    "decrypted": 3,
    "exports": 2
}
ui.print_session_summary(summary)

Main Application

See the UI in action in main.py

Viewer

Display chat data using the Viewer class

Rich Documentation

Learn more about Rich library features

Custom Themes

Customize the UI theme

Build docs developers (and LLMs) love