feat: Introduce core IPTV features, authentication screen, web player, and application theming.

This commit is contained in:
Michael committed 2025-12-06 18:19:21 +01:00
1 parent c90ea530ea
commit e699d3ec31
8 files changed
+931 -1379

No files matched your search

+69 -95
View File
@@ -1,125 +1,99 @@
import 'package:flutter/material.dart';
/// XtremFlow Premium Color Palette
/// XtremFlow Cinematic Minimalist Palette
///
/// Modern theme with cyan/teal gradients - supports light and dark modes
/// A deep, dark, and neutral palette designed for content-first experiences.
/// Focuses on #0A0A0A backgrounds and subtle surfaces.
class AppColors {
AppColors._();
// ============ PRIMARY GRADIENT ============
/// Cyan primary - main accent color
static const Color primary = Color(0xFF00BCD4);
// ============ BACKGROUNDS ============
/// Pitch black for OLED/Main backgrounds
static const Color background = Color(0xFF0A0A0A);
/// Teal secondary - gradient end
static const Color secondary = Color(0xFF00ACC1);
/// Dark grey for cards/sheets
static const Color surface = Color(0xFF141414);
/// Primary gradient for buttons and highlights
/// Slightly lighter for hover states or active items
static const Color surfaceLight = Color(0xFF1F1F1F);
/// For inputs or secondary surfaces
static const Color surfaceVariant = Color(0xFF2A2A2A);
// ============ ACCENTS (MINIMALIST) ============
/// Primary Brand Color (Electric Blue/Violet for modern feel)
/// Replacing the old Gradient Cyan with a solid, punchy color.
static const Color primary = Color(0xFF3F51B5); // Indigo
/// Secondary accent
static const Color accent = Color(0xFF7986CB);
/// Primary Gradient (Subtle, for buttons only)
static const LinearGradient primaryGradient = LinearGradient(
colors: [primary, secondary],
colors: [primary, accent],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
// ============ DARK MODE SURFACE COLORS ============
/// Deep dark background
static const Color backgroundDark = Color(0xFF0A0E1A);
// ============ TEXT ============
/// Pure white for high contrast headers
static const Color textPrimary = Color(0xFFFFFFFF);
/// Card/elevated surface (dark)
static const Color surfaceDark = Color(0xFF121829);
/// Light grey for body text
static const Color textSecondary = Color(0xFFB3B3B3);
/// Lighter surface variant (dark)
static const Color surfaceVariantDark = Color(0xFF1E2638);
/// Darker grey for hints/disabled
static const Color textTertiary = Color(0xFF808080);
/// Border/divider color (dark)
static const Color borderDark = Color(0xFF2A3441);
// ============ FUNCTIONAL COLORS ============
static const Color success = Color(0xFF4CAF50);
static const Color warning = Color(0xFFFFC107);
static const Color error = Color(0xFFCF6679);
static const Color info = Color(0xFF2196F3);
static const Color live = Color(0xFFFF0000); // Standard Red for LIVE
// ============ LIGHT MODE SURFACE COLORS ============
/// Light background
static const Color backgroundLight = Color(0xFFF5F7FA);
/// Card/elevated surface (light)
static const Color surfaceLight = Color(0xFFFFFFFF);
/// Lighter surface variant (light)
static const Color surfaceVariantLight = Color(0xFFF0F2F5);
/// Border/divider color (light)
static const Color borderLight = Color(0xFFE2E8F0);
// ============ DARK MODE TEXT COLORS ============
static const Color textPrimaryDark = Color(0xFFF5F5F5);
static const Color textSecondaryDark = Color(0xFF94A3B8);
static const Color textDisabledDark = Color(0xFF64748B);
// ============ LIGHT MODE TEXT COLORS ============
static const Color textPrimaryLight = Color(0xFF1A1A2E);
static const Color textSecondaryLight = Color(0xFF64748B);
static const Color textDisabledLight = Color(0xFF94A3B8);
// ============ LEGACY ALIASES (for backwards compatibility) ============
static const Color background = backgroundDark;
static const Color surface = surfaceDark;
static const Color surfaceVariant = surfaceVariantDark;
static const Color border = borderDark;
static const Color textPrimary = textPrimaryDark;
static const Color textSecondary = textSecondaryDark;
static const Color textDisabled = textDisabledDark;
static const Color overlay = Color(0xCC0A0E14);
// ============ ACCENT COLORS ============
/// Live indicator red
static const Color live = Color(0xFFFF6B6B);
/// Success green
static const Color success = Color(0xFF4ADE80);
/// Warning amber
static const Color warning = Color(0xFFFBBF24);
/// Error red
static const Color error = Color(0xFFEF4444);
/// Info blue
static const Color info = Color(0xFF3B82F6);
// ============ CATEGORY COLORS ============
static const List<Color> categoryColors = [
Color(0xFF6366F1), // Indigo
Color(0xFFEC4899), // Pink
Color(0xFF8B5CF6), // Purple
Color(0xFF14B8A6), // Teal
Color(0xFFF59E0B), // Amber
Color(0xFF10B981), // Emerald
];
// ============ BORDERS ============
static const Color border = Color(0xFF333333);
// ============ GLASSMORPHISM ============
static const Color glassBackground = Color(0x1AFFFFFF);
static const Color glassBorder = Color(0x33FFFFFF);
static const Color glassBackgroundLight = Color(0x40FFFFFF);
static const Color glassBorderLight = Color(0x20000000);
static final Color glassBackground = const Color(0xFF1E1E1E).withOpacity(0.7);
static final Color glassBorder = const Color(0xFFFFFFFF).withOpacity(0.1);
// ============ DARK THEME COLOR SCHEME ============
// ============ CATEGORY COLORS (MUTED) ============
static const List<Color> categoryColors = [
Color(0xFF5C6BC0), // Indigo
Color(0xFFAB47BC), // Purple
Color(0xFFEF5350), // Red
Color(0xFF26A69A), // Teal
Color(0xFFFFA726), // Orange
Color(0xFF78909C), // Blue Grey
];
// ============ THEME SCHEMES ============
static ColorScheme get darkColorScheme => const ColorScheme.dark(
primary: primary,
secondary: secondary,
surface: surfaceDark,
secondary: accent,
surface: surface,
background: background,
error: error,
onPrimary: Color(0xFF000000),
onSecondary: Color(0xFF000000),
onSurface: textPrimaryDark,
onError: Color(0xFFFFFFFF),
onPrimary: Colors.white,
onSecondary: Colors.white,
onSurface: textPrimary,
onError: Colors.white,
brightness: Brightness.dark,
);
// ============ LIGHT THEME COLOR SCHEME ============
// Minimalist Light Scheme (if ever toggled)
static ColorScheme get lightColorScheme => const ColorScheme.light(
primary: primary,
secondary: secondary,
surface: surfaceLight,
secondary: accent,
surface: Color(0xFFF5F5F5),
background: Colors.white,
error: error,
onPrimary: Color(0xFFFFFFFF),
onSecondary: Color(0xFFFFFFFF),
onSurface: textPrimaryLight,
onError: Color(0xFFFFFFFF),
onPrimary: Colors.white,
onSecondary: Colors.black,
onSurface: Color(0xFF121212),
onError: Colors.white,
brightness: Brightness.light,
);
}
+95 -525
View File
@@ -2,38 +2,28 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'app_colors.dart';
/// XtremFlow Modern Theme
/// XtremFlow Cinematic Minimalist Theme
///
/// Complete theme with typography, spacing, and component theming
/// Refined, content-first theme. Less noise, more focus.
class AppTheme {
AppTheme._();
// ============ SPACING SCALE ============
// ============ SPACING ============
static const double spacing4 = 4.0;
static const double spacing8 = 8.0;
static const double spacing12 = 12.0;
static const double spacing16 = 16.0;
static const double spacing24 = 24.0;
static const double spacing32 = 32.0;
static const double spacing48 = 48.0;
// ============ BORDER RADIUS ============
static const double radiusSm = 8.0;
static const double radiusMd = 12.0;
static const double radiusLg = 16.0;
static const double radiusXl = 24.0;
// ============ RADIUS (Tighter for professional look) ============
static const double radiusSm = 6.0;
static const double radiusMd = 8.0;
static const double radiusLg = 12.0;
static const double radiusXl = 16.0;
static const double radiusFull = 999.0;
// ============ ANIMATION DURATIONS ============
static const Duration durationFast = Duration(milliseconds: 150);
static const Duration durationNormal = Duration(milliseconds: 250);
static const Duration durationSlow = Duration(milliseconds: 400);
// ============ ANIMATION CURVES ============
static const Curve curveDefault = Curves.easeOutCubic;
static const Curve curveEmphasized = Curves.easeInOutCubic;
// ============ DARK THEME ============
// ============ DARK THEME (Main) ============
static ThemeData get darkTheme {
final baseTheme = ThemeData.dark(useMaterial3: true);
@@ -41,66 +31,60 @@ class AppTheme {
colorScheme: AppColors.darkColorScheme,
scaffoldBackgroundColor: AppColors.background,
// AppBar
// AppBar: Minimalist, blends with background
appBarTheme: AppBarTheme(
backgroundColor: AppColors.surface,
backgroundColor: AppColors.background, // Seamless
surfaceTintColor: Colors.transparent,
elevation: 0,
centerTitle: false,
iconTheme: const IconThemeData(color: AppColors.textPrimary),
titleTextStyle: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
iconTheme: const IconThemeData(color: AppColors.textPrimary),
),
// Navigation Bar (bottom)
// Navigation: Simple, functional
navigationBarTheme: NavigationBarThemeData(
backgroundColor: AppColors.surface,
backgroundColor: AppColors.background,
surfaceTintColor: Colors.transparent,
indicatorColor: AppColors.primary.withOpacity(0.2),
indicatorColor: AppColors.primary.withOpacity(0.15),
labelTextStyle: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.primary,
);
}
final isSelected = states.contains(WidgetState.selected);
return GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColors.textSecondary,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
color: isSelected ? AppColors.textPrimary : AppColors.textSecondary,
);
}),
iconTheme: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return const IconThemeData(color: AppColors.primary);
}
return const IconThemeData(color: AppColors.textSecondary);
final isSelected = states.contains(WidgetState.selected);
return IconThemeData(
color: isSelected ? AppColors.textPrimary : AppColors.textSecondary,
);
}),
),
// Navigation Rail (desktop sidebar)
// NavigationRail (Desktop)
navigationRailTheme: NavigationRailThemeData(
backgroundColor: AppColors.surface,
indicatorColor: AppColors.primary.withOpacity(0.2),
selectedIconTheme: const IconThemeData(color: AppColors.primary),
backgroundColor: AppColors.background,
indicatorColor: AppColors.primary.withOpacity(0.15),
selectedIconTheme: const IconThemeData(color: AppColors.textPrimary),
unselectedIconTheme: const IconThemeData(color: AppColors.textSecondary),
selectedLabelTextStyle: GoogleFonts.inter(
fontSize: 12,
color: AppColors.textPrimary,
fontWeight: FontWeight.w600,
color: AppColors.primary,
fontSize: 12,
),
unselectedLabelTextStyle: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColors.textSecondary,
fontWeight: FontWeight.w500,
fontSize: 12,
),
),
// Cards
// Cards: Flat, subtle border
cardTheme: CardThemeData(
color: AppColors.surface,
surfaceTintColor: Colors.transparent,
@@ -112,10 +96,11 @@ class AppTheme {
margin: EdgeInsets.zero,
),
// Inputs
// Inputs: Clean, filled
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColors.surfaceVariant,
contentPadding: const EdgeInsets.all(spacing16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.border),
@@ -126,498 +111,83 @@ class AppTheme {
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.primary, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.error),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: spacing16,
vertical: spacing12,
),
hintStyle: GoogleFonts.inter(
color: AppColors.textDisabled,
fontSize: 14,
),
labelStyle: GoogleFonts.inter(
color: AppColors.textSecondary,
fontSize: 14,
borderSide: const BorderSide(color: AppColors.primary),
),
hintStyle: GoogleFonts.inter(color: AppColors.textTertiary),
labelStyle: GoogleFonts.inter(color: AppColors.textSecondary),
),
// Buttons
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.black,
padding: const EdgeInsets.symmetric(
horizontal: spacing24,
vertical: spacing12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusSm),
),
textStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.primary,
side: const BorderSide(color: AppColors.primary),
padding: const EdgeInsets.symmetric(
horizontal: spacing24,
vertical: spacing12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusSm),
),
textStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColors.primary,
textStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
// Chips
chipTheme: ChipThemeData(
backgroundColor: AppColors.surfaceVariant,
selectedColor: AppColors.primary.withOpacity(0.2),
labelStyle: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
side: const BorderSide(color: AppColors.border),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusFull),
),
padding: const EdgeInsets.symmetric(horizontal: spacing8),
),
// Dialogs
dialogTheme: DialogThemeData(
backgroundColor: AppColors.surface,
surfaceTintColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusLg),
),
titleTextStyle: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
contentTextStyle: GoogleFonts.inter(
fontSize: 14,
color: AppColors.textSecondary,
),
),
// Snackbars
snackBarTheme: SnackBarThemeData(
backgroundColor: AppColors.surfaceVariant,
contentTextStyle: GoogleFonts.inter(
fontSize: 14,
color: AppColors.textPrimary,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusSm),
),
behavior: SnackBarBehavior.floating,
),
// Tabs
tabBarTheme: TabBarThemeData(
labelColor: AppColors.primary,
unselectedLabelColor: AppColors.textSecondary,
labelStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
),
unselectedLabelStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w500,
),
indicatorColor: AppColors.primary,
indicatorSize: TabBarIndicatorSize.tab,
dividerColor: AppColors.border,
),
// Dividers
dividerTheme: const DividerThemeData(
color: AppColors.border,
thickness: 1,
space: 1,
),
// List tiles
listTileTheme: ListTileThemeData(
tileColor: Colors.transparent,
contentPadding: const EdgeInsets.symmetric(
horizontal: spacing16,
vertical: spacing8,
),
titleTextStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
subtitleTextStyle: GoogleFonts.inter(
fontSize: 12,
color: AppColors.textSecondary,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusSm),
),
),
// Progress indicators
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: AppColors.primary,
linearTrackColor: AppColors.surfaceVariant,
circularTrackColor: AppColors.surfaceVariant,
),
// Switch
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColors.primary;
}
return AppColors.textSecondary;
}),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColors.primary.withOpacity(0.3);
}
return AppColors.surfaceVariant;
}),
),
// Text theme
textTheme: TextTheme(
displayLarge: GoogleFonts.inter(
fontSize: 57,
fontWeight: FontWeight.w400,
color: AppColors.textPrimary,
),
displayMedium: GoogleFonts.inter(
fontSize: 45,
fontWeight: FontWeight.w400,
color: AppColors.textPrimary,
),
displaySmall: GoogleFonts.inter(
fontSize: 36,
fontWeight: FontWeight.w400,
color: AppColors.textPrimary,
),
headlineLarge: GoogleFonts.inter(
fontSize: 32,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
headlineMedium: GoogleFonts.inter(
fontSize: 28,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
headlineSmall: GoogleFonts.inter(
fontSize: 24,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
titleLarge: GoogleFonts.inter(
fontSize: 22,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
titleMedium: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
titleSmall: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
bodyLarge: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.w400,
color: AppColors.textPrimary,
),
bodyMedium: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w400,
color: AppColors.textPrimary,
),
bodySmall: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w400,
color: AppColors.textSecondary,
),
labelLarge: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
labelMedium: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
labelSmall: GoogleFonts.inter(
fontSize: 11,
fontWeight: FontWeight.w500,
color: AppColors.textSecondary,
),
),
);
}
// ============ LIGHT THEME ============
static ThemeData get lightTheme {
final baseTheme = ThemeData.light(useMaterial3: true);
return baseTheme.copyWith(
colorScheme: AppColors.lightColorScheme,
scaffoldBackgroundColor: AppColors.backgroundLight,
// AppBar
appBarTheme: AppBarTheme(
backgroundColor: AppColors.surfaceLight,
surfaceTintColor: Colors.transparent,
elevation: 0,
centerTitle: false,
titleTextStyle: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.w600,
color: AppColors.textPrimaryLight,
),
iconTheme: const IconThemeData(color: AppColors.textPrimaryLight),
),
// Navigation Bar (bottom)
navigationBarTheme: NavigationBarThemeData(
backgroundColor: AppColors.surfaceLight,
surfaceTintColor: Colors.transparent,
indicatorColor: AppColors.primary.withOpacity(0.15),
labelTextStyle: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.primary,
);
}
return GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColors.textSecondaryLight,
);
}),
iconTheme: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return const IconThemeData(color: AppColors.primary);
}
return const IconThemeData(color: AppColors.textSecondaryLight);
}),
),
// Navigation Rail (desktop sidebar)
navigationRailTheme: NavigationRailThemeData(
backgroundColor: AppColors.surfaceLight,
indicatorColor: AppColors.primary.withOpacity(0.15),
selectedIconTheme: const IconThemeData(color: AppColors.primary),
unselectedIconTheme: const IconThemeData(color: AppColors.textSecondaryLight),
selectedLabelTextStyle: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.primary,
),
unselectedLabelTextStyle: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColors.textSecondaryLight,
),
),
// Cards
cardTheme: CardThemeData(
color: AppColors.surfaceLight,
surfaceTintColor: Colors.transparent,
elevation: 2,
shadowColor: Colors.black.withOpacity(0.08),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusMd),
),
margin: EdgeInsets.zero,
),
// Inputs
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColors.surfaceVariantLight,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.borderLight),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.borderLight),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.primary, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.error),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: spacing16,
vertical: spacing12,
),
hintStyle: GoogleFonts.inter(
color: AppColors.textDisabledLight,
fontSize: 14,
),
labelStyle: GoogleFonts.inter(
color: AppColors.textSecondaryLight,
fontSize: 14,
),
),
// Buttons
// Buttons: Sharp, reliable
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: spacing24,
vertical: spacing12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusSm),
),
textStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
textStyle: GoogleFonts.inter(fontWeight: FontWeight.w600),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.textPrimary,
side: const BorderSide(color: AppColors.border),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusSm),
),
textStyle: GoogleFonts.inter(fontWeight: FontWeight.w600),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
),
),
// Dialogs
dialogTheme: DialogThemeData(
backgroundColor: AppColors.surfaceLight,
surfaceTintColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusLg),
),
titleTextStyle: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.w600,
color: AppColors.textPrimaryLight,
),
contentTextStyle: GoogleFonts.inter(
fontSize: 14,
color: AppColors.textSecondaryLight,
),
),
// Dividers
dividerTheme: const DividerThemeData(
color: AppColors.borderLight,
thickness: 1,
space: 1,
),
// List tiles
listTileTheme: ListTileThemeData(
tileColor: Colors.transparent,
contentPadding: const EdgeInsets.symmetric(
horizontal: spacing16,
vertical: spacing8,
),
titleTextStyle: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.textPrimaryLight,
),
subtitleTextStyle: GoogleFonts.inter(
fontSize: 12,
color: AppColors.textSecondaryLight,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusSm),
),
),
// Progress indicators
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: AppColors.primary,
linearTrackColor: AppColors.surfaceVariantLight,
circularTrackColor: AppColors.surfaceVariantLight,
),
// Text theme
// Text
textTheme: TextTheme(
displayLarge: GoogleFonts.inter(
fontSize: 57,
fontWeight: FontWeight.w400,
color: AppColors.textPrimaryLight,
),
headlineLarge: GoogleFonts.inter(
fontSize: 32,
fontWeight: FontWeight.w600,
color: AppColors.textPrimaryLight,
),
titleLarge: GoogleFonts.inter(
fontSize: 22,
fontWeight: FontWeight.w600,
color: AppColors.textPrimaryLight,
),
titleMedium: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.textPrimaryLight,
),
bodyLarge: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.w400,
color: AppColors.textPrimaryLight,
),
bodyMedium: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w400,
color: AppColors.textPrimaryLight,
),
bodySmall: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w400,
color: AppColors.textSecondaryLight,
),
labelLarge: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.textPrimaryLight,
),
displayLarge: GoogleFonts.inter(color: AppColors.textPrimary, fontWeight: FontWeight.bold),
displayMedium: GoogleFonts.inter(color: AppColors.textPrimary, fontWeight: FontWeight.bold),
headlineMedium: GoogleFonts.inter(color: AppColors.textPrimary, fontWeight: FontWeight.w600),
titleLarge: GoogleFonts.inter(color: AppColors.textPrimary, fontWeight: FontWeight.w600),
titleMedium: GoogleFonts.inter(color: AppColors.textPrimary, fontWeight: FontWeight.w500),
bodyLarge: GoogleFonts.inter(color: AppColors.textSecondary, fontSize: 16),
bodyMedium: GoogleFonts.inter(color: AppColors.textSecondary, fontSize: 14),
),
);
}
}
// ============ LIGHT THEME (Minimalist) ============
static ThemeData get lightTheme {
final baseTheme = ThemeData.light(useMaterial3: true);
final colors = AppColors.lightColorScheme;
return baseTheme.copyWith(
colorScheme: colors,
scaffoldBackgroundColor: colors.background,
appBarTheme: AppBarTheme(
backgroundColor: colors.background,
foregroundColor: colors.onSurface,
elevation: 0,
centerTitle: false,
iconTheme: IconThemeData(color: colors.onSurface),
titleTextStyle: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.w600,
color: colors.onSurface,
),
),
cardTheme: CardThemeData(
color: colors.surface,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusMd),
side: BorderSide(color: Colors.grey.shade300),
),
),
textTheme: TextTheme(
bodyLarge: GoogleFonts.inter(color: colors.onSurface),
bodyMedium: GoogleFonts.inter(color: colors.onSurfaceVariant),
),
// Can expand light theme details later if needed
);
}
}