settings_screen.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. import 'package:flutter/material.dart';
  2. import 'package:vibration/vibration.dart';
  3. import '../utils/colors.dart';
  4. import '../utils/settings_manager.dart';
  5. import 'components/animated_background.dart';
  6. class SettingsScreen extends StatefulWidget {
  7. const SettingsScreen({super.key});
  8. @override
  9. State<SettingsScreen> createState() => _SettingsScreenState();
  10. }
  11. class _SettingsScreenState extends State<SettingsScreen> {
  12. bool _musicEnabled = true;
  13. bool _hapticsEnabled = true;
  14. @override
  15. void initState() {
  16. super.initState();
  17. _loadSettings();
  18. }
  19. Future<void> _loadSettings() async {
  20. setState(() {
  21. _musicEnabled = SettingsManager.isMusicEnabled;
  22. _hapticsEnabled = SettingsManager.isHapticsEnabled;
  23. });
  24. }
  25. @override
  26. Widget build(BuildContext context) {
  27. return Scaffold(
  28. backgroundColor: ZenColors.appBackground,
  29. body: AnimatedBackground(
  30. child: SafeArea(
  31. child: Column(
  32. children: [
  33. // Header
  34. Padding(
  35. padding: const EdgeInsets.all(16.0),
  36. child: Row(
  37. children: [
  38. IconButton(
  39. onPressed: () => Navigator.of(context).pop(),
  40. icon: const Icon(
  41. Icons.arrow_back,
  42. color: ZenColors.primaryText,
  43. size: 28,
  44. ),
  45. style: IconButton.styleFrom(
  46. backgroundColor: ZenColors.black.withOpacity(0.3),
  47. shape: const CircleBorder(),
  48. ),
  49. ),
  50. const SizedBox(width: 16),
  51. const Text(
  52. 'Settings',
  53. style: TextStyle(
  54. color: ZenColors.primaryText,
  55. fontSize: 28,
  56. fontWeight: FontWeight.bold,
  57. letterSpacing: 1.0,
  58. ),
  59. ),
  60. ],
  61. ),
  62. ),
  63. // Settings List
  64. Expanded(
  65. child: Padding(
  66. padding: const EdgeInsets.symmetric(horizontal: 20.0),
  67. child: Column(
  68. children: [
  69. const SizedBox(height: 20),
  70. // Audio Section
  71. _buildSectionHeader('Audio'),
  72. _buildSettingTile(
  73. icon: Icons.music_note,
  74. title: 'Background Music',
  75. subtitle: 'Enable relaxing ambient sounds',
  76. value: _musicEnabled,
  77. onChanged: _toggleMusic,
  78. ),
  79. const SizedBox(height: 30),
  80. // Feedback Section
  81. _buildSectionHeader('Feedback'),
  82. _buildSettingTile(
  83. icon: Icons.vibration,
  84. title: 'Haptic Feedback',
  85. subtitle: 'Feel gentle vibrations on tap',
  86. value: _hapticsEnabled,
  87. onChanged: _toggleHaptics,
  88. ),
  89. const SizedBox(height: 30),
  90. // Tutorial Section
  91. _buildSectionHeader('Help'),
  92. _buildActionTile(
  93. icon: Icons.help_outline,
  94. title: 'Show Tutorial',
  95. subtitle: 'Learn how to use ZenTap',
  96. onTap: _showTutorial,
  97. ),
  98. const Spacer(),
  99. // About Section
  100. Padding(
  101. padding: const EdgeInsets.only(bottom: 20),
  102. child: Column(
  103. children: [
  104. Text(
  105. 'ZenTap v1.0.0',
  106. style: TextStyle(
  107. color: ZenColors.mutedText,
  108. fontSize: 14,
  109. ),
  110. ),
  111. const SizedBox(height: 8),
  112. Text(
  113. 'A stress relief tapping game',
  114. style: TextStyle(
  115. color: ZenColors.mutedText,
  116. fontSize: 12,
  117. fontStyle: FontStyle.italic,
  118. ),
  119. ),
  120. ],
  121. ),
  122. ),
  123. ],
  124. ),
  125. ),
  126. ),
  127. ],
  128. ),
  129. ),
  130. ),
  131. );
  132. }
  133. Widget _buildSectionHeader(String title) {
  134. return Align(
  135. alignment: Alignment.centerLeft,
  136. child: Text(
  137. title,
  138. style: TextStyle(
  139. color: ZenColors.secondaryText,
  140. fontSize: 16,
  141. fontWeight: FontWeight.w600,
  142. letterSpacing: 0.5,
  143. ),
  144. ),
  145. );
  146. }
  147. Widget _buildSettingTile({
  148. required IconData icon,
  149. required String title,
  150. required String subtitle,
  151. required bool value,
  152. required ValueChanged<bool> onChanged,
  153. }) {
  154. return Container(
  155. margin: const EdgeInsets.only(top: 12),
  156. padding: const EdgeInsets.all(16),
  157. decoration: BoxDecoration(
  158. color: ZenColors.uiElements.withOpacity(0.3),
  159. borderRadius: BorderRadius.circular(12),
  160. border: Border.all(
  161. color: ZenColors.uiElements.withOpacity(0.2),
  162. width: 1,
  163. ),
  164. ),
  165. child: Row(
  166. children: [
  167. Icon(
  168. icon,
  169. color: ZenColors.primaryText,
  170. size: 24,
  171. ),
  172. const SizedBox(width: 16),
  173. Expanded(
  174. child: Column(
  175. crossAxisAlignment: CrossAxisAlignment.start,
  176. children: [
  177. Text(
  178. title,
  179. style: const TextStyle(
  180. color: ZenColors.primaryText,
  181. fontSize: 16,
  182. fontWeight: FontWeight.w500,
  183. ),
  184. ),
  185. const SizedBox(height: 2),
  186. Text(
  187. subtitle,
  188. style: TextStyle(
  189. color: ZenColors.secondaryText,
  190. fontSize: 13,
  191. ),
  192. ),
  193. ],
  194. ),
  195. ),
  196. Switch(
  197. value: value,
  198. onChanged: onChanged,
  199. activeColor: ZenColors.buttonBackground,
  200. activeTrackColor: ZenColors.buttonBackground.withOpacity(0.3),
  201. inactiveThumbColor: ZenColors.mutedText,
  202. inactiveTrackColor: ZenColors.mutedText.withOpacity(0.2),
  203. ),
  204. ],
  205. ),
  206. );
  207. }
  208. Widget _buildActionTile({
  209. required IconData icon,
  210. required String title,
  211. required String subtitle,
  212. required VoidCallback onTap,
  213. }) {
  214. return Container(
  215. margin: const EdgeInsets.only(top: 12),
  216. child: Material(
  217. color: ZenColors.uiElements.withOpacity(0.3),
  218. borderRadius: BorderRadius.circular(12),
  219. child: InkWell(
  220. onTap: onTap,
  221. borderRadius: BorderRadius.circular(12),
  222. child: Container(
  223. padding: const EdgeInsets.all(16),
  224. decoration: BoxDecoration(
  225. borderRadius: BorderRadius.circular(12),
  226. border: Border.all(
  227. color: ZenColors.uiElements.withOpacity(0.2),
  228. width: 1,
  229. ),
  230. ),
  231. child: Row(
  232. children: [
  233. Icon(
  234. icon,
  235. color: ZenColors.primaryText,
  236. size: 24,
  237. ),
  238. const SizedBox(width: 16),
  239. Expanded(
  240. child: Column(
  241. crossAxisAlignment: CrossAxisAlignment.start,
  242. children: [
  243. Text(
  244. title,
  245. style: const TextStyle(
  246. color: ZenColors.primaryText,
  247. fontSize: 16,
  248. fontWeight: FontWeight.w500,
  249. ),
  250. ),
  251. const SizedBox(height: 2),
  252. Text(
  253. subtitle,
  254. style: TextStyle(
  255. color: ZenColors.secondaryText,
  256. fontSize: 13,
  257. ),
  258. ),
  259. ],
  260. ),
  261. ),
  262. Icon(
  263. Icons.arrow_forward_ios,
  264. color: ZenColors.mutedText,
  265. size: 16,
  266. ),
  267. ],
  268. ),
  269. ),
  270. ),
  271. ),
  272. );
  273. }
  274. Future<void> _toggleMusic(bool value) async {
  275. setState(() {
  276. _musicEnabled = value;
  277. });
  278. await SettingsManager.setMusicEnabled(value);
  279. if (_hapticsEnabled) {
  280. try {
  281. await Vibration.vibrate(duration: 50);
  282. } catch (e) {
  283. // Vibration not supported on this platform
  284. }
  285. }
  286. }
  287. Future<void> _toggleHaptics(bool value) async {
  288. setState(() {
  289. _hapticsEnabled = value;
  290. });
  291. await SettingsManager.setHapticsEnabled(value);
  292. // Give immediate feedback if enabling haptics
  293. if (value) {
  294. try {
  295. await Vibration.vibrate(duration: 100);
  296. } catch (e) {
  297. // Vibration not supported on this platform
  298. }
  299. }
  300. }
  301. void _showTutorial() {
  302. if (_hapticsEnabled) {
  303. try {
  304. Vibration.vibrate(duration: 50);
  305. } catch (e) {
  306. // Vibration not supported on this platform
  307. }
  308. }
  309. showDialog(
  310. context: context,
  311. builder: (context) => _buildTutorialDialog(),
  312. );
  313. }
  314. Widget _buildTutorialDialog() {
  315. return AlertDialog(
  316. backgroundColor: ZenColors.uiElements,
  317. shape: RoundedRectangleBorder(
  318. borderRadius: BorderRadius.circular(20),
  319. ),
  320. title: const Text(
  321. 'How to Use ZenTap',
  322. style: TextStyle(
  323. color: ZenColors.primaryText,
  324. fontSize: 22,
  325. fontWeight: FontWeight.bold,
  326. ),
  327. ),
  328. content: Column(
  329. mainAxisSize: MainAxisSize.min,
  330. crossAxisAlignment: CrossAxisAlignment.start,
  331. children: [
  332. _buildTutorialStep(
  333. icon: Icons.touch_app,
  334. text: 'Tap anywhere on the screen to pop bubbles',
  335. ),
  336. const SizedBox(height: 16),
  337. _buildTutorialStep(
  338. icon: Icons.stars,
  339. text: 'Earn Relaxation Points in Play mode',
  340. ),
  341. const SizedBox(height: 16),
  342. _buildTutorialStep(
  343. icon: Icons.self_improvement,
  344. text: 'Choose Zen Mode for pure relaxation',
  345. ),
  346. const SizedBox(height: 16),
  347. _buildTutorialStep(
  348. icon: Icons.pause,
  349. text: 'Tap pause anytime to take a break',
  350. ),
  351. ],
  352. ),
  353. actions: [
  354. ElevatedButton(
  355. onPressed: () => Navigator.of(context).pop(),
  356. style: ElevatedButton.styleFrom(
  357. backgroundColor: ZenColors.buttonBackground,
  358. foregroundColor: ZenColors.buttonText,
  359. shape: RoundedRectangleBorder(
  360. borderRadius: BorderRadius.circular(12),
  361. ),
  362. ),
  363. child: const Text('Got it!'),
  364. ),
  365. ],
  366. );
  367. }
  368. Widget _buildTutorialStep({
  369. required IconData icon,
  370. required String text,
  371. }) {
  372. return Row(
  373. children: [
  374. Icon(
  375. icon,
  376. color: ZenColors.buttonBackground,
  377. size: 20,
  378. ),
  379. const SizedBox(width: 12),
  380. Expanded(
  381. child: Text(
  382. text,
  383. style: TextStyle(
  384. color: ZenColors.secondaryText,
  385. fontSize: 14,
  386. ),
  387. ),
  388. ),
  389. ],
  390. );
  391. }
  392. }