Major UI overhaul

This commit is contained in:
2026-02-10 23:11:45 +08:00
parent f4dea74394
commit 01c6b3537c
17 changed files with 2977 additions and 1219 deletions
+65 -13
View File
@@ -1,25 +1,39 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'app_typography.dart';
class AppTheme {
static ThemeData light() {
final base = ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF0C4A6E),
seedColor: const Color(0xFF334155),
brightness: Brightness.light,
),
useMaterial3: true,
);
final textTheme = GoogleFonts.spaceGroteskTextTheme(base.textTheme);
final monoTheme = GoogleFonts.robotoMonoTextTheme(base.textTheme);
final mono = AppMonoText(
label:
monoTheme.labelMedium?.copyWith(letterSpacing: 0.3) ??
const TextStyle(letterSpacing: 0.3),
body:
monoTheme.bodyMedium?.copyWith(letterSpacing: 0.2) ??
const TextStyle(letterSpacing: 0.2),
);
return base.copyWith(
textTheme: textTheme,
scaffoldBackgroundColor: const Color(0xFFF6F8FA),
scaffoldBackgroundColor: base.colorScheme.surfaceContainerLowest,
extensions: [mono],
appBarTheme: AppBarTheme(
backgroundColor: base.colorScheme.surface,
foregroundColor: base.colorScheme.onSurface,
elevation: 0,
scrolledUnderElevation: 1,
surfaceTintColor: base.colorScheme.surfaceTint,
centerTitle: false,
titleTextStyle: textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w700,
@@ -28,20 +42,26 @@ class AppTheme {
),
cardTheme: CardThemeData(
color: base.colorScheme.surface,
elevation: 0.6,
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
borderRadius: BorderRadius.circular(20),
side: BorderSide(color: base.colorScheme.outlineVariant),
),
),
chipTheme: ChipThemeData(
backgroundColor: base.colorScheme.surfaceContainerHighest,
side: BorderSide(color: base.colorScheme.outlineVariant),
labelStyle: textTheme.labelSmall,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
dividerTheme: DividerThemeData(
color: base.colorScheme.outlineVariant,
thickness: 1,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: base.colorScheme.surface,
fillColor: base.colorScheme.surfaceContainerLow,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: base.colorScheme.outlineVariant),
@@ -72,6 +92,11 @@ class AppTheme {
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 12),
),
),
navigationDrawerTheme: NavigationDrawerThemeData(
backgroundColor: base.colorScheme.surface,
indicatorColor: base.colorScheme.secondaryContainer,
tileHeight: 52,
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: base.colorScheme.surface,
selectedIconTheme: IconThemeData(color: base.colorScheme.primary),
@@ -79,6 +104,7 @@ class AppTheme {
fontWeight: FontWeight.w600,
),
unselectedIconTheme: IconThemeData(color: base.colorScheme.onSurface),
indicatorColor: base.colorScheme.secondaryContainer,
),
navigationBarTheme: NavigationBarThemeData(
backgroundColor: base.colorScheme.surface,
@@ -88,8 +114,9 @@ class AppTheme {
),
),
listTileTheme: ListTileThemeData(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
tileColor: base.colorScheme.surface,
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
),
);
}
@@ -97,21 +124,33 @@ class AppTheme {
static ThemeData dark() {
final base = ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF38BDF8),
seedColor: const Color(0xFF334155),
brightness: Brightness.dark,
),
useMaterial3: true,
);
final textTheme = GoogleFonts.spaceGroteskTextTheme(base.textTheme);
final monoTheme = GoogleFonts.robotoMonoTextTheme(base.textTheme);
final mono = AppMonoText(
label:
monoTheme.labelMedium?.copyWith(letterSpacing: 0.3) ??
const TextStyle(letterSpacing: 0.3),
body:
monoTheme.bodyMedium?.copyWith(letterSpacing: 0.2) ??
const TextStyle(letterSpacing: 0.2),
);
return base.copyWith(
textTheme: textTheme,
scaffoldBackgroundColor: const Color(0xFF0B111A),
scaffoldBackgroundColor: base.colorScheme.surface,
extensions: [mono],
appBarTheme: AppBarTheme(
backgroundColor: base.colorScheme.surface,
foregroundColor: base.colorScheme.onSurface,
elevation: 0,
scrolledUnderElevation: 1,
surfaceTintColor: base.colorScheme.surfaceTint,
centerTitle: false,
titleTextStyle: textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w700,
@@ -119,21 +158,27 @@ class AppTheme {
),
),
cardTheme: CardThemeData(
color: const Color(0xFF121A24),
color: base.colorScheme.surfaceContainer,
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
borderRadius: BorderRadius.circular(20),
side: BorderSide(color: base.colorScheme.outlineVariant),
),
),
chipTheme: ChipThemeData(
backgroundColor: base.colorScheme.surfaceContainerHighest,
side: BorderSide(color: base.colorScheme.outlineVariant),
labelStyle: textTheme.labelSmall,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
dividerTheme: DividerThemeData(
color: base.colorScheme.outlineVariant,
thickness: 1,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: const Color(0xFF121A24),
fillColor: base.colorScheme.surfaceContainerLow,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: base.colorScheme.outlineVariant),
@@ -164,6 +209,11 @@ class AppTheme {
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 12),
),
),
navigationDrawerTheme: NavigationDrawerThemeData(
backgroundColor: base.colorScheme.surface,
indicatorColor: base.colorScheme.secondaryContainer,
tileHeight: 52,
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: base.colorScheme.surface,
selectedIconTheme: IconThemeData(color: base.colorScheme.primary),
@@ -171,6 +221,7 @@ class AppTheme {
fontWeight: FontWeight.w600,
),
unselectedIconTheme: IconThemeData(color: base.colorScheme.onSurface),
indicatorColor: base.colorScheme.secondaryContainer,
),
navigationBarTheme: NavigationBarThemeData(
backgroundColor: base.colorScheme.surface,
@@ -180,8 +231,9 @@ class AppTheme {
),
),
listTileTheme: ListTileThemeData(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
tileColor: const Color(0xFF121A24),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
tileColor: base.colorScheme.surfaceContainer,
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
),
);
}
+28
View File
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
@immutable
class AppMonoText extends ThemeExtension<AppMonoText> {
const AppMonoText({required this.label, required this.body});
final TextStyle label;
final TextStyle body;
@override
AppMonoText copyWith({TextStyle? label, TextStyle? body}) {
return AppMonoText(label: label ?? this.label, body: body ?? this.body);
}
@override
AppMonoText lerp(ThemeExtension<AppMonoText>? other, double t) {
if (other is! AppMonoText) return this;
return AppMonoText(
label: TextStyle.lerp(label, other.label, t) ?? label,
body: TextStyle.lerp(body, other.body, t) ?? body,
);
}
static AppMonoText of(BuildContext context) {
final ext = Theme.of(context).extension<AppMonoText>();
return ext ?? const AppMonoText(label: TextStyle(), body: TextStyle());
}
}