alarm_page.dart 8.5 KB

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