feat: Establish initial application structure, theming, responsive utilities, and core feature screens.

This commit is contained in:
Michael committed 2025-12-06 16:38:15 +01:00
1 parent 33239ca11e
commit d2c92215e9
10 files changed
+1754 -332

No files matched your search

+94
View File
@@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
/// XtremFlow Premium Color Palette
///
/// Modern dark theme with cyan/teal gradients
class AppColors {
AppColors._();
// ============ PRIMARY GRADIENT ============
/// Cyan primary - main accent color
static const Color primary = Color(0xFF00D9FF);
/// Teal secondary - gradient end
static const Color secondary = Color(0xFF00BFA5);
/// Primary gradient for buttons and highlights
static const LinearGradient primaryGradient = LinearGradient(
colors: [primary, secondary],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
// ============ SURFACE COLORS ============
/// Deep dark background
static const Color background = Color(0xFF0A0E14);
/// Card/elevated surface
static const Color surface = Color(0xFF141A22);
/// Lighter surface variant (hover states, inputs)
static const Color surfaceVariant = Color(0xFF1E2630);
/// Border/divider color
static const Color border = Color(0xFF2A3441);
/// Overlay color (modals, dialogs)
static const Color overlay = Color(0xCC0A0E14);
// ============ TEXT COLORS ============
/// Primary text - white with high opacity
static const Color textPrimary = Color(0xFFF5F5F5);
/// Secondary text - muted
static const Color textSecondary = Color(0xFFB0BEC5);
/// Disabled/hint text
static const Color textDisabled = Color(0xFF607D8B);
// ============ 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 ============
/// Colors for category chips/tags
static const List<Color> categoryColors = [
Color(0xFF6366F1), // Indigo
Color(0xFFEC4899), // Pink
Color(0xFF8B5CF6), // Purple
Color(0xFF14B8A6), // Teal
Color(0xFFF59E0B), // Amber
Color(0xFF10B981), // Emerald
];
// ============ GLASSMORPHISM ============
/// Glass effect background color
static const Color glassBackground = Color(0x1AFFFFFF);
/// Glass border color
static const Color glassBorder = Color(0x33FFFFFF);
// ============ DARK THEME COLOR SCHEME ============
static ColorScheme get darkColorScheme => const ColorScheme.dark(
primary: primary,
secondary: secondary,
surface: surface,
error: error,
onPrimary: Color(0xFF000000),
onSecondary: Color(0xFF000000),
onSurface: textPrimary,
onError: Color(0xFFFFFFFF),
);
}
+391
View File
@@ -0,0 +1,391 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'app_colors.dart';
/// XtremFlow Modern Theme
///
/// Complete theme with typography, spacing, and component theming
class AppTheme {
AppTheme._();
// ============ SPACING SCALE ============
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;
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 ============
static ThemeData get darkTheme {
final baseTheme = ThemeData.dark(useMaterial3: true);
return baseTheme.copyWith(
colorScheme: AppColors.darkColorScheme,
scaffoldBackgroundColor: AppColors.background,
// AppBar
appBarTheme: AppBarTheme(
backgroundColor: AppColors.surface,
surfaceTintColor: Colors.transparent,
elevation: 0,
centerTitle: false,
titleTextStyle: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
iconTheme: const IconThemeData(color: AppColors.textPrimary),
),
// Navigation Bar (bottom)
navigationBarTheme: NavigationBarThemeData(
backgroundColor: AppColors.surface,
surfaceTintColor: Colors.transparent,
indicatorColor: AppColors.primary.withOpacity(0.2),
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.textSecondary,
);
}),
iconTheme: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return const IconThemeData(color: AppColors.primary);
}
return const IconThemeData(color: AppColors.textSecondary);
}),
),
// Navigation Rail (desktop sidebar)
navigationRailTheme: NavigationRailThemeData(
backgroundColor: AppColors.surface,
indicatorColor: AppColors.primary.withOpacity(0.2),
selectedIconTheme: const IconThemeData(color: AppColors.primary),
unselectedIconTheme: const IconThemeData(color: AppColors.textSecondary),
selectedLabelTextStyle: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.primary,
),
unselectedLabelTextStyle: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: AppColors.textSecondary,
),
),
// Cards
cardTheme: CardThemeData(
color: AppColors.surface,
surfaceTintColor: Colors.transparent,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radiusMd),
side: const BorderSide(color: AppColors.border, width: 1),
),
margin: EdgeInsets.zero,
),
// Inputs
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColors.surfaceVariant,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.border),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(radiusSm),
borderSide: const BorderSide(color: AppColors.border),
),
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,
),
),
// 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,
),
),
);
}
}