alarm_page.dart 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. class AlarmModel {
  4. final int id;
  5. final TimeOfDay time;
  6. final List<bool> days; // 7 days from Monday to Sunday
  7. final String label;
  8. bool isActive;
  9. AlarmModel({
  10. required this.id,
  11. required this.time,
  12. required this.days,
  13. required this.label,
  14. this.isActive = true,
  15. });
  16. String get timeString {
  17. final hour = time.hour;
  18. final minute = time.minute;
  19. return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}';
  20. }
  21. String get repeatDaysString {
  22. List<String> dayShortNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
  23. List<String> activeDays = [];
  24. for (int i = 0; i < 7; i++) {
  25. if (days[i]) {
  26. activeDays.add(dayShortNames[i]);
  27. }
  28. }
  29. if (activeDays.isEmpty) {
  30. return 'One time';
  31. } else if (activeDays.length == 7) {
  32. return 'Every day';
  33. } else if (activeDays.length == 5 &&
  34. days[0] && days[1] && days[2] && days[3] && days[4]) {
  35. return 'Weekdays';
  36. } else if (activeDays.length == 2 && days[5] && days[6]) {
  37. return 'Weekends';
  38. } else {
  39. return activeDays.join(', ');
  40. }
  41. }
  42. }
  43. class AlarmPage extends StatefulWidget {
  44. @override
  45. State<AlarmPage> createState() => _AlarmPageState();
  46. }
  47. class _AlarmPageState extends State<AlarmPage> {
  48. List<AlarmModel> _alarms = [];
  49. int _nextId = 0;
  50. @override
  51. void initState() {
  52. super.initState();
  53. // Add some sample alarms
  54. _addAlarm(
  55. TimeOfDay(hour: 8, minute: 0),
  56. [true, true, true, true, true, false, false],
  57. 'Wake up',
  58. );
  59. _addAlarm(
  60. TimeOfDay(hour: 18, minute: 30),
  61. [true, true, true, true, true, true, true],
  62. 'Evening reminder',
  63. );
  64. }
  65. void _addAlarm(TimeOfDay time, List<bool> days, String label) {
  66. setState(() {
  67. _alarms.add(
  68. AlarmModel(
  69. id: _nextId++,
  70. time: time,
  71. days: days,
  72. label: label,
  73. ),
  74. );
  75. });
  76. }
  77. void _toggleAlarm(int id) {
  78. setState(() {
  79. for (int i = 0; i < _alarms.length; i++) {
  80. if (_alarms[i].id == id) {
  81. _alarms[i].isActive = !_alarms[i].isActive;
  82. break;
  83. }
  84. }
  85. });
  86. }
  87. void _deleteAlarm(int id) {
  88. setState(() {
  89. _alarms.removeWhere((alarm) => alarm.id == id);
  90. });
  91. }
  92. Future<void> _showAddAlarmDialog() async {
  93. final TimeOfDay initialTime = TimeOfDay.now();
  94. final List<bool> days = List.generate(7, (_) => false);
  95. final TextEditingController labelController = TextEditingController();
  96. await showDialog(
  97. context: context,
  98. builder: (BuildContext context) {
  99. TimeOfDay selectedTime = initialTime;
  100. return StatefulBuilder(
  101. builder: (context, setState) {
  102. return AlertDialog(
  103. title: Text('Add Alarm'),
  104. content: SingleChildScrollView(
  105. child: Column(
  106. mainAxisSize: MainAxisSize.min,
  107. children: [
  108. // Time picker button
  109. ListTile(
  110. title: Text('Time'),
  111. subtitle: Text(
  112. '${selectedTime.hour.toString().padLeft(2, '0')}:${selectedTime.minute.toString().padLeft(2, '0')}',
  113. style: TextStyle(fontSize: 24.sp),
  114. ),
  115. onTap: () async {
  116. final TimeOfDay? picked = await showTimePicker(
  117. context: context,
  118. initialTime: selectedTime,
  119. );
  120. if (picked != null) {
  121. setState(() {
  122. selectedTime = picked;
  123. });
  124. }
  125. },
  126. ),
  127. SizedBox(height: 10.h),
  128. // Repeat days
  129. Text('Repeat', style: TextStyle(fontWeight: FontWeight.bold)),
  130. _buildWeekdaySelector(days, setState),
  131. SizedBox(height: 10.h),
  132. // Label
  133. TextField(
  134. controller: labelController,
  135. decoration: InputDecoration(
  136. labelText: 'Label',
  137. border: OutlineInputBorder(),
  138. ),
  139. ),
  140. ],
  141. ),
  142. ),
  143. actions: [
  144. TextButton(
  145. onPressed: () => Navigator.of(context).pop(),
  146. child: Text('Cancel'),
  147. ),
  148. TextButton(
  149. onPressed: () {
  150. _addAlarm(
  151. selectedTime,
  152. List.from(days),
  153. labelController.text.isNotEmpty
  154. ? labelController.text
  155. : 'Alarm',
  156. );
  157. Navigator.of(context).pop();
  158. },
  159. child: Text('Save'),
  160. ),
  161. ],
  162. );
  163. },
  164. );
  165. },
  166. );
  167. }
  168. Widget _buildWeekdaySelector(List<bool> days, StateSetter setState) {
  169. List<String> dayShortNames = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
  170. return Row(
  171. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  172. children: List.generate(7, (index) {
  173. return InkWell(
  174. onTap: () {
  175. setState(() {
  176. days[index] = !days[index];
  177. });
  178. },
  179. child: CircleAvatar(
  180. radius: 18.r,
  181. backgroundColor: days[index] ? Colors.blue : Colors.grey[300],
  182. child: Text(
  183. dayShortNames[index],
  184. style: TextStyle(
  185. color: days[index] ? Colors.white : Colors.black87,
  186. fontWeight: FontWeight.bold,
  187. ),
  188. ),
  189. ),
  190. );
  191. }),
  192. );
  193. }
  194. @override
  195. Widget build(BuildContext context) {
  196. return Scaffold(
  197. backgroundColor: Colors.white,
  198. floatingActionButton: FloatingActionButton(
  199. onPressed: _showAddAlarmDialog,
  200. child: Icon(Icons.add),
  201. tooltip: 'Add Alarm',
  202. ),
  203. body: _alarms.isEmpty
  204. ? Center(
  205. child: Text(
  206. 'No alarms set',
  207. style: TextStyle(fontSize: 18.sp, color: Colors.grey),
  208. ),
  209. )
  210. : ListView.builder(
  211. itemCount: _alarms.length,
  212. itemBuilder: (context, index) {
  213. final alarm = _alarms[index];
  214. return Card(
  215. margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
  216. child: ListTile(
  217. title: Text(
  218. alarm.timeString,
  219. style: TextStyle(
  220. fontSize: 24.sp,
  221. fontWeight: FontWeight.bold,
  222. color: alarm.isActive ? Colors.black : Colors.grey,
  223. ),
  224. ),
  225. subtitle: Column(
  226. crossAxisAlignment: CrossAxisAlignment.start,
  227. children: [
  228. Text(
  229. alarm.repeatDaysString,
  230. style: TextStyle(
  231. fontSize: 14.sp,
  232. color: alarm.isActive ? Colors.black87 : Colors.grey,
  233. ),
  234. ),
  235. Text(
  236. alarm.label,
  237. style: TextStyle(
  238. fontSize: 16.sp,
  239. fontWeight: FontWeight.w500,
  240. color: alarm.isActive ? Colors.black87 : Colors.grey,
  241. ),
  242. ),
  243. ],
  244. ),
  245. trailing: Row(
  246. mainAxisSize: MainAxisSize.min,
  247. children: [
  248. Switch(
  249. value: alarm.isActive,
  250. onChanged: (_) => _toggleAlarm(alarm.id),
  251. ),
  252. IconButton(
  253. icon: Icon(Icons.delete, color: Colors.red),
  254. onPressed: () => _deleteAlarm(alarm.id),
  255. ),
  256. ],
  257. ),
  258. ),
  259. );
  260. },
  261. ),
  262. );
  263. }
  264. }