""" Frontend Application - Main UI for Vision OS """ import sys import os from pathlib import Path from typing import Dict, List, Any, Optional from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTextEdit, QLineEdit, QTabWidget, QSplitter, QFrame, QStackedWidget, QScrollArea, QFileDialog) from PyQt5.QtGui import QFont, QColor, QPixmap, QIcon, QPainter, QBrush, QLinearGradient from PyQt5.QtCore import Qt, QSize, QTimer, QPropertyAnimation, QEasingCurve, QRect # Import core components from agents.orchestrator import AgentOrchestrator from memory.memory_manager import MemoryManager # Import UI components from frontend.components.chat_panel import ChatPanel from frontend.components.task_panel import TaskPanel from frontend.components.web_panel import WebAutomationPanel from frontend.components.file_panel import FilePanel from frontend.components.settings_panel import SettingsPanel from frontend.components.project_panel import ProjectPanel from frontend.theme import ThemeManager class VisionOSApp: """ Main application class for Vision OS """ def __init__(self, config: Dict[str, Any], agent_orchestrator: AgentOrchestrator, memory_manager: MemoryManager): """ Initialize the Vision OS application Args: config: Application configuration agent_orchestrator: Agent orchestrator instance memory_manager: Memory manager instance """ self.config = config self.agent_orchestrator = agent_orchestrator self.memory_manager = memory_manager self.app = QApplication(sys.argv) self.theme_manager = ThemeManager(config.get("theme", "dark")) # Apply theme to application self.apply_theme() # Create main window self.main_window = MainWindow(config, agent_orchestrator, memory_manager, self.theme_manager) def run(self): """Run the application""" self.main_window.show() sys.exit(self.app.exec_()) def apply_theme(self): """Apply theme to application""" # Set application style sheet style_sheet = self.theme_manager.get_application_style() self.app.setStyleSheet(style_sheet) class MainWindow(QMainWindow): """ Main window for Vision OS application """ def __init__(self, config: Dict[str, Any], agent_orchestrator: AgentOrchestrator, memory_manager: MemoryManager, theme_manager: ThemeManager): """ Initialize the main window Args: config: Application configuration agent_orchestrator: Agent orchestrator instance memory_manager: Memory manager instance theme_manager: Theme manager instance """ super().__init__() self.config = config self.agent_orchestrator = agent_orchestrator self.memory_manager = memory_manager self.theme_manager = theme_manager # Set window properties self.setWindowTitle(f"{config.get('app_name', 'Vision OS')} v{config.get('version', '1.0.0')}") self.setMinimumSize(1200, 800) # Create UI self.init_ui() def init_ui(self): """Initialize the user interface""" # Create central widget central_widget = QWidget() self.setCentralWidget(central_widget) # Create main layout main_layout = QVBoxLayout(central_widget) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) # Create header header = self.create_header() main_layout.addWidget(header) # Create content area content = self.create_content() main_layout.addWidget(content, 1) # 1 = stretch factor # Create command bar command_bar = self.create_command_bar() main_layout.addWidget(command_bar) def create_header(self) -> QWidget: """Create the header widget""" header = QWidget() header.setObjectName("header") header.setFixedHeight(60) layout = QHBoxLayout(header) layout.setContentsMargins(20, 0, 20, 0) # Logo and title logo_label = QLabel("VISION OS") logo_label.setObjectName("logo") logo_label.setFont(QFont("SF Pro Display", 18, QFont.Bold)) # Spacer spacer = QWidget() spacer.setSizePolicy(QWidget.QSizePolicy.Expanding, QWidget.QSizePolicy.Preferred) # Navigation buttons nav_buttons = QWidget() nav_layout = QHBoxLayout(nav_buttons) nav_layout.setContentsMargins(0, 0, 0, 0) nav_layout.setSpacing(10) for name in ["Chat", "Tasks", "Web", "Files", "Projects"]: button = QPushButton(name) button.setObjectName("nav-button") button.setFixedSize(100, 40) button.clicked.connect(lambda checked, n=name: self.switch_panel(n.lower())) nav_layout.addWidget(button) # Settings button settings_button = QPushButton("Settings") settings_button.setObjectName("settings-button") settings_button.setFixedSize(40, 40) settings_button.clicked.connect(lambda: self.switch_panel("settings")) # Add widgets to layout layout.addWidget(logo_label) layout.addWidget(spacer) layout.addWidget(nav_buttons) layout.addWidget(settings_button) return header def create_content(self) -> QWidget: """Create the content widget""" content = QWidget() content.setObjectName("content") layout = QVBoxLayout(content) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # Create stacked widget for different panels self.stacked_widget = QStackedWidget() # Create panels self.chat_panel = ChatPanel(self.agent_orchestrator, self.memory_manager, self.theme_manager) self.task_panel = TaskPanel(self.agent_orchestrator, self.memory_manager, self.theme_manager) self.web_panel = WebAutomationPanel(self.agent_orchestrator, self.memory_manager, self.theme_manager) self.file_panel = FilePanel(self.agent_orchestrator, self.memory_manager, self.theme_manager) self.project_panel = ProjectPanel(self.agent_orchestrator, self.memory_manager, self.theme_manager) self.settings_panel = SettingsPanel(self.config, self.theme_manager) # Add panels to stacked widget self.stacked_widget.addWidget(self.chat_panel) self.stacked_widget.addWidget(self.task_panel) self.stacked_widget.addWidget(self.web_panel) self.stacked_widget.addWidget(self.file_panel) self.stacked_widget.addWidget(self.project_panel) self.stacked_widget.addWidget(self.settings_panel) # Set default panel self.stacked_widget.setCurrentWidget(self.chat_panel) layout.addWidget(self.stacked_widget) return content def create_command_bar(self) -> QWidget: """Create the command bar widget""" command_bar = QWidget() command_bar.setObjectName("command-bar") command_bar.setFixedHeight(60) layout = QHBoxLayout(command_bar) layout.setContentsMargins(20, 10, 20, 10) # Command input self.command_input = QLineEdit() self.command_input.setObjectName("command-input") self.command_input.setPlaceholderText("What would you like to create today?") self.command_input.returnPressed.connect(self.process_command) # Voice button voice_button = QPushButton() voice_button.setObjectName("voice-button") voice_button.setFixedSize(40, 40) voice_button.setIcon(QIcon("frontend/assets/mic.png")) voice_button.setIconSize(QSize(20, 20)) voice_button.clicked.connect(self.toggle_voice_input) # Add widgets to layout layout.addWidget(self.command_input) layout.addWidget(voice_button) return command_bar def switch_panel(self, panel_name: str): """ Switch to the specified panel Args: panel_name: Name of the panel to switch to """ panel_map = { "chat": self.chat_panel, "tasks": self.task_panel, "web": self.web_panel, "files": self.file_panel, "projects": self.project_panel, "settings": self.settings_panel } if panel_name in panel_map: self.stacked_widget.setCurrentWidget(panel_map[panel_name]) def process_command(self): """Process the command from the command bar""" command = self.command_input.text() if not command: return # Clear command input self.command_input.clear() # Process command through agent orchestrator response = self.agent_orchestrator.route_request(command) # Switch to appropriate panel based on agent response agent_panel_map = { "task": "tasks", "ui": "projects", "grant": "projects", "file": "files", "system": "chat", "automation": "web", "memory": "chat", "creative": "projects" } if "agent" in response and response["agent"] in agent_panel_map: self.switch_panel(agent_panel_map[response["agent"]]) # Update the current panel with the response current_panel = self.stacked_widget.currentWidget() if hasattr(current_panel, "update_with_response"): current_panel.update_with_response(command, response) def toggle_voice_input(self): """Toggle voice input for commands""" # This would be implemented with Whisper.cpp integration # For now, just show a placeholder message self.command_input.setText("Voice input coming soon...") QTimer.singleShot(2000, self.command_input.clear)