import 'package:flutter/material.dart'; import 'iop_console_contract.dart'; /// A rich, highly-aesthetic overview panel for visualizing IOP Control Plane configuration and status. class IopConsoleOverview extends StatefulWidget { final IopConsoleConfig config; final String statusText; final VoidCallback? onRefresh; const IopConsoleOverview({ super.key, required this.config, required this.statusText, this.onRefresh, }); @override State createState() => _IopConsoleOverviewState(); } class _IopConsoleOverviewState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _glowAnimation; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(seconds: 2), )..repeat(reverse: true); _glowAnimation = Tween(begin: 4.0, end: 12.0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); } bool get _isConnected => widget.statusText.trim().toLowerCase() == 'connected'; @override Widget build(BuildContext context) { final statusColor = _isConnected ? const Color(0xFF10B981) : const Color(0xFFEF4444); return Container( color: const Color(0xFF0F172A), padding: const EdgeInsets.all(24.0), child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 800), child: LayoutBuilder( builder: (context, constraints) { final isNarrow = constraints.maxWidth < 600; final headerText = const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'IOP CONTROL PLANE', style: TextStyle( color: Color(0xFF10B981), fontSize: 12, fontWeight: FontWeight.bold, letterSpacing: 2.0, ), ), SizedBox(height: 4), Text( 'Operations Overview', style: TextStyle( color: Colors.white, fontSize: 28, fontWeight: FontWeight.w800, letterSpacing: -0.5, ), ), ], ); final badge = AnimatedBuilder( animation: _glowAnimation, builder: (context, child) { return Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), decoration: BoxDecoration( color: statusColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(20), border: Border.all( color: statusColor.withValues(alpha: 0.5), width: 1.5, ), boxShadow: [ BoxShadow( color: statusColor.withValues(alpha: 0.2), blurRadius: _glowAnimation.value, spreadRadius: 1, ), ], ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 8, height: 8, decoration: BoxDecoration( color: statusColor, shape: BoxShape.circle, ), ), const SizedBox(width: 8), Flexible( child: Text( widget.statusText.toUpperCase(), overflow: TextOverflow.ellipsis, maxLines: 1, style: TextStyle( color: statusColor, fontSize: 12, fontWeight: FontWeight.w800, letterSpacing: 1.0, ), ), ), ], ), ); }, ); final header = isNarrow ? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ headerText, const SizedBox(height: 16), badge, ], ) : Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: headerText), const SizedBox(width: 24), badge, ], ); final statsList = [ _buildStatTile( 'Status', _isConnected ? 'ACTIVE WIRE' : 'OFFLINE', _isConnected ? const Color(0xFF10B981) : const Color(0xFF94A3B8), ), _buildStatTile( 'Protocol', 'Proto-Socket / WS', const Color(0xFF3B82F6), ), ]; final statsSection = isNarrow ? Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ statsList[0], const SizedBox(height: 16), statsList[1], ], ) : Row( children: [ Expanded(child: statsList[0]), const SizedBox(width: 16), Expanded(child: statsList[1]), ], ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ header, const SizedBox(height: 32), Expanded( child: ListView( children: [ _buildSectionHeader( 'SYSTEM ENDPOINTS', Icons.lan_outlined, ), const SizedBox(height: 12), _buildEndpointCard( title: 'Control Plane HTTP REST API', url: widget.config.controlPlaneHttpUrl, icon: Icons.http_outlined, ), const SizedBox(height: 16), _buildEndpointCard( title: 'Control Plane WebSocket Wire', url: widget.config.controlPlaneWireUrl, icon: Icons.swap_calls_outlined, ), const SizedBox(height: 32), _buildSectionHeader( 'WIRE PERFORMANCE & HEALTH', Icons.analytics_outlined, ), const SizedBox(height: 12), statsSection, const SizedBox(height: 32), _buildSectionHeader( 'AUTHENTICATION & WIRE SECURITY', Icons.security_outlined, ), const SizedBox(height: 12), _buildEndpointCard( title: 'Active Auth Token Reference', url: widget.config.authTokenReference != null && widget.config.authTokenReference!.isNotEmpty ? widget.config.authTokenReference! : 'None (Unauthenticated / Public)', icon: Icons.key_outlined, ), const SizedBox(height: 32), if (widget.onRefresh != null) Align( alignment: Alignment.centerLeft, child: _buildRefreshButton(), ), ], ), ), ], ); }, ), ), ), ); } Widget _buildSectionHeader(String title, IconData icon) { return Row( children: [ Icon(icon, color: const Color(0xFF10B981), size: 18), const SizedBox(width: 8), Expanded( child: Text( title, overflow: TextOverflow.ellipsis, maxLines: 1, style: const TextStyle( color: Colors.white70, fontSize: 13, fontWeight: FontWeight.w700, letterSpacing: 1.0, ), ), ), ], ); } Widget _buildEndpointCard({ required String title, required String url, required IconData icon, }) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFF334155), width: 1), ), child: Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFF0F172A), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, color: const Color(0xFF10B981), size: 20), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( color: Colors.white54, fontSize: 12, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 4), Text( url, overflow: TextOverflow.ellipsis, maxLines: 1, style: const TextStyle( color: Colors.white, fontFamily: 'monospace', fontSize: 14, fontWeight: FontWeight.w600, ), ), ], ), ), ], ), ); } Widget _buildStatTile(String label, String value, Color valueColor) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFF334155), width: 1), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle( color: Colors.white54, fontSize: 11, fontWeight: FontWeight.w600, letterSpacing: 0.5, ), ), const SizedBox(height: 6), Text( value, style: TextStyle( color: valueColor, fontSize: 16, fontWeight: FontWeight.bold, ), ), ], ), ); } Widget _buildRefreshButton() { return Material( color: Colors.transparent, child: InkWell( onTap: widget.onRefresh, borderRadius: BorderRadius.circular(12), child: Ink( decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF10B981), Color(0xFF059669)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: const Color(0xFF10B981).withValues(alpha: 0.3), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Container( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.refresh_outlined, color: Colors.white, size: 18), SizedBox(width: 10), Text( 'Refresh Connection', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14, ), ), ], ), ), ), ), ); } }