|
@@ -1,4 +1,52 @@
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
+import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
|
+import 'package:intl/intl.dart';
|
|
|
|
+
|
|
|
|
+class AlarmModel {
|
|
|
|
+ final int id;
|
|
|
|
+ final TimeOfDay time;
|
|
|
|
+ final List<bool> days; // 7 days from Monday to Sunday
|
|
|
|
+ final String label;
|
|
|
|
+ bool isActive;
|
|
|
|
+
|
|
|
|
+ AlarmModel({
|
|
|
|
+ required this.id,
|
|
|
|
+ required this.time,
|
|
|
|
+ required this.days,
|
|
|
|
+ required this.label,
|
|
|
|
+ this.isActive = true,
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ String get timeString {
|
|
|
|
+ final hour = time.hour;
|
|
|
|
+ final minute = time.minute;
|
|
|
|
+ return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ String get repeatDaysString {
|
|
|
|
+ List<String> dayShortNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
|
|
+ List<String> activeDays = [];
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < 7; i++) {
|
|
|
|
+ if (days[i]) {
|
|
|
|
+ activeDays.add(dayShortNames[i]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (activeDays.isEmpty) {
|
|
|
|
+ return 'One time';
|
|
|
|
+ } else if (activeDays.length == 7) {
|
|
|
|
+ return 'Every day';
|
|
|
|
+ } else if (activeDays.length == 5 &&
|
|
|
|
+ days[0] && days[1] && days[2] && days[3] && days[4]) {
|
|
|
|
+ return 'Weekdays';
|
|
|
|
+ } else if (activeDays.length == 2 && days[5] && days[6]) {
|
|
|
|
+ return 'Weekends';
|
|
|
|
+ } else {
|
|
|
|
+ return activeDays.join(', ');
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
class AlarmPage extends StatefulWidget {
|
|
class AlarmPage extends StatefulWidget {
|
|
@override
|
|
@override
|
|
@@ -6,16 +54,229 @@ class AlarmPage extends StatefulWidget {
|
|
}
|
|
}
|
|
|
|
|
|
class _AlarmPageState extends State<AlarmPage> {
|
|
class _AlarmPageState extends State<AlarmPage> {
|
|
|
|
+ List<AlarmModel> _alarms = [];
|
|
|
|
+ int _nextId = 0;
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ void initState() {
|
|
|
|
+ super.initState();
|
|
|
|
+ // Add some sample alarms
|
|
|
|
+ _addAlarm(
|
|
|
|
+ TimeOfDay(hour: 8, minute: 0),
|
|
|
|
+ [true, true, true, true, true, false, false],
|
|
|
|
+ 'Wake up',
|
|
|
|
+ );
|
|
|
|
+ _addAlarm(
|
|
|
|
+ TimeOfDay(hour: 18, minute: 30),
|
|
|
|
+ [true, true, true, true, true, true, true],
|
|
|
|
+ 'Evening reminder',
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void _addAlarm(TimeOfDay time, List<bool> days, String label) {
|
|
|
|
+ setState(() {
|
|
|
|
+ _alarms.add(
|
|
|
|
+ AlarmModel(
|
|
|
|
+ id: _nextId++,
|
|
|
|
+ time: time,
|
|
|
|
+ days: days,
|
|
|
|
+ label: label,
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void _toggleAlarm(int id) {
|
|
|
|
+ setState(() {
|
|
|
|
+ for (int i = 0; i < _alarms.length; i++) {
|
|
|
|
+ if (_alarms[i].id == id) {
|
|
|
|
+ _alarms[i].isActive = !_alarms[i].isActive;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void _deleteAlarm(int id) {
|
|
|
|
+ setState(() {
|
|
|
|
+ _alarms.removeWhere((alarm) => alarm.id == id);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Future<void> _showAddAlarmDialog() async {
|
|
|
|
+ final TimeOfDay initialTime = TimeOfDay.now();
|
|
|
|
+ final List<bool> days = List.generate(7, (_) => false);
|
|
|
|
+ final TextEditingController labelController = TextEditingController();
|
|
|
|
+
|
|
|
|
+ await showDialog(
|
|
|
|
+ context: context,
|
|
|
|
+ builder: (BuildContext context) {
|
|
|
|
+ TimeOfDay selectedTime = initialTime;
|
|
|
|
+
|
|
|
|
+ return StatefulBuilder(
|
|
|
|
+ builder: (context, setState) {
|
|
|
|
+ return AlertDialog(
|
|
|
|
+ title: Text('Add Alarm'),
|
|
|
|
+ content: SingleChildScrollView(
|
|
|
|
+ child: Column(
|
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
|
+ children: [
|
|
|
|
+ // Time picker button
|
|
|
|
+ ListTile(
|
|
|
|
+ title: Text('Time'),
|
|
|
|
+ subtitle: Text(
|
|
|
|
+ '${selectedTime.hour.toString().padLeft(2, '0')}:${selectedTime.minute.toString().padLeft(2, '0')}',
|
|
|
|
+ style: TextStyle(fontSize: 24.sp),
|
|
|
|
+ ),
|
|
|
|
+ onTap: () async {
|
|
|
|
+ final TimeOfDay? picked = await showTimePicker(
|
|
|
|
+ context: context,
|
|
|
|
+ initialTime: selectedTime,
|
|
|
|
+ );
|
|
|
|
+ if (picked != null) {
|
|
|
|
+ setState(() {
|
|
|
|
+ selectedTime = picked;
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ ),
|
|
|
|
+ SizedBox(height: 10.h),
|
|
|
|
+ // Repeat days
|
|
|
|
+ Text('Repeat', style: TextStyle(fontWeight: FontWeight.bold)),
|
|
|
|
+ _buildWeekdaySelector(days, setState),
|
|
|
|
+ SizedBox(height: 10.h),
|
|
|
|
+ // Label
|
|
|
|
+ TextField(
|
|
|
|
+ controller: labelController,
|
|
|
|
+ decoration: InputDecoration(
|
|
|
|
+ labelText: 'Label',
|
|
|
|
+ border: OutlineInputBorder(),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ actions: [
|
|
|
|
+ TextButton(
|
|
|
|
+ onPressed: () => Navigator.of(context).pop(),
|
|
|
|
+ child: Text('Cancel'),
|
|
|
|
+ ),
|
|
|
|
+ TextButton(
|
|
|
|
+ onPressed: () {
|
|
|
|
+ _addAlarm(
|
|
|
|
+ selectedTime,
|
|
|
|
+ List.from(days),
|
|
|
|
+ labelController.text.isNotEmpty
|
|
|
|
+ ? labelController.text
|
|
|
|
+ : 'Alarm',
|
|
|
|
+ );
|
|
|
|
+ Navigator.of(context).pop();
|
|
|
|
+ },
|
|
|
|
+ child: Text('Save'),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Widget _buildWeekdaySelector(List<bool> days, StateSetter setState) {
|
|
|
|
+ List<String> dayShortNames = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
|
|
|
|
+ return Row(
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
+ children: List.generate(7, (index) {
|
|
|
|
+ return InkWell(
|
|
|
|
+ onTap: () {
|
|
|
|
+ setState(() {
|
|
|
|
+ days[index] = !days[index];
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ child: CircleAvatar(
|
|
|
|
+ radius: 18.r,
|
|
|
|
+ backgroundColor: days[index] ? Colors.blue : Colors.grey[300],
|
|
|
|
+ child: Text(
|
|
|
|
+ dayShortNames[index],
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ color: days[index] ? Colors.white : Colors.black87,
|
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ }),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
return Scaffold(
|
|
backgroundColor: Colors.white,
|
|
backgroundColor: Colors.white,
|
|
- body: Center(
|
|
|
|
- child: Text(
|
|
|
|
- 'Alarm Feature Coming Soon',
|
|
|
|
- style: TextStyle(fontSize: 20),
|
|
|
|
- ),
|
|
|
|
|
|
+ floatingActionButton: FloatingActionButton(
|
|
|
|
+ onPressed: _showAddAlarmDialog,
|
|
|
|
+ child: Icon(Icons.add),
|
|
|
|
+ tooltip: 'Add Alarm',
|
|
),
|
|
),
|
|
|
|
+ body: _alarms.isEmpty
|
|
|
|
+ ? Center(
|
|
|
|
+ child: Text(
|
|
|
|
+ 'No alarms set',
|
|
|
|
+ style: TextStyle(fontSize: 18.sp, color: Colors.grey),
|
|
|
|
+ ),
|
|
|
|
+ )
|
|
|
|
+ : ListView.builder(
|
|
|
|
+ itemCount: _alarms.length,
|
|
|
|
+ itemBuilder: (context, index) {
|
|
|
|
+ final alarm = _alarms[index];
|
|
|
|
+ return Card(
|
|
|
|
+ margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
|
|
|
|
+ child: ListTile(
|
|
|
|
+ title: Text(
|
|
|
|
+ alarm.timeString,
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 24.sp,
|
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
|
+ color: alarm.isActive ? Colors.black : Colors.grey,
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ subtitle: Column(
|
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
+ children: [
|
|
|
|
+ Text(
|
|
|
|
+ alarm.repeatDaysString,
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 14.sp,
|
|
|
|
+ color: alarm.isActive ? Colors.black87 : Colors.grey,
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ Text(
|
|
|
|
+ alarm.label,
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 16.sp,
|
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
|
+ color: alarm.isActive ? Colors.black87 : Colors.grey,
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ trailing: Row(
|
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
|
+ children: [
|
|
|
|
+ Switch(
|
|
|
|
+ value: alarm.isActive,
|
|
|
|
+ onChanged: (_) => _toggleAlarm(alarm.id),
|
|
|
|
+ ),
|
|
|
|
+ IconButton(
|
|
|
|
+ icon: Icon(Icons.delete, color: Colors.red),
|
|
|
|
+ onPressed: () => _deleteAlarm(alarm.id),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ ),
|
|
);
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|