first commit
This commit is contained in:
96
lib/core/theme/app_animations.dart
Normal file
96
lib/core/theme/app_animations.dart
Normal file
@@ -0,0 +1,96 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppAnimations {
|
||||
const AppAnimations._();
|
||||
|
||||
/// A standard fade transition
|
||||
static Widget fade({
|
||||
required Widget child,
|
||||
Duration duration = const Duration(milliseconds: 300),
|
||||
}) {
|
||||
return AnimatedSwitcher(
|
||||
duration: duration,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
/// A slide transition from the bottom (Brutalist style)
|
||||
static Widget slideIn({
|
||||
required Widget child,
|
||||
Offset begin = const Offset(0, 0.1),
|
||||
Duration duration = const Duration(milliseconds: 400),
|
||||
}) {
|
||||
return TweenAnimationBuilder<Offset>(
|
||||
tween: Tween<Offset>(begin: begin, end: Offset.zero),
|
||||
duration: duration,
|
||||
curve: Curves.easeOutQuart,
|
||||
builder: (context, offset, child) {
|
||||
return FractionalTranslation(
|
||||
translation: offset,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
/// A simple "Glitch" effect using staggered offsets and opacities
|
||||
/// This simulates an underground/grunge signal interference.
|
||||
static Widget glitch({required Widget child}) {
|
||||
return _GlitchWidget(child: child);
|
||||
}
|
||||
}
|
||||
|
||||
class _GlitchWidget extends StatefulWidget {
|
||||
final Widget child;
|
||||
const _GlitchWidget({required this.child});
|
||||
|
||||
@override
|
||||
State<_GlitchWidget> createState() => _GlitchWidgetState();
|
||||
}
|
||||
|
||||
class _GlitchWidgetState extends State<_GlitchWidget> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (context, child) {
|
||||
final double glitchFactor = _controller.value;
|
||||
// Only glitch occasionally
|
||||
if (glitchFactor > 0.9) {
|
||||
return Stack(
|
||||
children: [
|
||||
Transform.translate(
|
||||
offset: const Offset(2, 0),
|
||||
child: Opacity(opacity: 0.5, child: widget.child),
|
||||
),
|
||||
Transform.translate(
|
||||
offset: const Offset(-2, 1),
|
||||
child: Opacity(opacity: 0.5, child: widget.child),
|
||||
),
|
||||
widget.child,
|
||||
],
|
||||
);
|
||||
}
|
||||
return widget.child;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
35
lib/core/theme/app_colors.dart
Normal file
35
lib/core/theme/app_colors.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppColors {
|
||||
const AppColors._();
|
||||
|
||||
// Core Palette
|
||||
static const black = Color(0xFF000000); // Pitch black
|
||||
static const blackRaised = Color(0xFF1A1A1A); // Slightly raised black
|
||||
static const blackSoft = Color(0xFF0F0F0F); // Soft black for backgrounds
|
||||
static const darkGrey = Color(0xFF0A0A0A);
|
||||
static const white = Color(0xFFFFFFFF);
|
||||
static const offWhite = Color(0xFFEBEBEB); // For body text readability
|
||||
|
||||
// RIOTZ Red Tones (Aggressive & Premium)
|
||||
static const neonRed = Color(0xFFFF0033); // Primary accent
|
||||
static const bloodRed = Color(0xFF8B0000); // Secondary
|
||||
static const deepRed = Color(0xFF4A0000); // Muted backgrounds
|
||||
|
||||
// Purple Accents
|
||||
static const neonPurple = Color(0xFF9D00FF); // Neon purple accent
|
||||
|
||||
// Surfaces & Borders
|
||||
static const surface = Color(0xFF0D0D0D); // Elevated surfaces
|
||||
static const surfaceLight = Color(0xFF1A1A1A);
|
||||
static const border = Color(0xFF262626); // Brutalist outlines
|
||||
|
||||
// Neutral / Muted
|
||||
static const grey = Color(0xFF757575);
|
||||
static const greyDark = Color(0xFF424242);
|
||||
static const greyMuted = Color(0xFF212121);
|
||||
|
||||
// Semantic
|
||||
static const error = Color(0xFFFF0033);
|
||||
static const success = Color(0xFF00FF66); // Acid green for contrast
|
||||
}
|
||||
12
lib/core/theme/app_motion.dart
Normal file
12
lib/core/theme/app_motion.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppMotion {
|
||||
const AppMotion._();
|
||||
|
||||
static const fast = Duration(milliseconds: 120);
|
||||
static const normal = Duration(milliseconds: 220);
|
||||
static const slow = Duration(milliseconds: 360);
|
||||
|
||||
static const standardCurve = Curves.easeOutCubic;
|
||||
static const emphasizedCurve = Curves.easeOutQuart;
|
||||
}
|
||||
131
lib/core/theme/app_theme.dart
Normal file
131
lib/core/theme/app_theme.dart
Normal file
@@ -0,0 +1,131 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_colors.dart';
|
||||
import 'app_typography.dart';
|
||||
import 'app_motion.dart';
|
||||
|
||||
class AppTheme {
|
||||
const AppTheme._();
|
||||
|
||||
static ThemeData get dark {
|
||||
final textTheme = AppTypography.darkTextTheme();
|
||||
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.dark,
|
||||
scaffoldBackgroundColor: AppColors.black,
|
||||
colorScheme: const ColorScheme.dark(
|
||||
primary: AppColors.neonRed,
|
||||
secondary: AppColors.bloodRed,
|
||||
surface: AppColors.surface,
|
||||
onPrimary: AppColors.white,
|
||||
onSecondary: AppColors.white,
|
||||
onSurface: AppColors.white,
|
||||
error: AppColors.error,
|
||||
outline: AppColors.border,
|
||||
),
|
||||
textTheme: textTheme,
|
||||
|
||||
// App Bar Theme - Centralized & Brutalist
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: AppColors.black,
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
iconTheme: const IconThemeData(color: AppColors.white, size: 20),
|
||||
titleTextStyle: textTheme.headlineMedium?.copyWith(
|
||||
color: AppColors.white,
|
||||
),
|
||||
),
|
||||
|
||||
// Card Theme - Sharp Edges, Subtle Borders
|
||||
cardTheme: CardThemeData(
|
||||
color: AppColors.surface,
|
||||
elevation: 0,
|
||||
margin: EdgeInsets.zero,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.zero,
|
||||
side: BorderSide(color: AppColors.border, width: 1),
|
||||
),
|
||||
),
|
||||
|
||||
// Input Decoration - Industrial / Terminal style
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: AppColors.surface,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18),
|
||||
hintStyle: textTheme.bodySmall?.copyWith(color: AppColors.greyDark),
|
||||
labelStyle: textTheme.bodyMedium?.copyWith(color: AppColors.grey),
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.zero,
|
||||
borderSide: BorderSide(color: AppColors.border),
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.zero,
|
||||
borderSide: BorderSide(color: AppColors.border),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.zero,
|
||||
borderSide: BorderSide(color: AppColors.neonRed, width: 1.5),
|
||||
),
|
||||
errorBorder: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.zero,
|
||||
borderSide: BorderSide(color: AppColors.error),
|
||||
),
|
||||
),
|
||||
|
||||
// Button Themes
|
||||
filledButtonTheme: FilledButtonThemeData(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: AppColors.neonRed,
|
||||
foregroundColor: AppColors.white,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero),
|
||||
textStyle: textTheme.labelLarge,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
|
||||
),
|
||||
),
|
||||
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: AppColors.white,
|
||||
side: const BorderSide(color: AppColors.white, width: 1.5),
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero),
|
||||
textStyle: textTheme.labelLarge,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
|
||||
),
|
||||
),
|
||||
|
||||
// Navigation Bar - Custom Riotz Feel
|
||||
navigationBarTheme: NavigationBarThemeData(
|
||||
backgroundColor: AppColors.black,
|
||||
indicatorColor: AppColors.neonRed.withOpacity(0.1),
|
||||
labelTextStyle: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return textTheme.bodySmall?.copyWith(color: AppColors.neonRed, fontWeight: FontWeight.bold);
|
||||
}
|
||||
return textTheme.bodySmall?.copyWith(color: AppColors.grey);
|
||||
}),
|
||||
iconTheme: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const IconThemeData(color: AppColors.neonRed, size: 24);
|
||||
}
|
||||
return const IconThemeData(color: AppColors.grey, size: 24);
|
||||
}),
|
||||
),
|
||||
|
||||
// Dialog Theme
|
||||
dialogTheme: const DialogThemeData(
|
||||
backgroundColor: AppColors.surface,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.zero,
|
||||
side: BorderSide(color: AppColors.border, width: 1),
|
||||
),
|
||||
),
|
||||
|
||||
dividerTheme: const DividerThemeData(
|
||||
color: AppColors.border,
|
||||
thickness: 1,
|
||||
space: 1,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
91
lib/core/theme/app_typography.dart
Normal file
91
lib/core/theme/app_typography.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import 'app_colors.dart';
|
||||
|
||||
class AppTypography {
|
||||
const AppTypography._();
|
||||
|
||||
// Primary heading font: Aggressive, industrial, and bold
|
||||
static String get headingFont => GoogleFonts.bebasNeue().fontFamily!;
|
||||
|
||||
// Body font: Monospace or clean Sans for that "terminal/underground" feel
|
||||
static String get bodyFont => GoogleFonts.inter().fontFamily!;
|
||||
static String get monoFont => GoogleFonts.jetBrainsMono().fontFamily!;
|
||||
|
||||
static TextTheme darkTextTheme() {
|
||||
return TextTheme(
|
||||
displayLarge: TextStyle(
|
||||
fontFamily: headingFont,
|
||||
fontSize: 72,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: AppColors.white,
|
||||
letterSpacing: -1.0,
|
||||
height: 0.9,
|
||||
),
|
||||
displayMedium: TextStyle(
|
||||
fontFamily: headingFont,
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.white,
|
||||
letterSpacing: 0.5,
|
||||
height: 1.0,
|
||||
),
|
||||
headlineLarge: TextStyle(
|
||||
fontFamily: headingFont,
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.neonRed,
|
||||
letterSpacing: 1.5,
|
||||
),
|
||||
headlineMedium: TextStyle(
|
||||
fontFamily: headingFont,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.white,
|
||||
letterSpacing: 1.2,
|
||||
),
|
||||
titleLarge: TextStyle(
|
||||
fontFamily: bodyFont,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: AppColors.white,
|
||||
letterSpacing: -0.5,
|
||||
),
|
||||
titleMedium: TextStyle(
|
||||
fontFamily: bodyFont,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.white,
|
||||
),
|
||||
bodyLarge: TextStyle(
|
||||
fontFamily: bodyFont,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.offWhite,
|
||||
height: 1.5,
|
||||
),
|
||||
bodyMedium: TextStyle(
|
||||
fontFamily: bodyFont,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.offWhite,
|
||||
height: 1.4,
|
||||
),
|
||||
bodySmall: TextStyle(
|
||||
fontFamily: monoFont,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.grey,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
labelLarge: TextStyle(
|
||||
fontFamily: headingFont,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.white,
|
||||
letterSpacing: 2.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user