""" Search History Screen for YouTube TUI """ import json from pathlib import Path from textual.app import ComposeResult from textual.containers import Container from textual.screen import ModalScreen from textual.widgets import Footer, Header, ListItem, ListView, Static class SearchHistoryScreen(ModalScreen): """Screen showing search history""" CSS = """ SearchHistoryScreen { align: center middle; } #history-container { width: 70%; height: 70%; border: solid #555555; background: $surface; padding: 1; } #history-title { width: 100%; height: 3; dock: top; background: $primary; content-align: center middle; color: $text; } ListView { width: 100%; height: 100%; } ListItem { height: 3; padding: 0 1; } ListItem:hover { background: $primary-darken-2; } ListItem.--highlight { background: $primary; } .history-item { height: 3; } .history-time { color: $text-muted; } #clear-btn { margin: 1 1; } """ BINDINGS = [ ("escape", "close_history", "Close"), ("q", "close_history", "Close"), ("d", "delete_selected", "Delete Selected"), ("c", "clear_all", "Clear All"), ] def __init__(self): super().__init__() self.history_file = ( Path.home() / ".config" / "youtube_cli" / "search_history.json" ) self.search_history = [] def compose(self) -> ComposeResult: """Compose the history screen""" yield Header() yield Container( Static("Search History", id="history-title"), ListView(id="history-list"), id="history-container", ) yield Footer() def on_mount(self) -> None: """Load history on mount""" self.load_history() def load_history(self) -> None: """Load search history from file""" self.search_history = [] if self.history_file.exists(): try: with open(self.history_file, "r") as f: self.search_history = json.load(f) except Exception: self.search_history = [] # Reverse to show newest first self.search_history = list(reversed(self.search_history)) list_view = self.query_one("#history-list", ListView) list_view.clear() for item in self.search_history: search_term = item.get("search_term", "") timestamp = item.get("timestamp", "") # Format timestamp if timestamp: try: from datetime import datetime dt = datetime.fromisoformat(timestamp) time_str = dt.strftime("%Y-%m-%d %H:%M") except Exception: time_str = timestamp else: time_str = "Unknown time" list_view.append( ListItem(Static(f"[bold]{search_term}[/bold]\n[dim]{time_str}[/dim]")) ) def action_delete_selected(self) -> None: """Delete selected history item""" list_view = self.query_one("#history-list", ListView) if list_view.children: # Get the selected item selected_index = list_view.index if ( selected_index is not None and selected_index >= 0 and selected_index < len(self.search_history) ): # Remove from history del self.search_history[selected_index] self.save_history() self.load_history() def action_clear_all(self) -> None: """Clear all history""" self.search_history = [] self.save_history() self.load_history() self.notify("Search history cleared", timeout=2) def save_history(self) -> None: """Save history to file""" try: # Ensure directory exists self.history_file.parent.mkdir(parents=True, exist_ok=True) with open(self.history_file, "w") as f: json.dump(list(reversed(self.search_history)), f, indent=2) except Exception as e: self.notify(f"Error saving history: {e}", severity="error", timeout=3) def action_close_history(self) -> None: """Close the history screen""" self.app.pop_screen() def on_list_view_selected(self, event: ListView.Selected) -> None: """Handle item selection""" # Use event.index directly, ignore list_view item_index = event.index if 0 <= item_index < len(self.search_history): # Get the search term search_term = self.search_history[item_index].get("search_term", "") # Push search screen with the term self.app.push_screen("search") # Note: We'd need to expose the search screen to set the term # For now, just notify self.notify(f"Selected: {search_term}", timeout=2)