import 'dart:async'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:iop_console/iop_console.dart'; import 'client_config.dart'; import 'iop_wire/client_wire_client.dart'; import 'src/integrations/mattermost/mattermost_push_host_integration.dart'; import 'src/integrations/mattermost/mattermost_push_plugin_client.dart'; final _mattermostHost = MattermostPushHostIntegration( pushClient: MattermostPushPluginClient(), ); const iopDefaultCapabilityPack = IopCapabilityPack( capabilities: [ IopCapability( name: 'Edge Control', description: 'Monitor and configure Edge routing groups.', ), IopCapability( name: 'Node Management', description: 'Track node registration and execution lanes.', ), IopCapability( name: 'Runtime Dispatch', description: 'Trigger manual adapter execution sessions.', ), IopCapability( name: 'Execution Tracing', description: 'View live logs and execution metrics stream.', ), IopCapability( name: 'Maintenance Mode', description: 'Trigger node bootstrap or cluster repairs.', ), ], ); Future main() => runIopClient(); Future applyFullscreenMode() async { await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Colors.transparent, systemNavigationBarColor: Colors.transparent, systemNavigationBarDividerColor: Colors.transparent, ), ); } Future bootstrapIopClient() async { await applyFullscreenMode(); await Firebase.initializeApp(); await _mattermostHost.initialize(); } Future runIopClient() async { WidgetsFlutterBinding.ensureInitialized(); await bootstrapIopClient(); runApp(IopClientApp(mattermostHost: _mattermostHost)); } class IopClientApp extends StatelessWidget { final ClientWireClient? testClient; final MattermostPushHostIntegration? mattermostHost; const IopClientApp({super.key, this.testClient, this.mattermostHost}); @override Widget build(BuildContext context) { return MaterialApp( title: 'IOP Client', debugShowCheckedModeBanner: false, theme: ThemeData.dark(useMaterial3: true).copyWith( colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFF6366F1), brightness: Brightness.dark, primary: const Color(0xFF6366F1), secondary: const Color(0xFF10B981), ), scaffoldBackgroundColor: const Color(0xFF0F172A), ), home: ClientHomePage( testClient: testClient, mattermostHost: mattermostHost, ), ); } } class ClientHomePage extends StatefulWidget { final ClientWireClient? testClient; final MattermostPushHostIntegration? mattermostHost; const ClientHomePage({super.key, this.testClient, this.mattermostHost}); @override State createState() => _ClientHomePageState(); } class _ClientHomePageState extends State { String _wireStatus = 'Disconnected'; ClientWireClient? _client; StreamSubscription? _notificationSubscription; @override void initState() { super.initState(); // Auto-connect on start WidgetsBinding.instance.addPostFrameCallback((_) { applyFullscreenMode(); _connectWire(); }); final host = widget.mattermostHost; if (host != null) { _notificationSubscription = host.onNotification.listen( _showMattermostNotification, ); } } @override void dispose() { _notificationSubscription?.cancel(); _client?.close(); super.dispose(); } void _showMattermostNotification(Map data) { if (data['type'] != 'message' || !mounted) return; final message = data['message'] as String? ?? ''; final channel = data['channel_name'] as String? ?? ''; final sender = data['sender_name'] as String? ?? ''; final content = sender.isNotEmpty ? '[$channel] $sender: $message' : message; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(content, maxLines: 2, overflow: TextOverflow.ellipsis), duration: const Duration(seconds: 4), behavior: SnackBarBehavior.floating, ), ); } Future _connectWire() async { if (!mounted) return; setState(() { _wireStatus = 'Connecting'; }); try { ClientWireClient client; if (widget.testClient != null) { client = widget.testClient!; } else { client = await ClientWireClient.connectToUrl( ClientConfig.controlPlaneWireUrl, ); } _client = client; // Hello handshake final response = await client.hello( clientId: 'client-ui', clientVersion: '1.0.0', ); if (!mounted) return; setState(() { _wireStatus = response.ready ? 'Connected' : 'Error'; }); client.addDisconnectListener((_) { if (!mounted) return; setState(() { _wireStatus = 'Disconnected'; _client = null; }); }); } catch (e) { if (!mounted) return; setState(() { _wireStatus = 'Error'; _client = null; }); } } @override Widget build(BuildContext context) { final config = IopConsoleConfig( controlPlaneHttpUrl: ClientConfig.controlPlaneHttpUrl, controlPlaneWireUrl: ClientConfig.controlPlaneWireUrl, ); return IopConsoleShell( config: config, capabilities: iopDefaultCapabilityPack, overview: IopConsoleOverview( config: config, statusText: _wireStatus, onRefresh: _connectWire, ), agent: const IopAgentPanel(capabilities: iopDefaultCapabilityPack), ); } }