Files
kooltab/lib/theme.dart
T
2026-07-29 01:42:34 +02:00

704 lines
20 KiB
Dart

import 'package:flutter/material.dart';
// ---------------------------------------------------------------------------
// Shared design tokens
// ---------------------------------------------------------------------------
class AppRadii {
static const double sm = 10;
static const double md = 14;
static const double lg = 20;
static const double xl = 28;
}
class AppSpacing {
static const double xs = 4;
static const double sm = 8;
static const double md = 12;
static const double lg = 16;
static const double xl = 24;
}
// ---------------------------------------------------------------------------
// Dark theme — refined violet palette
// ---------------------------------------------------------------------------
const _violet = Color(0xFF8B5CF6);
const _violetSoft = Color(0xFFB39DFF);
const _bg = Color(0xFF111014);
const _surface = Color(0xFF1A1920);
const _surfaceRaised = Color(0xFF221F29);
const _outline = Color(0x1FFFFFFF); // ~12% white
final ThemeData darkTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
splashFactory: InkRipple.splashFactory,
colorScheme: ColorScheme.fromSeed(
seedColor: _violet,
brightness: Brightness.dark,
surface: _surface,
error: const Color(0xFFFF6B6B),
),
scaffoldBackgroundColor: _bg,
canvasColor: _bg,
appBarTheme: AppBarTheme(
elevation: 0,
centerTitle: false,
backgroundColor: _bg,
foregroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
titleTextStyle: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.w800,
letterSpacing: -0.3,
color: Colors.white,
),
iconTheme: const IconThemeData(color: Colors.white70, size: 22),
actionsIconTheme: const IconThemeData(color: Colors.white70, size: 22),
),
iconButtonTheme: IconButtonThemeData(
style: IconButton.styleFrom(
backgroundColor: Colors.white.withValues(alpha: 0.05),
foregroundColor: Colors.white70,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
padding: const EdgeInsets.all(10),
),
),
cardTheme: CardThemeData(
color: _surface,
elevation: 0,
margin: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.lg),
side: const BorderSide(color: _outline, width: 1),
),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
elevation: 0,
backgroundColor: _violet,
foregroundColor: Colors.white,
disabledBackgroundColor: Colors.white.withValues(alpha: 0.06),
disabledForegroundColor: Colors.white24,
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.xl,
vertical: AppSpacing.lg,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
letterSpacing: 0.1,
),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
backgroundColor: _violet,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.xl,
vertical: AppSpacing.lg,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
textStyle: const TextStyle(fontSize: 15, fontWeight: FontWeight.w700),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: Colors.white,
side: const BorderSide(color: _outline, width: 1.4),
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.xl,
vertical: AppSpacing.lg,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.white70,
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.md,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
),
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: _surfaceRaised,
hintStyle: const TextStyle(color: Colors.white38),
contentPadding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.lg,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
borderSide: const BorderSide(color: _outline),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
borderSide: const BorderSide(color: _violet, width: 2),
),
),
dialogTheme: DialogThemeData(
backgroundColor: _surfaceRaised,
surfaceTintColor: Colors.transparent,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.lg),
),
titleTextStyle: const TextStyle(
color: Colors.white,
fontSize: 19,
fontWeight: FontWeight.w800,
),
contentTextStyle: const TextStyle(color: Colors.white70, height: 1.4),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: _violet,
foregroundColor: Colors.white,
elevation: 2,
),
navigationBarTheme: NavigationBarThemeData(
backgroundColor: _surface,
indicatorColor: _violet.withValues(alpha: 0.25),
labelTextStyle: const WidgetStatePropertyAll(
TextStyle(fontWeight: FontWeight.w600),
),
),
listTileTheme: ListTileThemeData(
tileColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
iconColor: _violetSoft,
textColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.xs,
),
),
snackBarTheme: SnackBarThemeData(
backgroundColor: _surfaceRaised,
behavior: SnackBarBehavior.floating,
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
side: const BorderSide(color: _outline),
),
contentTextStyle: const TextStyle(color: Colors.white),
),
dividerTheme: const DividerThemeData(color: _outline, thickness: 1, space: 1),
chipTheme: ChipThemeData(
backgroundColor: _surfaceRaised,
labelStyle: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 12,
),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.sm),
side: const BorderSide(color: _outline),
),
),
textTheme: const TextTheme(
displayLarge: TextStyle(color: Colors.white, fontWeight: FontWeight.w800),
headlineMedium: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w800,
letterSpacing: -0.3,
),
titleLarge: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w800,
letterSpacing: -0.2,
),
titleMedium: TextStyle(color: Colors.white, fontWeight: FontWeight.w700),
bodyLarge: TextStyle(color: Colors.white70, fontSize: 16, height: 1.5),
bodyMedium: TextStyle(color: Colors.white60, height: 1.4),
bodySmall: TextStyle(color: Colors.white38, height: 1.3),
labelLarge: TextStyle(color: Colors.white, fontWeight: FontWeight.w700),
),
);
// ---------------------------------------------------------------------------
// Neo-brutalist dark theme — punchy, high-contrast alternative
// ---------------------------------------------------------------------------
const _nbBg = Color(0xFF0C0C0E);
const _nbSurface = Color(0xFF1C1C20);
const _nbYellow = Color(0xFFFFD60A);
const _nbCyan = Color(0xFF00E5FF);
const _nbPink = Color(0xFFFF3D81);
final ThemeData neoBrutalDarkTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorScheme: const ColorScheme.dark(
primary: _nbYellow,
secondary: _nbCyan,
surface: _nbSurface,
error: _nbPink,
),
scaffoldBackgroundColor: _nbBg,
canvasColor: _nbBg,
textTheme: const TextTheme(
displayLarge: TextStyle(
fontSize: 48,
fontWeight: FontWeight.w900,
color: Colors.white,
letterSpacing: -1.5,
),
headlineMedium: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w900,
color: Colors.white,
letterSpacing: -0.5,
),
titleLarge: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w900,
color: Colors.white,
),
titleMedium: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w800,
color: Colors.white,
),
bodyLarge: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
bodyMedium: TextStyle(fontSize: 14, color: Colors.white70),
bodySmall: TextStyle(
fontSize: 12,
color: Colors.white54,
fontWeight: FontWeight.w600,
),
),
appBarTheme: const AppBarTheme(
backgroundColor: _nbBg,
foregroundColor: Colors.white,
elevation: 0,
centerTitle: false,
titleTextStyle: TextStyle(
fontSize: 26,
fontWeight: FontWeight.w900,
color: Colors.white,
),
),
cardTheme: CardThemeData(
color: _nbSurface,
elevation: 0,
margin: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.white, width: 3),
),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: _nbYellow,
foregroundColor: Colors.black,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.black, width: 3),
),
textStyle: const TextStyle(fontWeight: FontWeight.w900, fontSize: 16),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: _nbYellow,
foregroundColor: Colors.black,
elevation: 0,
shadowColor: Colors.transparent,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.black, width: 3),
),
textStyle: const TextStyle(fontWeight: FontWeight.w900, fontSize: 16),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: Colors.white,
side: const BorderSide(color: Colors.white, width: 3),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 18),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
textStyle: const TextStyle(fontWeight: FontWeight.w800),
),
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: _nbSurface,
hintStyle: const TextStyle(
color: Colors.white38,
fontWeight: FontWeight.w600,
),
contentPadding: const EdgeInsets.all(18),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white, width: 3),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.white, width: 3),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: _nbYellow, width: 4),
),
),
dialogTheme: DialogThemeData(
backgroundColor: _nbSurface,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.white, width: 3),
),
titleTextStyle: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w900,
),
contentTextStyle: const TextStyle(
color: Colors.white70,
fontWeight: FontWeight.w600,
),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: _nbPink,
foregroundColor: Colors.white,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
side: BorderSide(color: Colors.white, width: 3),
),
),
snackBarTheme: SnackBarThemeData(
backgroundColor: _nbSurface,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.white, width: 3),
),
behavior: SnackBarBehavior.floating,
contentTextStyle: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
dividerTheme: const DividerThemeData(color: Colors.white, thickness: 3),
listTileTheme: ListTileThemeData(
tileColor: _nbSurface,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.white, width: 3),
),
textColor: Colors.white,
iconColor: _nbYellow,
),
);
const _violetL = Color(0xFF7C3AED);
const _violetSoftL = Color(0xFF6D28D9);
const _bgL = Color(0xFFFAFAFC);
const _surfaceL = Color(0xFFFFFFFF);
const _surfaceRaisedL = Color(0xFFF3F1F8);
const _outlineL = Color(0x14000000); // ~8% black
final ThemeData lightTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.light,
splashFactory: InkRipple.splashFactory,
colorScheme: ColorScheme.fromSeed(
seedColor: _violetL,
brightness: Brightness.light,
surface: _surfaceL,
error: const Color(0xFFE5484D),
),
scaffoldBackgroundColor: _bgL,
canvasColor: _bgL,
appBarTheme: AppBarTheme(
elevation: 0,
centerTitle: false,
backgroundColor: _bgL,
foregroundColor: Colors.black87,
surfaceTintColor: Colors.transparent,
titleTextStyle: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.w800,
letterSpacing: -0.3,
color: Colors.black87,
),
iconTheme: const IconThemeData(color: Colors.black54, size: 22),
actionsIconTheme: const IconThemeData(color: Colors.black54, size: 22),
),
iconButtonTheme: IconButtonThemeData(
style: IconButton.styleFrom(
backgroundColor: Colors.black.withValues(alpha: 0.04),
foregroundColor: Colors.black54,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
padding: const EdgeInsets.all(10),
),
),
cardTheme: CardThemeData(
color: _surfaceL,
elevation: 0,
margin: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.lg),
side: const BorderSide(color: _outlineL, width: 1),
),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
elevation: 0,
backgroundColor: _violetL,
foregroundColor: Colors.white,
disabledBackgroundColor: Colors.black.withValues(alpha: 0.06),
disabledForegroundColor: Colors.black26,
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.xl,
vertical: AppSpacing.lg,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
letterSpacing: 0.1,
),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
backgroundColor: _violetL,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.xl,
vertical: AppSpacing.lg,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
textStyle: const TextStyle(fontSize: 15, fontWeight: FontWeight.w700),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: Colors.black87,
side: const BorderSide(color: _outlineL, width: 1.4),
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.xl,
vertical: AppSpacing.lg,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.black54,
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.md,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
),
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: _surfaceRaisedL,
hintStyle: const TextStyle(color: Colors.black38),
contentPadding: const EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.lg,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
borderSide: const BorderSide(color: _outlineL),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
borderSide: const BorderSide(color: _violetL, width: 2),
),
),
dialogTheme: DialogThemeData(
backgroundColor: _surfaceL,
surfaceTintColor: Colors.transparent,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.lg),
),
titleTextStyle: const TextStyle(
color: Colors.black87,
fontSize: 19,
fontWeight: FontWeight.w800,
),
contentTextStyle: const TextStyle(color: Colors.black54, height: 1.4),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: _violetL,
foregroundColor: Colors.white,
elevation: 2,
),
navigationBarTheme: NavigationBarThemeData(
backgroundColor: _surfaceL,
indicatorColor: _violetL.withValues(alpha: 0.15),
labelTextStyle: const WidgetStatePropertyAll(
TextStyle(fontWeight: FontWeight.w600),
),
),
listTileTheme: ListTileThemeData(
tileColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
iconColor: _violetSoftL,
textColor: Colors.black87,
contentPadding: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.xs,
),
),
snackBarTheme: SnackBarThemeData(
backgroundColor: Colors.black87,
behavior: SnackBarBehavior.floating,
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.md),
),
contentTextStyle: const TextStyle(color: Colors.white),
),
dividerTheme: const DividerThemeData(
color: _outlineL,
thickness: 1,
space: 1,
),
chipTheme: ChipThemeData(
backgroundColor: _surfaceRaisedL,
labelStyle: const TextStyle(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 12,
),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadii.sm),
side: const BorderSide(color: _outlineL),
),
),
textTheme: const TextTheme(
displayLarge: TextStyle(color: Colors.black87, fontWeight: FontWeight.w800),
headlineMedium: TextStyle(
color: Colors.black87,
fontWeight: FontWeight.w800,
letterSpacing: -0.3,
),
titleLarge: TextStyle(
color: Colors.black87,
fontWeight: FontWeight.w800,
letterSpacing: -0.2,
),
titleMedium: TextStyle(color: Colors.black87, fontWeight: FontWeight.w700),
bodyLarge: TextStyle(color: Colors.black54, fontSize: 16, height: 1.5),
bodyMedium: TextStyle(color: Colors.black45, height: 1.4),
bodySmall: TextStyle(color: Colors.black38, height: 1.3),
labelLarge: TextStyle(color: Colors.black87, fontWeight: FontWeight.w700),
),
);