Skip to content

Instantly share code, notes, and snippets.

@tchafack
Last active May 4, 2023 09:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tchafack/f8f0ca1df9d16915af14fad54b644872 to your computer and use it in GitHub Desktop.
Save tchafack/f8f0ca1df9d16915af14fad54b644872 to your computer and use it in GitHub Desktop.
Flutter Material 3 from design to deployment. Gist based on Flutter Forward https://www.youtube.com/watch?v=7nrhTdS7dHg
import 'theme.dart';
..
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
const basilTheme = BasilTheme();
return MaterialApp.router(
...
theme: basilTheme.toThemeData(),
darkTheme: basilTheme.toDarkThemeData(),
themeMode: ThemeMode.light,
...
);
}
}
import 'package:material_color_utilities/material_color_utilities.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
...
@immutable
class BasilTheme extends ThemeExtension<BasilTheme> {
final Color primaryColor, tertiaryColor, neutralColor;
const BasilTheme({
this.primaryColor = const Color(0xFF356859),
this.tertiaryColor = const Color(0xFFFF5722),
this.neutralColor = const Color(0xFFFFFBE6),
});
@override
ThemeExtension<BasilTheme> copyWith({
Color? primaryColor,
Color? tertiaryColor,
Color? neutralColor,
}) =>
BasilTheme(
primaryColor: primaryColor ?? this.primaryColor,
tertiaryColor: tertiaryColor ?? this.tertiaryColor,
neutralColor: neutralColor ?? this.neutralColor,
);
@override
ThemeExtension<BasilTheme> lerp(
covariant ThemeExtension<BasilTheme>? other, double t) {
if (other is! BasilTheme) return this;
return BasilTheme(
primaryColor: Color.lerp(primaryColor, other.primaryColor, t)!,
tertiaryColor: Color.lerp(tertiaryColor, other.tertiaryColor, t)!,
neutralColor: Color.lerp(neutralColor, other.neutralColor, t)!,
);
}
Scheme _scheme() {
final base = CorePalette.of(primaryColor.value);
final primary = base.primary;
final tertiary = CorePalette.of(tertiaryColor.value).primary;
final neutral = CorePalette.of(neutralColor.value).neutral;
return Scheme(
primary: primary.get(40),
onPrimary: primary.get(100),
primaryContainer: primary.get(90),
onPrimaryContainer: primary.get(10),
secondary: base.secondary.get(40),
onSecondary: base.secondary.get(100),
secondaryContainer: base.secondary.get(90),
onSecondaryContainer: base.secondary.get(10),
tertiary: tertiary.get(40),
onTertiary: tertiary.get(100),
tertiaryContainer: tertiary.get(90),
onTertiaryContainer: tertiary.get(10),
error: base.error.get(40),
onError: base.error.get(100),
errorContainer: base.error.get(90),
onErrorContainer: base.error.get(10),
background: neutral.get(98),
onBackground: neutral.get(10),
surface: neutral.get(98),
onSurface: neutral.get(10),
surfaceVariant: base.neutralVariant.get(90),
onSurfaceVariant: base.neutralVariant.get(30),
outline: base.neutralVariant.get(50),
outlineVariant: base.neutralVariant.get(80),
shadow: neutral.get(0),
scrim: neutral.get(0),
inverseSurface: neutral.get(20),
inverseOnSurface: neutral.get(95),
inversePrimary: primary.get(80));
}
Scheme _darkScheme() {
final base = CorePalette.of(primaryColor.value);
final primary = base.primary;
final tertiary = CorePalette.of(tertiaryColor.value).primary;
final neutral = CorePalette.of(neutralColor.value).neutral;
return Scheme(
primary: primary.get(80),
onPrimary: primary.get(20),
primaryContainer: primary.get(30),
onPrimaryContainer: primary.get(90),
secondary: base.secondary.get(80),
onSecondary: base.secondary.get(20),
secondaryContainer: base.secondary.get(30),
onSecondaryContainer: base.secondary.get(90),
tertiary: tertiary.get(80),
onTertiary: tertiary.get(20),
tertiaryContainer: tertiary.get(30),
onTertiaryContainer: tertiary.get(90),
error: base.error.get(80),
onError: base.error.get(20),
errorContainer: base.error.get(30),
onErrorContainer: base.error.get(90),
background: neutral.get(6),
onBackground: neutral.get(90),
surface: neutral.get(6),
onSurface: neutral.get(90),
surfaceVariant: base.neutralVariant.get(30),
onSurfaceVariant: base.neutralVariant.get(80),
outline: base.neutralVariant.get(60),
outlineVariant: base.neutralVariant.get(30),
shadow: neutral.get(0),
scrim: neutral.get(0),
inverseSurface: neutral.get(90),
inverseOnSurface: neutral.get(20),
inversePrimary: primary.get(40));
}
ThemeData _base(ColorScheme colorScheme) {
final isLight = colorScheme.brightness == Brightness.light;
final primaryTexTheme = GoogleFonts.lektonTextTheme();
final secondaryTexTheme = GoogleFonts.montserratTextTheme();
final textTheme = primaryTexTheme.copyWith(
displaySmall: secondaryTexTheme.displaySmall,
);
return ThemeData(
useMaterial3: true,
extensions: [this],
textTheme: textTheme,
colorScheme: colorScheme,
scaffoldBackgroundColor: isLight ? neutralColor : colorScheme.background,
tabBarTheme: TabBarTheme(
labelColor: colorScheme.onSurface,
unselectedLabelColor: colorScheme.onSurface,
indicator: BoxDecoration(
border: Border(
bottom: BorderSide(color: colorScheme.primary, width: 2,),
),
),
),
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: colorScheme.error,
foregroundColor: colorScheme.onError,
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: isLight ? neutralColor : colorScheme.surface,
selectedIconTheme: IconThemeData(color: colorScheme.onSecondaryContainer,),
indicatorColor: colorScheme.secondaryContainer,
),
appBarTheme: AppBarTheme(backgroundColor: isLight?neutralColor : colorScheme.surface,
),
chipTheme: ChipThemeData(
backgroundColor: isLight ? neutralColor : colorScheme.surface,
)
);
}
ThemeData toThemeData() {
final colorScheme = _scheme().toColorScheme(Brightness.light);
return _base(colorScheme).copyWith(brightness: colorScheme.brightness);
}
ThemeData toDarkThemeData() {
final colorScheme = _darkScheme().toColorScheme(Brightness.dark);
return _base(colorScheme).copyWith(brightness: colorScheme.brightness);
}
}
extension on Scheme {
ColorScheme toColorScheme(Brightness brightness) {
return ColorScheme(
brightness: brightness,
primary: Color(primary),
onPrimary: Color(onPrimary),
secondary: Color(secondary),
onSecondary: Color(onSecondary),
error: Color(error),
onError: Color(onError),
background: Color(background),
onBackground: Color(onBackground),
surface: Color(surface),
onSurface: Color(onSurface));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment