"""Modal for displaying files/URLs to access in web mode.""" from textual.screen import ModalScreen from textual.containers import Container, Vertical, Horizontal from textual.widgets import Static, Button, Label from textual.app import ComposeResult import logging logger = logging.getLogger(__name__) class AccessModal(ModalScreen): """Modal to display a file/URL that can be accessed from phone browser.""" CSS = """ Screen { align: center middle; } #access-container { width: 80; height: auto; border: thick $primary; background: $surface; } #access-header { dock: top; height: 3; background: $boost; border-bottom: solid $accent; content-align: center middle; } #access-content { height: auto; width: 1fr; padding: 1 2; border-bottom: solid $accent; } #access-footer { dock: bottom; height: 3; background: $boost; border-top: solid $accent; align: center middle; } .access-url { width: 1fr; height: auto; margin-bottom: 1; border: solid $accent; padding: 1; } .access-label { width: 1fr; height: auto; margin-bottom: 1; } Button { margin-right: 1; } """ def __init__(self, title: str, content: str, is_url: bool = False): """Initialize access modal. Args: title: Title of the item being accessed content: The URL or file path is_url: Whether this is a URL (True) or file path (False) """ super().__init__() self.item_title = title self.item_content = content self.is_url = is_url def compose(self) -> ComposeResult: """Create the modal layout.""" with Container(id="access-container"): with Vertical(id="access-header"): yield Label(f"[bold]{self.item_title}[/bold]") yield Label("[dim]Click link below to open in your browser[/dim]") with Vertical(id="access-content"): if self.is_url: yield Label("[bold cyan]Link:[/bold cyan]", classes="access-label") else: yield Label("[bold cyan]File:[/bold cyan]", classes="access-label") # Display as clickable link using HTML link element for web mode # Rich link markup `[link=URL]` has parsing issues with URLs containing special chars # Instead, use the HTML link markup that Textual-serve renders as tag # Format: [link=URL "tooltip"]text[/link] - the quotes help with parsing link_text = f'[link="{self.item_content}"]Open in Browser[/link]' content_box = Static(link_text, classes="access-url") yield content_box # Also show the URL for reference/copying yield Label(self.item_content, classes="access-label") yield Label("\n[yellow]↑ Click the link above to open on your device[/yellow]", classes="access-label") with Horizontal(id="access-footer"): yield Button("Copy URL", id="copy-btn", variant="primary") yield Button("Close", id="close-btn", variant="default") def on_button_pressed(self, event: Button.Pressed) -> None: """Handle button presses.""" if event.button.id == "copy-btn": # Copy to clipboard (optional - not critical if fails) logger.info(f"Attempting to copy: {self.item_content}") try: # Try to use pyperclip if available try: import pyperclip pyperclip.copy(self.item_content) logger.info("URL copied to clipboard via pyperclip") except ImportError: # Fallback: try xclip on Linux or pbcopy on Mac import subprocess import sys if sys.platform == "win32": # Windows: use clipboard via pyperclip (already tried) logger.debug("Windows clipboard not available without pyperclip") else: # Linux/Mac process = subprocess.Popen(['xclip', '-selection', 'clipboard'], stdin=subprocess.PIPE) process.communicate(self.item_content.encode('utf-8')) logger.info("URL copied to clipboard via xclip") except Exception as e: logger.debug(f"Clipboard copy not available: {e}") # Not critical - just informational elif event.button.id == "close-btn": self.dismiss()