import 'dart:ui'; import 'package:flutter/material.dart'; import '../../app/theme.dart'; /// A blurred surface for stable application chrome only. /// /// Keep this out of scrollable content. Diagnostic rows and metric panels use /// [InstrumentPanel], which has the same visual language without creating a /// compositing layer per item. class FrostedChrome extends StatelessWidget { const FrostedChrome({ required this.child, super.key, this.borderRadius = BorderRadius.zero, }); final Widget child; final BorderRadius borderRadius; @override Widget build(BuildContext context) { final highContrast = MediaQuery.maybeOf(context)?.highContrast ?? false; final surface = _SurfaceFrame( borderRadius: borderRadius, chrome: true, opaque: highContrast, child: child, ); if (highContrast) { return surface; } return ClipRRect( borderRadius: borderRadius, child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), child: surface, ), ); } } /// An opaque, high-legibility panel for operational data and event rows. class InstrumentPanel extends StatelessWidget { const InstrumentPanel({ required this.child, super.key, this.borderRadius = const BorderRadius.all(Radius.circular(12)), this.accent, }); final Widget child; final BorderRadius borderRadius; final Color? accent; @override Widget build(BuildContext context) => _SurfaceFrame( borderRadius: borderRadius, accent: accent, opaque: true, child: child, ); } class _SurfaceFrame extends StatelessWidget { const _SurfaceFrame({ required this.child, required this.borderRadius, this.chrome = false, this.opaque = false, this.accent, }); final Widget child; final BorderRadius borderRadius; final bool chrome; final bool opaque; final Color? accent; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; final dark = scheme.brightness == Brightness.dark; final opacity = opaque ? 0xf6 : (dark ? 0xbf : 0xd9); final top = dark ? Color.fromARGB( opacity, chrome ? 12 : 16, chrome ? 17 : 23, chrome ? 14 : 18, ) : Color.fromARGB(opacity, 255, 255, 255); final bottom = dark ? Color.fromARGB(opacity, 8, 11, 9) : Color.fromARGB(opacity, 244, 248, 244); final border = accent?.withValues(alpha: 0.74) ?? scheme.outline.withValues(alpha: dark ? 0.92 : 0.82); return DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [top, bottom], ), border: Border.all(color: border), borderRadius: borderRadius, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: dark ? 0.18 : 0.06), blurRadius: 18, offset: const Offset(0, 8), ), ], ), child: child, ); } } /// The static canvas behind Ground Suite's chrome and instrument surfaces. class AppCanvas extends StatelessWidget { const AppCanvas({required this.child, super.key}); final Widget child; @override Widget build(BuildContext context) { final dark = Theme.of(context).brightness == Brightness.dark; final base = dark ? const Color(0xff080b09) : const Color(0xfff3f6f3); final primaryHaze = (dark ? accentGreen : const Color(0xff087a3b)) .withValues(alpha: dark ? 0.075 : 0.05); return ColoredBox( color: base, child: Stack( children: [ Positioned( top: -250, right: -200, child: IgnorePointer(child: _Haze(color: primaryHaze)), ), Positioned( bottom: -330, left: -260, child: IgnorePointer( child: _Haze(color: primaryHaze.withValues(alpha: 0.55)), ), ), Positioned.fill(child: child), ], ), ); } } class _Haze extends StatelessWidget { const _Haze({required this.color}); final Color color; @override Widget build(BuildContext context) => Container( width: 600, height: 600, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient(colors: [color, Colors.transparent]), ), ); } class ConsoleLabel extends StatelessWidget { const ConsoleLabel(this.text, {super.key, this.color}); final String text; final Color? color; @override Widget build(BuildContext context) => Text( text.toUpperCase(), style: Theme.of(context).textTheme.labelSmall?.copyWith( color: color ?? Theme.of(context).colorScheme.onSurfaceVariant, fontFamily: 'monospace', fontWeight: FontWeight.w700, letterSpacing: 1.25, ), ); } class StatusBadge extends StatelessWidget { const StatusBadge({required this.label, super.key, this.color}); final String label; final Color? color; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; final tone = color ?? scheme.onSurfaceVariant; return DecoratedBox( decoration: BoxDecoration( color: tone.withValues(alpha: 0.11), border: Border.all(color: tone.withValues(alpha: 0.45)), borderRadius: BorderRadius.circular(7), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 5), child: ConsoleLabel(label, color: tone), ), ); } }