| 1 | import 'package:flutter/material.dart'; |
| 2 | import 'package:cake_wallet/themes/core/material_base_theme.dart'; |
| 3 | import 'package:cake_wallet/themes/core/custom_theme_colors.dart'; |
| 4 | import 'package:cake_wallet/themes/custom_theme_colors/black_theme_custom_colors.dart'; |
| 5 | |
| 6 | enum BlackThemeAccentColor implements ThemeAccentColor { |
| 7 | cakePrimary(Color(0xFF52B6F0), 'Cake Primary'), |
| 8 | bchGreen(Color(0xFF44BA52), 'BCH Green'), |
| 9 | bitcoinYellow(Color(0xFFFFC107), 'Bitcoin Yellow'), |
| 10 | moneroOrange(Color(0xFFFF6600), 'Monero Orange'), |
| 11 | tronRed(Color(0xFFFF4242), 'Tron Red'), |
| 12 | frostingPurple(Color(0xFFBABAF3), 'Frosting Purple'); |
| 13 | |
| 14 | const BlackThemeAccentColor(this.color, this.name); |
| 15 | |
| 16 | @override |
| 17 | final Color color; |
| 18 | |
| 19 | @override |
| 20 | final String name; |
| 21 | } |
| 22 | |
| 23 | class BlackTheme extends MaterialThemeBase { |
| 24 | BlackTheme(this.accentColor, {this.isOled = false}); |
| 25 | |
| 26 | final BlackThemeAccentColor accentColor; |
| 27 | final bool isOled; |
| 28 | |
| 29 | @override |
| 30 | Brightness get brightness => Brightness.dark; |
| 31 | |
| 32 | @override |
| 33 | ThemeMode get themeMode => ThemeMode.dark; |
| 34 | |
| 35 | @override |
| 36 | Color get primaryColor => accentColor.color; |
| 37 | |
| 38 | @override |
| 39 | Color get secondaryColor => const Color(0xFFCCC4CD); |
| 40 | |
| 41 | @override |
| 42 | Color get errorColor => const Color(0xFFFFB4AB); |
| 43 | |
| 44 | @override |
| 45 | Color get surfaceColor => isOled ? const Color(0xFF000000) : const Color(0xFF131314); |
| 46 | |
| 47 | @override |
| 48 | Color get tertiaryColor => const Color(0xFFDEBFC5); |
| 49 | |
| 50 | @override |
| 51 | ColorScheme get colorScheme => ColorScheme.dark( |
| 52 | primary: primaryColor, |
| 53 | onPrimary: const Color(0xFF352D3C), |
| 54 | primaryContainer: const Color(0xFF28212F), |
| 55 | onPrimaryContainer: const Color(0xFFB7ABBE), |
| 56 | secondary: secondaryColor, |
| 57 | onSecondary: const Color(0xFF332F36), |
| 58 | secondaryContainer: const Color(0xFF454148), |
| 59 | onSecondaryContainer: const Color(0xFFDFD6DF), |
| 60 | tertiary: tertiaryColor, |
| 61 | onTertiary: const Color(0xFF3F2B30), |
| 62 | tertiaryContainer: const Color(0xFF321F24), |
| 63 | onTertiaryContainer: const Color(0xFFC6A8AE), |
| 64 | error: errorColor, |
| 65 | onError: const Color(0xFFB71919), |
| 66 | errorContainer: const Color(0xFFC53636), |
| 67 | onErrorContainer: const Color(0xFFFFDAD6), |
| 68 | surface: surfaceColor, |
| 69 | surfaceDim: const Color(0xFF000000), |
| 70 | background: surfaceColor, |
| 71 | onSurface: const Color(0xFFE6E1E3), |
| 72 | onSurfaceVariant: const Color(0xFFB4B4B4), |
| 73 | surfaceContainerLowest: isOled ? const Color(0xFF000000) : const Color(0xFF0F0E0F), |
| 74 | surfaceContainerLow: Color(0xFF1C1B1C), |
| 75 | surfaceContainer: Color(0xFF211F20), |
| 76 | surfaceContainerHigh: Color(0xFF2B292B), |
| 77 | surfaceContainerHighest: Color(0xFF363435), |
| 78 | outline: const Color(0xFF958F95), |
| 79 | outlineVariant: const Color(0xFF2F2D2F), |
| 80 | ); |
| 81 | |
| 82 | static const String fontFamily = 'Wix Madefor Text'; |
| 83 | |
| 84 | @override |
| 85 | TextTheme get textTheme => TextTheme( |
| 86 | displayLarge: TextStyle( |
| 87 | fontSize: 57, |
| 88 | fontWeight: FontWeight.w400, |
| 89 | letterSpacing: -0.25, |
| 90 | color: colorScheme.onSurface, |
| 91 | ), |
| 92 | displayMedium: TextStyle( |
| 93 | fontSize: 45, |
| 94 | fontWeight: FontWeight.w400, |
| 95 | letterSpacing: 0, |
| 96 | color: colorScheme.onSurface, |
| 97 | ), |
| 98 | displaySmall: TextStyle( |
| 99 | fontSize: 36, |
| 100 | fontWeight: FontWeight.w400, |
| 101 | letterSpacing: 0, |
| 102 | color: colorScheme.onSurface, |
| 103 | ), |
| 104 | headlineLarge: TextStyle( |
| 105 | fontSize: 22, |
| 106 | fontWeight: FontWeight.w600, |
| 107 | letterSpacing: 0, |
| 108 | color: colorScheme.onSurface, |
| 109 | ), |
| 110 | headlineMedium: TextStyle( |
| 111 | fontSize: 18, |
| 112 | fontWeight: FontWeight.w600, |
| 113 | letterSpacing: 0, |
| 114 | color: colorScheme.onSurface, |
| 115 | ), |
| 116 | headlineSmall: TextStyle( |
| 117 | fontSize: 14, |
| 118 | fontWeight: FontWeight.w600, |
| 119 | letterSpacing: 0, |
| 120 | color: colorScheme.onSurface, |
| 121 | ), |
| 122 | titleLarge: TextStyle( |
| 123 | fontSize: 22, |
| 124 | fontWeight: FontWeight.w500, |
| 125 | letterSpacing: 0, |
| 126 | color: colorScheme.onSurface, |
| 127 | ), |
| 128 | titleMedium: TextStyle( |
| 129 | fontSize: 16, |
| 130 | fontWeight: FontWeight.w500, |
| 131 | letterSpacing: 0.15, |
| 132 | color: colorScheme.onSurface, |
| 133 | ), |
| 134 | titleSmall: TextStyle( |
| 135 | fontSize: 14, |
| 136 | fontWeight: FontWeight.w500, |
| 137 | letterSpacing: 0.1, |
| 138 | color: colorScheme.onSurface, |
| 139 | ), |
| 140 | bodyLarge: TextStyle( |
| 141 | fontSize: 16, |
| 142 | fontWeight: FontWeight.w400, |
| 143 | letterSpacing: 0.5, |
| 144 | color: colorScheme.onSurface, |
| 145 | ), |
| 146 | bodyMedium: TextStyle( |
| 147 | fontSize: 14, |
| 148 | fontWeight: FontWeight.w400, |
| 149 | letterSpacing: 0.25, |
| 150 | color: colorScheme.onSurface, |
| 151 | ), |
| 152 | bodySmall: TextStyle( |
| 153 | fontSize: 12, |
| 154 | fontWeight: FontWeight.w400, |
| 155 | letterSpacing: 0.4, |
| 156 | color: colorScheme.onSurface, |
| 157 | ), |
| 158 | labelLarge: TextStyle( |
| 159 | fontSize: 14, |
| 160 | fontWeight: FontWeight.w500, |
| 161 | letterSpacing: 0.1, |
| 162 | color: colorScheme.onSurface, |
| 163 | ), |
| 164 | labelMedium: TextStyle( |
| 165 | fontSize: 12, |
| 166 | fontWeight: FontWeight.w500, |
| 167 | letterSpacing: 0.5, |
| 168 | color: colorScheme.onSurface, |
| 169 | ), |
| 170 | labelSmall: TextStyle( |
| 171 | fontSize: 10, |
| 172 | fontWeight: FontWeight.w500, |
| 173 | letterSpacing: 0.5, |
| 174 | color: colorScheme.onSurface, |
| 175 | ), |
| 176 | ); |
| 177 | |
| 178 | @override |
| 179 | ThemeData get themeData => ThemeData( |
| 180 | useMaterial3: true, |
| 181 | fontFamily: fontFamily, |
| 182 | brightness: brightness, |
| 183 | colorScheme: colorScheme, |
| 184 | scaffoldBackgroundColor: surfaceColor, |
| 185 | canvasColor: surfaceColor, |
| 186 | cardColor: colorScheme.surface, |
| 187 | textTheme: textTheme, |
| 188 | appBarTheme: AppBarTheme( |
| 189 | backgroundColor: surfaceColor, |
| 190 | foregroundColor: colorScheme.onSurface, |
| 191 | elevation: 0, |
| 192 | ), |
| 193 | cardTheme: CardThemeData( |
| 194 | color: colorScheme.surface, |
| 195 | elevation: 1, |
| 196 | shape: RoundedRectangleBorder( |
| 197 | borderRadius: BorderRadius.circular(12), |
| 198 | ), |
| 199 | ), |
| 200 | elevatedButtonTheme: ElevatedButtonThemeData( |
| 201 | style: ElevatedButton.styleFrom( |
| 202 | backgroundColor: colorScheme.primary, |
| 203 | foregroundColor: colorScheme.onPrimary, |
| 204 | elevation: 0, |
| 205 | shape: RoundedRectangleBorder( |
| 206 | borderRadius: BorderRadius.circular(18), |
| 207 | ), |
| 208 | ), |
| 209 | ), |
| 210 | outlinedButtonTheme: OutlinedButtonThemeData( |
| 211 | style: OutlinedButton.styleFrom( |
| 212 | foregroundColor: colorScheme.primary, |
| 213 | side: BorderSide(color: colorScheme.outline), |
| 214 | shape: RoundedRectangleBorder( |
| 215 | borderRadius: BorderRadius.circular(18), |
| 216 | ), |
| 217 | ), |
| 218 | ), |
| 219 | textButtonTheme: TextButtonThemeData( |
| 220 | style: TextButton.styleFrom( |
| 221 | foregroundColor: colorScheme.primary, |
| 222 | shape: RoundedRectangleBorder( |
| 223 | borderRadius: BorderRadius.circular(18), |
| 224 | ), |
| 225 | ), |
| 226 | ), |
| 227 | inputDecorationTheme: InputDecorationTheme( |
| 228 | filled: true, |
| 229 | fillColor: colorScheme.surfaceContainer, |
| 230 | border: OutlineInputBorder( |
| 231 | borderRadius: BorderRadius.circular(18), |
| 232 | borderSide: BorderSide.none, |
| 233 | ), |
| 234 | enabledBorder: OutlineInputBorder( |
| 235 | borderRadius: BorderRadius.circular(18), |
| 236 | borderSide: BorderSide.none, |
| 237 | ), |
| 238 | focusedBorder: OutlineInputBorder( |
| 239 | borderRadius: BorderRadius.circular(18), |
| 240 | borderSide: BorderSide(color: colorScheme.primary), |
| 241 | ), |
| 242 | errorBorder: OutlineInputBorder( |
| 243 | borderRadius: BorderRadius.circular(18), |
| 244 | borderSide: BorderSide(color: colorScheme.error), |
| 245 | ), |
| 246 | focusedErrorBorder: OutlineInputBorder( |
| 247 | borderRadius: BorderRadius.circular(18), |
| 248 | borderSide: BorderSide(color: colorScheme.error), |
| 249 | ), |
| 250 | disabledBorder: OutlineInputBorder( |
| 251 | borderRadius: BorderRadius.circular(18), |
| 252 | borderSide: BorderSide.none, |
| 253 | ), |
| 254 | ), |
| 255 | ); |
| 256 | |
| 257 | @override |
| 258 | String get title => 'Black Theme (${accentColor.name})'; |
| 259 | |
| 260 | @override |
| 261 | ThemeType get type => ThemeType.dark; |
| 262 | |
| 263 | @override |
| 264 | int get raw { |
| 265 | final baseValue = switch (accentColor) { |
| 266 | BlackThemeAccentColor.cakePrimary => 12, |
| 267 | BlackThemeAccentColor.bchGreen => 13, |
| 268 | BlackThemeAccentColor.bitcoinYellow => 14, |
| 269 | BlackThemeAccentColor.moneroOrange => 15, |
| 270 | BlackThemeAccentColor.tronRed => 16, |
| 271 | BlackThemeAccentColor.frostingPurple => 17, |
| 272 | }; |
| 273 | if (!isOled) return baseValue; |
| 274 | // OLED encodes as 100 + base to avoid collisions |
| 275 | return 100 + baseValue; |
| 276 | } |
| 277 | |
| 278 | @override |
| 279 | CustomThemeColors get customColors => BlackThemeCustomColors(); |
| 280 | |
| 281 | @override |
| 282 | String? get themeFamily => 'BlackTheme'; |
| 283 | |
| 284 | @override |
| 285 | String? get accentColorId => accentColor.name.toLowerCase(); |
| 286 | |
| 287 | @override |
| 288 | String? get accentColorName => accentColor.name; |
| 289 | |
| 290 | @override |
| 291 | bool operator ==(Object other) => |
| 292 | identical(this, other) || |
| 293 | other is BlackTheme && |
| 294 | runtimeType == other.runtimeType && |
| 295 | accentColor == other.accentColor && |
| 296 | isOled == other.isOled; |
| 297 | |
| 298 | @override |
| 299 | int get hashCode => Object.hash(accentColor, isOled); |
| 300 | } |