// F∆I Studio — desktop GUI for the F∆I hub. // // MVP scope: three pages (Modules, Audit, Approvals) with mock // data, sharing one navigation shell. Live gRPC connection // arrives in the next iteration via fai_dart_sdk. import 'package:flutter/material.dart'; import 'pages/approvals.dart'; import 'pages/audit.dart'; import 'pages/modules.dart'; void main() { runApp(const StudioApp()); } class StudioApp extends StatelessWidget { const StudioApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'F∆I Studio', theme: ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFF1E3A8A), brightness: Brightness.light, ), ), darkTheme: ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFF1E3A8A), brightness: Brightness.dark, ), ), home: const StudioShell(), ); } } class StudioShell extends StatefulWidget { const StudioShell({super.key}); @override State createState() => _StudioShellState(); } class _StudioShellState extends State { int _selectedIndex = 0; static const _pages = <_NavPage>[ _NavPage( label: 'Modules', icon: Icons.extension_outlined, selectedIcon: Icons.extension, page: ModulesPage(), ), _NavPage( label: 'Audit', icon: Icons.timeline_outlined, selectedIcon: Icons.timeline, page: AuditPage(), ), _NavPage( label: 'Approvals', icon: Icons.inbox_outlined, selectedIcon: Icons.inbox, page: ApprovalsPage(), ), ]; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Scaffold( body: Row( children: [ NavigationRail( extended: true, minExtendedWidth: 180, selectedIndex: _selectedIndex, onDestinationSelected: (i) => setState(() => _selectedIndex = i), leading: Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Column( children: [ Icon(Icons.hub_outlined, size: 32, color: theme.colorScheme.primary), const SizedBox(height: 8), Text( 'F∆I Studio', style: theme.textTheme.titleMedium?.copyWith( color: theme.colorScheme.primary, fontWeight: FontWeight.w600, ), ), Text( 'connected: localhost:50051', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), ), destinations: _pages .map( (p) => NavigationRailDestination( icon: Icon(p.icon), selectedIcon: Icon(p.selectedIcon), label: Text(p.label), ), ) .toList(), ), const VerticalDivider(width: 1), Expanded(child: _pages[_selectedIndex].page), ], ), ); } } class _NavPage { final String label; final IconData icon; final IconData selectedIcon; final Widget page; const _NavPage({ required this.label, required this.icon, required this.selectedIcon, required this.page, }); }