项目文件夹

文件
2025-12-13 01:23:24 +08:00

114 行
4.9 KiB
Python

"""Splash screen component with ASCII banner for PentestGPT TUI."""
from collections.abc import Iterator
from typing import TYPE_CHECKING, Any
from rich.align import Align
from rich.console import Group
from rich.style import Style
from rich.text import Text
from textual.widgets import Static
if TYPE_CHECKING:
from textual.timer import Timer
class SplashScreen(Static):
"""Animated splash screen with ASCII banner and loading indicator."""
# Color scheme - modern indigo/purple
PRIMARY_COLOR = "#6366f1"
SECONDARY_COLOR = "#8b5cf6"
# ASCII Art Banner - Clean and modern design
BANNER = """
██████╗ ███████╗███╗ ██╗████████╗███████╗███████╗████████╗ ██████╗ ██████╗ ████████╗
██╔══██╗██╔════╝████╗ ██║╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝██╔════╝ ██╔══██╗╚══██╔══╝
██████╔╝█████╗ ██╔██╗ ██║ ██║ █████╗ ███████╗ ██║ ██║ ███╗██████╔╝ ██║
██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██╔══╝ ╚════██║ ██║ ██║ ██║██╔═══╝ ██║
██║ ███████╗██║ ╚████║ ██║ ███████╗███████║ ██║ ╚██████╔╝██║ ██║
╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
"""
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""Initialize splash screen."""
super().__init__(*args, **kwargs)
self._animation_step = 0
self._animation_timer: Timer | None = None
self._panel_static: Static | None = None
self._version = "1.0.0"
def compose(self) -> Iterator[Static]:
"""Create the splash screen content."""
self._animation_step = 0
loading_text = self._build_loading_text(self._animation_step)
content = self._build_content(loading_text)
panel_static = Static(content, id="splash_content")
self._panel_static = panel_static
yield panel_static
def on_mount(self) -> None:
"""Start animation when mounted."""
self._animation_timer = self.set_interval(0.4, self._animate_loading)
def on_unmount(self) -> None:
"""Stop animation when unmounted."""
if self._animation_timer is not None:
self._animation_timer.stop()
self._animation_timer = None
def _animate_loading(self) -> None:
"""Animate the loading indicator."""
if not self._panel_static:
return
self._animation_step = (self._animation_step + 1) % 4
loading_text = self._build_loading_text(self._animation_step)
content = self._build_content(loading_text)
self._panel_static.update(content)
def _build_content(self, loading_text: Text) -> Group:
"""Build the complete splash screen content."""
# Banner with gradient effect
banner_text = Text(self.BANNER.strip("\n"), justify="center")
banner_text.stylize(self.PRIMARY_COLOR)
# Title line
title_text = Text()
title_text.append("AI-Powered ", style=Style(color="#a3a3a3"))
title_text.append("Penetration Testing", style=Style(color=self.PRIMARY_COLOR, bold=True))
title_text.append(" Assistant", style=Style(color="#a3a3a3"))
# Version
version_text = Text(f"v{self._version}", style=Style(color="#525252", dim=True))
# Tagline
tagline_text = Text(
"AI Security Agent", style=Style(color=self.SECONDARY_COLOR, italic=True)
)
return Group(
Align.center(banner_text),
Align.center(Text(" ")),
Align.center(title_text),
Align.center(version_text),
Align.center(Text(" ")),
Align.center(tagline_text),
Align.center(Text(" ")),
Align.center(Text(" ")),
Align.center(loading_text),
)
def _build_loading_text(self, phase: int) -> Text:
"""Build animated loading text with dots."""
dots = "." * phase
spaces = " " * (3 - phase)
text = Text()
text.append("Initializing", style=Style(color=self.PRIMARY_COLOR, bold=True))
text.append(dots, style=Style(color=self.SECONDARY_COLOR))
text.append(spaces) # Keep consistent width
return text