197 lines
6.4 KiB
Dart
197 lines
6.4 KiB
Dart
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,
|
|
),
|
|
);
|
|
}
|
|
}
|