import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; /// NetDesk design tokens + [ThemeData]. /// /// A single, dark, premium theme in the spirit of TeamViewer / RustDesk — /// deep near-black surfaces, a confident green accent, generous spacing and /// softly rounded cards. All colors live here as tokens so the rest of the /// app never hardcodes a hex value. class NetDeskColors { NetDeskColors._(); /// App background — deep, near-black with a cool blue cast. static const Color background = Color(0xFF0B0F15); /// Raised surface (cards, panels) — one step lighter than the background. static const Color surface = Color(0xFF121821); /// A second elevation used for inputs / inset wells. static const Color surfaceAlt = Color(0xFF0E141C); /// Hairline borders and dividers. static const Color border = Color(0xFF1E2733); /// Primary brand accent — a vivid, trustworthy green. static const Color accent = Color(0xFF22C55E); /// Darker accent for pressed / gradient ends. static const Color accentDeep = Color(0xFF16A34A); /// Soft accent glow used sparingly behind the wordmark. static const Color accentGlow = Color(0x3322C55E); /// High-emphasis text. static const Color textPrimary = Color(0xFFF2F5F9); /// Medium-emphasis text (subtitles, labels). static const Color textSecondary = Color(0xFF9AA7B8); /// Low-emphasis text (hints, captions). static const Color textMuted = Color(0xFF5E6B7D); /// Destructive / disconnect actions. static const Color danger = Color(0xFFEF4444); } class NetDeskRadius { NetDeskRadius._(); static const double sm = 8; static const double md = 12; static const double lg = 16; static const double xl = 22; } class NetDeskSpacing { NetDeskSpacing._(); static const double xs = 6; static const double sm = 10; static const double md = 16; static const double lg = 24; static const double xl = 36; } class NetDeskTheme { NetDeskTheme._(); static ThemeData get dark { const scheme = ColorScheme.dark( primary: NetDeskColors.accent, onPrimary: Color(0xFF04210F), secondary: NetDeskColors.accentDeep, onSecondary: Color(0xFF04210F), surface: NetDeskColors.surface, onSurface: NetDeskColors.textPrimary, error: NetDeskColors.danger, onError: Colors.white, outline: NetDeskColors.border, ); final base = ThemeData.dark(useMaterial3: true); return base.copyWith( colorScheme: scheme, scaffoldBackgroundColor: NetDeskColors.background, canvasColor: NetDeskColors.background, dividerColor: NetDeskColors.border, splashFactory: InkSparkle.splashFactory, textTheme: base.textTheme .apply( bodyColor: NetDeskColors.textPrimary, displayColor: NetDeskColors.textPrimary, fontFamily: 'Roboto', ) .copyWith( bodyMedium: const TextStyle( color: NetDeskColors.textSecondary, height: 1.4, ), labelLarge: const TextStyle( fontWeight: FontWeight.w600, letterSpacing: 0.3, ), ), appBarTheme: const AppBarTheme( backgroundColor: NetDeskColors.surfaceAlt, foregroundColor: NetDeskColors.textPrimary, elevation: 0, centerTitle: false, titleTextStyle: TextStyle( color: NetDeskColors.textPrimary, fontSize: 16, fontWeight: FontWeight.w600, letterSpacing: 0.2, ), systemOverlayStyle: SystemUiOverlayStyle.light, ), cardTheme: CardThemeData( color: NetDeskColors.surface, elevation: 0, margin: EdgeInsets.zero, shape: RoundedRectangleBorder( side: const BorderSide(color: NetDeskColors.border), borderRadius: BorderRadius.circular(NetDeskRadius.xl), ), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: NetDeskColors.surfaceAlt, hintStyle: const TextStyle(color: NetDeskColors.textMuted), labelStyle: const TextStyle(color: NetDeskColors.textSecondary), contentPadding: const EdgeInsets.symmetric( horizontal: NetDeskSpacing.md, vertical: 18, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(NetDeskRadius.md), borderSide: const BorderSide(color: NetDeskColors.border), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(NetDeskRadius.md), borderSide: const BorderSide(color: NetDeskColors.accent, width: 1.6), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(NetDeskRadius.md), borderSide: const BorderSide(color: NetDeskColors.danger), ), ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( backgroundColor: NetDeskColors.accent, foregroundColor: const Color(0xFF04210F), disabledBackgroundColor: NetDeskColors.border, disabledForegroundColor: NetDeskColors.textMuted, minimumSize: const Size.fromHeight(54), textStyle: const TextStyle( fontSize: 15, fontWeight: FontWeight.w700, letterSpacing: 0.3, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(NetDeskRadius.md), ), ), ), iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( foregroundColor: NetDeskColors.textSecondary, hoverColor: NetDeskColors.surface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(NetDeskRadius.sm), ), ), ), tooltipTheme: const TooltipThemeData( decoration: BoxDecoration( color: Color(0xFF1B2430), borderRadius: BorderRadius.all(Radius.circular(NetDeskRadius.sm)), ), textStyle: TextStyle(color: NetDeskColors.textPrimary, fontSize: 12), ), dividerTheme: const DividerThemeData( color: NetDeskColors.border, thickness: 1, space: 1, ), ); } }