import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mam_core/mam_core.dart'; import 'src/providers/session_providers.dart'; import 'src/theme/app_theme.dart'; import 'src/widgets/detail_pane.dart'; import 'src/widgets/session_table.dart'; import 'src/widgets/stale_banner.dart'; void main() { runApp(const ProviderScope(child: MamDesktopApp())); } class MamDesktopApp extends StatelessWidget { const MamDesktopApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'multi-agent-mux', debugShowCheckedModeBanner: false, theme: buildAppTheme(), home: const DashboardScreen(), ); } } class DashboardScreen extends ConsumerWidget { const DashboardScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final pollAsync = ref.watch(sessionsPollProvider); return Scaffold( body: DecoratedBox( decoration: const BoxDecoration(gradient: backgroundGradient), child: SafeArea( child: pollAsync.when( data: (poll) => _DashboardBody(poll: poll), loading: () => const Center(child: CircularProgressIndicator()), error: (error, stackTrace) => _ErrorScreen(error: error), ), ), ), ); } } class _ErrorScreen extends StatelessWidget { final Object error; const _ErrorScreen({required this.error}); @override Widget build(BuildContext context) { return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.error_outline, color: AppColors.danger, size: 40), const SizedBox(height: 12), Text( 'Failed to start status polling:\n$error', textAlign: TextAlign.center, style: const TextStyle(color: AppColors.danger), ), ], ), ), ); } } class _DashboardBody extends ConsumerWidget { final SessionsPoll poll; const _DashboardBody({required this.poll}); @override Widget build(BuildContext context, WidgetRef ref) { final selectedName = ref.watch(selectedSessionNameProvider); final sessions = poll.snapshot?.sessions ?? const []; final matches = sessions.where((s) => s.name == selectedName); final selectedRow = matches.isEmpty ? null : matches.first; return Column( children: [ _TopBar(poll: poll), StaleBanner(poll: poll), Expanded( child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Expanded( flex: 3, child: Padding( padding: const EdgeInsets.all(16), child: SessionTable( sessions: sessions, selectedName: selectedName, onSelect: (name) => ref.read(selectedSessionNameProvider.notifier).state = name, ), ), ), SizedBox(width: 380, child: DetailPane(session: selectedRow)), ], ), ), ], ); } } class _TopBar extends StatelessWidget { final SessionsPoll poll; const _TopBar({required this.poll}); @override Widget build(BuildContext context) { final count = poll.snapshot?.sessions.length ?? 0; return Padding( padding: const EdgeInsets.fromLTRB(20, 16, 20, 0), child: Row( children: [ const Text( 'multi-agent-mux', style: TextStyle( fontSize: 20, fontWeight: FontWeight.w700, color: AppColors.textPrimary, ), ), const SizedBox(width: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: AppColors.accent.withValues(alpha: 0.18), borderRadius: BorderRadius.circular(999), ), child: Text( '$count session${count == 1 ? '' : 's'}', style: const TextStyle( color: AppColors.accent2, fontWeight: FontWeight.w600, ), ), ), ], ), ); } }