theme_manager.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. import 'package:flutter/foundation.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:shared_preferences/shared_preferences.dart';
  4. import 'theme_notifier.dart';
  5. /// Seasonal theme system for ZenTap
  6. enum SeasonalTheme {
  7. automatic('automatic'),
  8. default_('default'),
  9. spring('spring'),
  10. summer('summer'),
  11. autumn('autumn'),
  12. winter('winter');
  13. const SeasonalTheme(this.id);
  14. final String id;
  15. static SeasonalTheme fromId(String id) {
  16. return SeasonalTheme.values.firstWhere(
  17. (theme) => theme.id == id,
  18. orElse: () => SeasonalTheme.automatic,
  19. );
  20. }
  21. }
  22. /// Theme color scheme for each season
  23. class SeasonalColors {
  24. final Color appBackground;
  25. final Color secondaryBackground;
  26. final Color primaryText;
  27. final Color secondaryText;
  28. final Color mutedText;
  29. final Color buttonBackground;
  30. final Color buttonText;
  31. final Color uiElements;
  32. final Color gameBoardBorder;
  33. final Color bubbleDefault;
  34. final Color bubblePopEffect;
  35. final Color scoreText;
  36. final Color timerText;
  37. final Color links;
  38. final Color linkHover;
  39. final Color selectedMenuItem;
  40. // Animation colors
  41. final List<Color> animationLayer1;
  42. final List<Color> animationLayer2;
  43. final List<Color> animationLayer3;
  44. final List<Color> zenModeColors;
  45. const SeasonalColors({
  46. required this.appBackground,
  47. required this.secondaryBackground,
  48. required this.primaryText,
  49. required this.secondaryText,
  50. required this.mutedText,
  51. required this.buttonBackground,
  52. required this.buttonText,
  53. required this.uiElements,
  54. required this.gameBoardBorder,
  55. required this.bubbleDefault,
  56. required this.bubblePopEffect,
  57. required this.scoreText,
  58. required this.timerText,
  59. required this.links,
  60. required this.linkHover,
  61. required this.selectedMenuItem,
  62. required this.animationLayer1,
  63. required this.animationLayer2,
  64. required this.animationLayer3,
  65. required this.zenModeColors,
  66. });
  67. }
  68. class ThemeManager {
  69. static const String _keySelectedTheme = 'selected_theme';
  70. static SharedPreferences? _prefs;
  71. static SeasonalTheme _currentTheme = SeasonalTheme.automatic;
  72. static Future<void> init() async {
  73. _prefs = await SharedPreferences.getInstance();
  74. final themeId = _prefs?.getString(_keySelectedTheme) ?? 'automatic';
  75. _currentTheme = SeasonalTheme.fromId(themeId);
  76. ThemeNotifier().initFromManager();
  77. }
  78. static SeasonalTheme get currentTheme => _currentTheme;
  79. static Future<void> setTheme(SeasonalTheme theme) async {
  80. _currentTheme = theme;
  81. await _prefs?.setString(_keySelectedTheme, theme.id);
  82. ThemeNotifier().setTheme(theme);
  83. }
  84. /// Detect current season based on date
  85. static SeasonalTheme _detectCurrentSeason() {
  86. final now = DateTime.now();
  87. final month = now.month;
  88. final day = now.day;
  89. // Northern hemisphere seasons
  90. if ((month == 3 && day >= 20) ||
  91. month == 4 ||
  92. month == 5 ||
  93. (month == 6 && day < 21)) {
  94. return SeasonalTheme.spring; // March 20 - June 20
  95. } else if ((month == 6 && day >= 21) ||
  96. month == 7 ||
  97. month == 8 ||
  98. (month == 9 && day < 22)) {
  99. return SeasonalTheme.summer; // June 21 - September 21
  100. } else if ((month == 9 && day >= 22) ||
  101. month == 10 ||
  102. month == 11 ||
  103. (month == 12 && day < 21)) {
  104. return SeasonalTheme.autumn; // September 22 - December 20
  105. } else {
  106. return SeasonalTheme.winter; // December 21 - March 19
  107. }
  108. }
  109. /// Get the effective theme (resolves automatic to actual season)
  110. static SeasonalTheme get effectiveTheme {
  111. if (_currentTheme == SeasonalTheme.automatic) {
  112. return _detectCurrentSeason();
  113. }
  114. return _currentTheme;
  115. }
  116. /// Get the auto-detected season (regardless of current theme setting)
  117. static SeasonalTheme get autoDetectedSeason {
  118. return _detectCurrentSeason();
  119. }
  120. /// Get the current theme's color scheme
  121. static SeasonalColors get colors {
  122. final theme = effectiveTheme;
  123. switch (theme) {
  124. case SeasonalTheme.spring:
  125. return _springColors;
  126. case SeasonalTheme.summer:
  127. return _summerColors;
  128. case SeasonalTheme.autumn:
  129. return _autumnColors;
  130. case SeasonalTheme.winter:
  131. return _winterColors;
  132. case SeasonalTheme.default_:
  133. return _defaultColors;
  134. case SeasonalTheme.automatic:
  135. // This should never happen since effectiveTheme resolves it
  136. return _detectCurrentSeason() == SeasonalTheme.spring
  137. ? _springColors
  138. : _detectCurrentSeason() == SeasonalTheme.summer
  139. ? _summerColors
  140. : _detectCurrentSeason() == SeasonalTheme.autumn
  141. ? _autumnColors
  142. : _winterColors;
  143. }
  144. }
  145. /// Get theme display name
  146. static String getThemeDisplayName(SeasonalTheme theme) {
  147. switch (theme) {
  148. case SeasonalTheme.automatic:
  149. return 'Automatic';
  150. case SeasonalTheme.default_:
  151. return 'Default (fSociety)';
  152. case SeasonalTheme.spring:
  153. return 'Spring Bloom';
  154. case SeasonalTheme.summer:
  155. return 'Summer Bright';
  156. case SeasonalTheme.autumn:
  157. return 'Autumn Leaves';
  158. case SeasonalTheme.winter:
  159. return 'Winter Frost';
  160. }
  161. }
  162. /// Get theme icon
  163. static IconData getThemeIcon(SeasonalTheme theme) {
  164. switch (theme) {
  165. case SeasonalTheme.automatic:
  166. return Icons.auto_mode;
  167. case SeasonalTheme.default_:
  168. return Icons.contrast;
  169. case SeasonalTheme.spring:
  170. return Icons.local_florist;
  171. case SeasonalTheme.summer:
  172. return Icons.wb_sunny;
  173. case SeasonalTheme.autumn:
  174. return Icons.park;
  175. case SeasonalTheme.winter:
  176. return Icons.ac_unit;
  177. }
  178. }
  179. /// Get available themes for selection (excluding default in release mode)
  180. static List<SeasonalTheme> get availableThemes {
  181. return SeasonalTheme.values.where((theme) {
  182. // Hide default theme in release builds
  183. if (!kDebugMode && theme == SeasonalTheme.default_) {
  184. return false;
  185. }
  186. return true;
  187. }).toList();
  188. }
  189. /// Default fSociety theme (current colors)
  190. static const SeasonalColors _defaultColors = SeasonalColors(
  191. appBackground: Color(0xFF000000),
  192. secondaryBackground: Color(0xFF0A0A0A),
  193. primaryText: Color(0xFFFFFFFF),
  194. secondaryText: Color(0xDEFFFFFF),
  195. mutedText: Color(0xFF808080),
  196. buttonBackground: Color(0xFF0BC2F9),
  197. buttonText: Color(0xFFFFFFFF),
  198. uiElements: Color(0xFF808080),
  199. gameBoardBorder: Color(0xFF808080),
  200. bubbleDefault: Color(0xFF646CFF),
  201. bubblePopEffect: Color(0xFFFF0000),
  202. scoreText: Color(0xFFFFFFFF),
  203. timerText: Color(0xDEFFFFFF),
  204. links: Color(0xFF000080),
  205. linkHover: Color(0xFFFF0000),
  206. selectedMenuItem: Color(0xFFFFFFFF),
  207. animationLayer1: [Color(0x33808080), Colors.transparent],
  208. animationLayer2: [Color(0x1AFF0000), Colors.transparent],
  209. animationLayer3: [Color(0x0D0BC2F9), Colors.transparent],
  210. zenModeColors: [Color(0x4D000080), Colors.transparent],
  211. );
  212. /// Spring theme - Fresh greens and soft pastels
  213. static const SeasonalColors _springColors = SeasonalColors(
  214. appBackground: Color(0xFF0A1A0A), // Dark forest green
  215. secondaryBackground: Color(0xFF1A2A1A),
  216. primaryText: Color(0xFFE8F5E8), // Light mint
  217. secondaryText: Color(0xDEE8F5E8),
  218. mutedText: Color(0xFF7FB069), // Soft green
  219. buttonBackground: Color(0xFF8FBC8F), // Dark sea green
  220. buttonText: Color(0xFF0A1A0A),
  221. uiElements: Color(0xFF556B2F), // Dark olive green
  222. gameBoardBorder: Color(0xFF6B8E23),
  223. bubbleDefault: Color(0xFF98FB98), // Pale green
  224. bubblePopEffect: Color(0xFFFFB6C1), // Light pink
  225. scoreText: Color(0xFFE8F5E8),
  226. timerText: Color(0xDEE8F5E8),
  227. links: Color(0xFF228B22), // Forest green
  228. linkHover: Color(0xFFFF69B4), // Hot pink
  229. selectedMenuItem: Color(0xFFE8F5E8),
  230. animationLayer1: [Color(0x3398FB98), Colors.transparent], // Pale green
  231. animationLayer2: [Color(0x1AFFB6C1), Colors.transparent], // Light pink
  232. animationLayer3: [Color(0x0D7FB069), Colors.transparent], // Soft green
  233. zenModeColors: [Color(0x4D228B22), Colors.transparent], // Forest green
  234. );
  235. /// Summer theme - Bright blues and warm yellows
  236. static const SeasonalColors _summerColors = SeasonalColors(
  237. appBackground: Color(0xFF0A0A2A), // Deep navy
  238. secondaryBackground: Color(0xFF1A1A3A),
  239. primaryText: Color(0xFFF0F8FF), // Alice blue
  240. secondaryText: Color(0xDEF0F8FF),
  241. mutedText: Color(0xFF87CEEB), // Sky blue
  242. buttonBackground: Color(0xFFFFD700), // Gold
  243. buttonText: Color(0xFF0A0A2A),
  244. uiElements: Color(0xFF4682B4), // Steel blue
  245. gameBoardBorder: Color(0xFF5F9EA0),
  246. bubbleDefault: Color(0xFF00BFFF), // Deep sky blue
  247. bubblePopEffect: Color(0xFFFF6347), // Tomato
  248. scoreText: Color(0xFFF0F8FF),
  249. timerText: Color(0xDEF0F8FF),
  250. links: Color(0xFF1E90FF), // Dodger blue
  251. linkHover: Color(0xFFFF4500), // Orange red
  252. selectedMenuItem: Color(0xFFF0F8FF),
  253. animationLayer1: [Color(0x33FFD700), Colors.transparent], // Gold
  254. animationLayer2: [Color(0x1AFFFF00), Colors.transparent], // Yellow
  255. animationLayer3: [Color(0x0DFFA500), Colors.transparent], // Orange
  256. zenModeColors: [Color(0x4D1E90FF), Colors.transparent], // Dodger blue
  257. );
  258. /// Autumn theme - Warm oranges, reds, and browns
  259. static const SeasonalColors _autumnColors = SeasonalColors(
  260. appBackground: Color(0xFF2A1A0A), // Dark brown
  261. secondaryBackground: Color(0xFF3A2A1A),
  262. primaryText: Color(0xFFFFF8DC), // Cornsilk
  263. secondaryText: Color(0xDEFFF8DC),
  264. mutedText: Color(0xFFDEB887), // Burlywood
  265. buttonBackground: Color(0xFFD2691E), // Chocolate
  266. buttonText: Color(0xFFFFF8DC),
  267. uiElements: Color(0xFF8B4513), // Saddle brown
  268. gameBoardBorder: Color(0xFFA0522D),
  269. bubbleDefault: Color(0xFFFF7F50), // Coral
  270. bubblePopEffect: Color(0xFFDC143C), // Crimson
  271. scoreText: Color(0xFFFFF8DC),
  272. timerText: Color(0xDEFFF8DC),
  273. links: Color(0xFFB22222), // Fire brick
  274. linkHover: Color(0xFFFF4500), // Orange red
  275. selectedMenuItem: Color(0xFFFFF8DC),
  276. animationLayer1: [Color(0x33FF7F50), Colors.transparent], // Coral
  277. animationLayer2: [Color(0x1ADC143C), Colors.transparent], // Crimson
  278. animationLayer3: [Color(0x0DDEB887), Colors.transparent], // Burlywood
  279. zenModeColors: [Color(0x4DB22222), Colors.transparent], // Fire brick
  280. );
  281. /// Winter theme - Cool blues and icy whites
  282. static const SeasonalColors _winterColors = SeasonalColors(
  283. appBackground: Color(0xFF0A1A2A), // Dark slate blue
  284. secondaryBackground: Color(0xFF1A2A3A),
  285. primaryText: Color(0xFFF0F8FF), // Alice blue
  286. secondaryText: Color(0xDEF0F8FF),
  287. mutedText: Color(0xFFB0C4DE), // Light steel blue
  288. buttonBackground: Color(0xFF6495ED), // Cornflower blue
  289. buttonText: Color(0xFF0A1A2A),
  290. uiElements: Color(0xFF708090), // Slate gray
  291. gameBoardBorder: Color(0xFF778899),
  292. bubbleDefault: Color(0xFF87CEFA), // Light sky blue
  293. bubblePopEffect: Color(0xFFFFFFFF), // White
  294. scoreText: Color(0xFFF0F8FF),
  295. timerText: Color(0xDEF0F8FF),
  296. links: Color(0xFF4169E1), // Royal blue
  297. linkHover: Color(0xFF00CED1), // Dark turquoise
  298. selectedMenuItem: Color(0xFFF0F8FF),
  299. animationLayer1: [Color(0x3387CEFA), Colors.transparent], // Light sky blue
  300. animationLayer2: [Color(0x1AFFFFFF), Colors.transparent], // White
  301. animationLayer3: [
  302. Color(0x0DB0C4DE),
  303. Colors.transparent,
  304. ], // Light steel blue
  305. zenModeColors: [Color(0x4D4169E1), Colors.transparent], // Royal blue
  306. );
  307. }