app_theme.dart 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import 'package:flutter/material.dart';
  2. import 'accent_choice.dart';
  3. import 'app_colors.dart';
  4. /// Material 3 theme built from the CarDash token set.
  5. class AppTheme {
  6. const AppTheme._();
  7. static ThemeData light({AccentChoice accent = AccentChoice.green}) =>
  8. _build(AppColors.lightFor(accent), Brightness.light);
  9. static ThemeData dark({AccentChoice accent = AccentChoice.green}) =>
  10. _build(AppColors.darkFor(accent), Brightness.dark);
  11. static ThemeData _build(AppColors colors, Brightness brightness) {
  12. final scheme =
  13. ColorScheme.fromSeed(
  14. seedColor: colors.accent,
  15. brightness: brightness,
  16. ).copyWith(
  17. primary: colors.accent,
  18. onPrimary: colors.accentInk,
  19. primaryContainer: colors.accentSoft,
  20. onPrimaryContainer: colors.ink,
  21. secondary: colors.accent,
  22. onSecondary: colors.accentInk,
  23. secondaryContainer: colors.accentSoft,
  24. onSecondaryContainer: colors.ink,
  25. surface: colors.surface,
  26. onSurface: colors.ink,
  27. surfaceContainerHighest: colors.surfaceStrong,
  28. outline: colors.border,
  29. outlineVariant: colors.border,
  30. error: colors.danger,
  31. onError: Colors.white,
  32. );
  33. final textTheme = _textTheme(colors);
  34. return ThemeData(
  35. useMaterial3: true,
  36. brightness: brightness,
  37. colorScheme: scheme,
  38. scaffoldBackgroundColor: colors.canvas,
  39. canvasColor: colors.canvas,
  40. fontFamily: 'Manrope',
  41. textTheme: textTheme,
  42. iconTheme: IconThemeData(color: colors.ink, size: 22),
  43. dividerTheme: DividerThemeData(color: colors.border, thickness: 1),
  44. sliderTheme: SliderThemeData(
  45. activeTrackColor: colors.accent,
  46. inactiveTrackColor: colors.border,
  47. thumbColor: colors.accent,
  48. overlayColor: colors.accent.withValues(alpha: 0.14),
  49. trackHeight: 6,
  50. thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10),
  51. overlayShape: const RoundSliderOverlayShape(overlayRadius: 22),
  52. trackShape: const RoundedRectSliderTrackShape(),
  53. tickMarkShape: SliderTickMarkShape.noTickMark,
  54. disabledActiveTrackColor: colors.border,
  55. disabledInactiveTrackColor: colors.border,
  56. disabledThumbColor: colors.inkFaint,
  57. ),
  58. inputDecorationTheme: InputDecorationTheme(
  59. filled: true,
  60. fillColor: colors.surfaceStrong,
  61. hintStyle: textTheme.bodyLarge?.copyWith(color: colors.inkFaint),
  62. contentPadding: const EdgeInsets.symmetric(
  63. horizontal: 20,
  64. vertical: 16,
  65. ),
  66. border: OutlineInputBorder(
  67. borderRadius: BorderRadius.circular(18),
  68. borderSide: BorderSide.none,
  69. ),
  70. enabledBorder: OutlineInputBorder(
  71. borderRadius: BorderRadius.circular(18),
  72. borderSide: BorderSide(color: colors.border),
  73. ),
  74. focusedBorder: OutlineInputBorder(
  75. borderRadius: BorderRadius.circular(18),
  76. borderSide: BorderSide(color: colors.accent, width: 1.4),
  77. ),
  78. ),
  79. snackBarTheme: SnackBarThemeData(
  80. backgroundColor: colors.ink,
  81. contentTextStyle: textTheme.bodyMedium?.copyWith(color: colors.canvas),
  82. behavior: SnackBarBehavior.floating,
  83. elevation: 0,
  84. shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
  85. ),
  86. bottomSheetTheme: const BottomSheetThemeData(
  87. backgroundColor: Colors.transparent,
  88. surfaceTintColor: Colors.transparent,
  89. modalBarrierColor: Color(0x99000000),
  90. ),
  91. dialogTheme: DialogThemeData(
  92. backgroundColor: colors.surface,
  93. surfaceTintColor: Colors.transparent,
  94. shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(26)),
  95. ),
  96. pageTransitionsTheme: const PageTransitionsTheme(
  97. builders: {
  98. TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
  99. TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(),
  100. },
  101. ),
  102. extensions: [colors],
  103. );
  104. }
  105. static TextTheme _textTheme(AppColors colors) {
  106. TextStyle style(
  107. double size,
  108. FontWeight weight,
  109. int variation, {
  110. double? height,
  111. double? letterSpacing,
  112. }) {
  113. return TextStyle(
  114. fontFamily: 'Manrope',
  115. fontSize: size,
  116. fontWeight: weight,
  117. height: height,
  118. letterSpacing: letterSpacing,
  119. color: colors.ink,
  120. fontVariations: [FontVariation('wght', variation.toDouble())],
  121. );
  122. }
  123. return TextTheme(
  124. displayLarge: style(
  125. 68,
  126. FontWeight.w600,
  127. 640,
  128. height: 0.96,
  129. letterSpacing: -2.6,
  130. ),
  131. displayMedium: style(
  132. 52,
  133. FontWeight.w600,
  134. 620,
  135. height: 1.0,
  136. letterSpacing: -1.8,
  137. ),
  138. displaySmall: style(
  139. 42,
  140. FontWeight.w600,
  141. 620,
  142. height: 1.05,
  143. letterSpacing: -1.2,
  144. ),
  145. headlineLarge: style(
  146. 34,
  147. FontWeight.w600,
  148. 620,
  149. height: 1.1,
  150. letterSpacing: -0.6,
  151. ),
  152. headlineMedium: style(
  153. 28,
  154. FontWeight.w600,
  155. 610,
  156. height: 1.15,
  157. letterSpacing: -0.4,
  158. ),
  159. headlineSmall: style(24, FontWeight.w600, 600, height: 1.2),
  160. titleLarge: style(20, FontWeight.w600, 600, height: 1.25),
  161. titleMedium: style(16, FontWeight.w600, 600, height: 1.3),
  162. titleSmall: style(14, FontWeight.w600, 600, height: 1.3),
  163. bodyLarge: style(16, FontWeight.w400, 440, height: 1.45),
  164. bodyMedium: style(14, FontWeight.w400, 440, height: 1.45),
  165. bodySmall: style(12, FontWeight.w400, 430, height: 1.4),
  166. labelLarge: style(14, FontWeight.w600, 600, height: 1.2),
  167. labelMedium: style(12, FontWeight.w500, 530, height: 1.25),
  168. labelSmall: style(11, FontWeight.w500, 520, height: 1.25),
  169. ).apply(bodyColor: colors.ink, displayColor: colors.ink);
  170. }
  171. }