From 55e1907ba86128794863f4a4a24987d7daba1bcf Mon Sep 17 00:00:00 2001 From: mahendra-918 Date: Sun, 13 Apr 2025 07:45:59 +0530 Subject: [PATCH 1/2] completed --- lib/app/data/models/alarm_model.dart | 22 +- lib/app/data/models/alarm_model.g.dart | 423 +++++++++++++---- lib/app/data/models/profile_model.dart | 21 +- lib/app/data/models/task_model.dart | 39 ++ .../add_or_update_alarm_controller.dart | 47 +- .../controllers/input_time_controller.dart | 33 +- .../views/add_or_update_alarm_view.dart | 25 +- .../views/guardian_angel.dart | 2 +- .../views/task_list_editor_page.dart | 237 ++++++++++ .../views/task_list_tile.dart | 148 ++++++ .../controllers/alarm_ring_controller.dart | 39 ++ .../alarmRing/views/alarm_ring_view.dart | 447 ++++++++++++------ lib/app/utils/utils.dart | 2 + 13 files changed, 1222 insertions(+), 263 deletions(-) create mode 100644 lib/app/data/models/task_model.dart create mode 100644 lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart create mode 100644 lib/app/modules/addOrUpdateAlarm/views/task_list_tile.dart diff --git a/lib/app/data/models/alarm_model.dart b/lib/app/data/models/alarm_model.dart index 4bd43aad..c77b479c 100644 --- a/lib/app/data/models/alarm_model.dart +++ b/lib/app/data/models/alarm_model.dart @@ -59,6 +59,8 @@ class AlarmModel { late int guardianTimer; late String guardian; late bool isCall; + late bool isTaskListEnabled; + late String serializedTaskList; @ignore Map? offsetDetails; @@ -109,7 +111,9 @@ class AlarmModel { required this.isGuardian, required this.guardianTimer, required this.guardian, - required this.isCall}); + required this.isCall, + this.isTaskListEnabled = false, + this.serializedTaskList = '[]'}); AlarmModel.fromDocumentSnapshot({ required firestore.DocumentSnapshot documentSnapshot, @@ -179,6 +183,10 @@ class AlarmModel { guardianTimer = documentSnapshot['guardianTimer']; guardian = documentSnapshot['guardian']; isCall = documentSnapshot['isCall']; + + // Task list fields with default values if they don't exist + isTaskListEnabled = documentSnapshot['isTaskListEnabled'] ?? false; + serializedTaskList = documentSnapshot['serializedTaskList'] ?? '[]'; } AlarmModel fromMapSQFlite(Map map) { @@ -231,6 +239,8 @@ class AlarmModel { guardian: map['guardian'], isCall: map['isCall'] == 1, ringOn: map['ringOn'] == 1, + isTaskListEnabled: map['isTaskListEnabled'] == 1, + serializedTaskList: map['serializedTaskList'] ?? '[]', ); } @@ -283,6 +293,8 @@ class AlarmModel { 'guardianTimer': guardianTimer, 'guardian': guardian, 'isCall': isCall ? 1 : 0, + 'isTaskListEnabled': isTaskListEnabled ? 1 : 0, + 'serializedTaskList': serializedTaskList, }; } @@ -338,6 +350,10 @@ class AlarmModel { guardian = alarmData['guardian']; isCall = alarmData['isCall']; ringOn = alarmData['ringOn']; + + // Task list fields with defaults if they don't exist + isTaskListEnabled = alarmData['isTaskListEnabled'] ?? false; + serializedTaskList = alarmData['serializedTaskList'] ?? '[]'; } AlarmModel.fromJson(String alarmData, UserModel? user) { @@ -395,7 +411,9 @@ class AlarmModel { 'guardianTimer': alarmRecord.guardianTimer, 'guardian': alarmRecord.guardian, 'isCall': alarmRecord.isCall, - 'ringOn': alarmRecord.ringOn + 'ringOn': alarmRecord.ringOn, + 'isTaskListEnabled': alarmRecord.isTaskListEnabled, + 'serializedTaskList': alarmRecord.serializedTaskList }; if (alarmRecord.isSharedAlarmEnabled) { diff --git a/lib/app/data/models/alarm_model.g.dart b/lib/app/data/models/alarm_model.g.dart index 4f95ab4a..28f9c1d5 100644 --- a/lib/app/data/models/alarm_model.g.dart +++ b/lib/app/data/models/alarm_model.g.dart @@ -132,123 +132,133 @@ const AlarmModelSchema = CollectionSchema( name: r'isSharedAlarmEnabled', type: IsarType.bool, ), - r'isWeatherEnabled': PropertySchema( + r'isTaskListEnabled': PropertySchema( id: 23, + name: r'isTaskListEnabled', + type: IsarType.bool, + ), + r'isWeatherEnabled': PropertySchema( + id: 24, name: r'isWeatherEnabled', type: IsarType.bool, ), r'label': PropertySchema( - id: 24, + id: 25, name: r'label', type: IsarType.string, ), r'lastEditedUserId': PropertySchema( - id: 25, + id: 26, name: r'lastEditedUserId', type: IsarType.string, ), r'location': PropertySchema( - id: 26, + id: 27, name: r'location', type: IsarType.string, ), r'mainAlarmTime': PropertySchema( - id: 27, + id: 28, name: r'mainAlarmTime', type: IsarType.string, ), r'mathsDifficulty': PropertySchema( - id: 28, + id: 29, name: r'mathsDifficulty', type: IsarType.long, ), r'minutesSinceMidnight': PropertySchema( - id: 29, + id: 30, name: r'minutesSinceMidnight', type: IsarType.long, ), r'mutexLock': PropertySchema( - id: 30, + id: 31, name: r'mutexLock', type: IsarType.bool, ), r'note': PropertySchema( - id: 31, + id: 32, name: r'note', type: IsarType.string, ), r'numMathsQuestions': PropertySchema( - id: 32, + id: 33, name: r'numMathsQuestions', type: IsarType.long, ), r'numberOfSteps': PropertySchema( - id: 33, + id: 34, name: r'numberOfSteps', type: IsarType.long, ), r'ownerId': PropertySchema( - id: 34, + id: 35, name: r'ownerId', type: IsarType.string, ), r'ownerName': PropertySchema( - id: 35, + id: 36, name: r'ownerName', type: IsarType.string, ), r'profile': PropertySchema( - id: 36, + id: 37, name: r'profile', type: IsarType.string, ), r'qrValue': PropertySchema( - id: 37, + id: 38, name: r'qrValue', type: IsarType.string, ), r'ringOn': PropertySchema( - id: 38, + id: 39, name: r'ringOn', type: IsarType.bool, ), r'ringtoneName': PropertySchema( - id: 39, + id: 40, name: r'ringtoneName', type: IsarType.string, ), + r'serializedTaskList': PropertySchema( + id: 41, + name: r'serializedTaskList', + type: IsarType.string, + ), r'shakeTimes': PropertySchema( - id: 40, + id: 42, name: r'shakeTimes', type: IsarType.long, ), r'sharedUserIds': PropertySchema( - id: 41, + id: 43, name: r'sharedUserIds', type: IsarType.stringList, ), r'showMotivationalQuote': PropertySchema( - id: 42, + id: 44, name: r'showMotivationalQuote', type: IsarType.bool, ), r'snoozeDuration': PropertySchema( - id: 43, + id: 45, name: r'snoozeDuration', type: IsarType.long, ), r'volMax': PropertySchema( - id: 44, + id: 46, name: r'volMax', type: IsarType.double, ), r'volMin': PropertySchema( - id: 45, + id: 47, name: r'volMin', type: IsarType.double, ), r'weatherTypes': PropertySchema( - id: 46, + id: 48, name: r'weatherTypes', type: IsarType.longList, ) @@ -299,6 +309,7 @@ int _alarmModelEstimateSize( bytesCount += 3 + object.profile.length * 3; bytesCount += 3 + object.qrValue.length * 3; bytesCount += 3 + object.ringtoneName.length * 3; + bytesCount += 3 + object.serializedTaskList.length * 3; { final list = object.sharedUserIds; if (list != null) { @@ -344,30 +355,32 @@ void _alarmModelSerialize( writer.writeBool(offsets[20], object.isQrEnabled); writer.writeBool(offsets[21], object.isShakeEnabled); writer.writeBool(offsets[22], object.isSharedAlarmEnabled); - writer.writeBool(offsets[23], object.isWeatherEnabled); - writer.writeString(offsets[24], object.label); - writer.writeString(offsets[25], object.lastEditedUserId); - writer.writeString(offsets[26], object.location); - writer.writeString(offsets[27], object.mainAlarmTime); - writer.writeLong(offsets[28], object.mathsDifficulty); - writer.writeLong(offsets[29], object.minutesSinceMidnight); - writer.writeBool(offsets[30], object.mutexLock); - writer.writeString(offsets[31], object.note); - writer.writeLong(offsets[32], object.numMathsQuestions); - writer.writeLong(offsets[33], object.numberOfSteps); - writer.writeString(offsets[34], object.ownerId); - writer.writeString(offsets[35], object.ownerName); - writer.writeString(offsets[36], object.profile); - writer.writeString(offsets[37], object.qrValue); - writer.writeBool(offsets[38], object.ringOn); - writer.writeString(offsets[39], object.ringtoneName); - writer.writeLong(offsets[40], object.shakeTimes); - writer.writeStringList(offsets[41], object.sharedUserIds); - writer.writeBool(offsets[42], object.showMotivationalQuote); - writer.writeLong(offsets[43], object.snoozeDuration); - writer.writeDouble(offsets[44], object.volMax); - writer.writeDouble(offsets[45], object.volMin); - writer.writeLongList(offsets[46], object.weatherTypes); + writer.writeBool(offsets[23], object.isTaskListEnabled); + writer.writeBool(offsets[24], object.isWeatherEnabled); + writer.writeString(offsets[25], object.label); + writer.writeString(offsets[26], object.lastEditedUserId); + writer.writeString(offsets[27], object.location); + writer.writeString(offsets[28], object.mainAlarmTime); + writer.writeLong(offsets[29], object.mathsDifficulty); + writer.writeLong(offsets[30], object.minutesSinceMidnight); + writer.writeBool(offsets[31], object.mutexLock); + writer.writeString(offsets[32], object.note); + writer.writeLong(offsets[33], object.numMathsQuestions); + writer.writeLong(offsets[34], object.numberOfSteps); + writer.writeString(offsets[35], object.ownerId); + writer.writeString(offsets[36], object.ownerName); + writer.writeString(offsets[37], object.profile); + writer.writeString(offsets[38], object.qrValue); + writer.writeBool(offsets[39], object.ringOn); + writer.writeString(offsets[40], object.ringtoneName); + writer.writeString(offsets[41], object.serializedTaskList); + writer.writeLong(offsets[42], object.shakeTimes); + writer.writeStringList(offsets[43], object.sharedUserIds); + writer.writeBool(offsets[44], object.showMotivationalQuote); + writer.writeLong(offsets[45], object.snoozeDuration); + writer.writeDouble(offsets[46], object.volMax); + writer.writeDouble(offsets[47], object.volMin); + writer.writeLongList(offsets[48], object.weatherTypes); } AlarmModel _alarmModelDeserialize( @@ -399,30 +412,32 @@ AlarmModel _alarmModelDeserialize( isQrEnabled: reader.readBool(offsets[20]), isShakeEnabled: reader.readBool(offsets[21]), isSharedAlarmEnabled: reader.readBool(offsets[22]), - isWeatherEnabled: reader.readBool(offsets[23]), - label: reader.readString(offsets[24]), - lastEditedUserId: reader.readString(offsets[25]), - location: reader.readString(offsets[26]), - mainAlarmTime: reader.readStringOrNull(offsets[27]), - mathsDifficulty: reader.readLong(offsets[28]), - minutesSinceMidnight: reader.readLong(offsets[29]), - mutexLock: reader.readBool(offsets[30]), - note: reader.readString(offsets[31]), - numMathsQuestions: reader.readLong(offsets[32]), - numberOfSteps: reader.readLong(offsets[33]), - ownerId: reader.readString(offsets[34]), - ownerName: reader.readString(offsets[35]), - profile: reader.readString(offsets[36]), - qrValue: reader.readString(offsets[37]), - ringOn: reader.readBool(offsets[38]), - ringtoneName: reader.readString(offsets[39]), - shakeTimes: reader.readLong(offsets[40]), - sharedUserIds: reader.readStringList(offsets[41]), - showMotivationalQuote: reader.readBool(offsets[42]), - snoozeDuration: reader.readLong(offsets[43]), - volMax: reader.readDouble(offsets[44]), - volMin: reader.readDouble(offsets[45]), - weatherTypes: reader.readLongList(offsets[46]) ?? [], + isTaskListEnabled: reader.readBoolOrNull(offsets[23]) ?? false, + isWeatherEnabled: reader.readBool(offsets[24]), + label: reader.readString(offsets[25]), + lastEditedUserId: reader.readString(offsets[26]), + location: reader.readString(offsets[27]), + mainAlarmTime: reader.readStringOrNull(offsets[28]), + mathsDifficulty: reader.readLong(offsets[29]), + minutesSinceMidnight: reader.readLong(offsets[30]), + mutexLock: reader.readBool(offsets[31]), + note: reader.readString(offsets[32]), + numMathsQuestions: reader.readLong(offsets[33]), + numberOfSteps: reader.readLong(offsets[34]), + ownerId: reader.readString(offsets[35]), + ownerName: reader.readString(offsets[36]), + profile: reader.readString(offsets[37]), + qrValue: reader.readString(offsets[38]), + ringOn: reader.readBool(offsets[39]), + ringtoneName: reader.readString(offsets[40]), + serializedTaskList: reader.readStringOrNull(offsets[41]) ?? '[]', + shakeTimes: reader.readLong(offsets[42]), + sharedUserIds: reader.readStringList(offsets[43]), + showMotivationalQuote: reader.readBool(offsets[44]), + snoozeDuration: reader.readLong(offsets[45]), + volMax: reader.readDouble(offsets[46]), + volMin: reader.readDouble(offsets[47]), + weatherTypes: reader.readLongList(offsets[48]) ?? [], ); object.firestoreId = reader.readStringOrNull(offsets[7]); object.isarId = id; @@ -483,29 +498,29 @@ P _alarmModelDeserializeProp

( case 22: return (reader.readBool(offset)) as P; case 23: - return (reader.readBool(offset)) as P; + return (reader.readBoolOrNull(offset) ?? false) as P; case 24: - return (reader.readString(offset)) as P; + return (reader.readBool(offset)) as P; case 25: return (reader.readString(offset)) as P; case 26: return (reader.readString(offset)) as P; case 27: - return (reader.readStringOrNull(offset)) as P; + return (reader.readString(offset)) as P; case 28: - return (reader.readLong(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 29: return (reader.readLong(offset)) as P; case 30: - return (reader.readBool(offset)) as P; + return (reader.readLong(offset)) as P; case 31: - return (reader.readString(offset)) as P; + return (reader.readBool(offset)) as P; case 32: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 33: return (reader.readLong(offset)) as P; case 34: - return (reader.readString(offset)) as P; + return (reader.readLong(offset)) as P; case 35: return (reader.readString(offset)) as P; case 36: @@ -513,22 +528,26 @@ P _alarmModelDeserializeProp

( case 37: return (reader.readString(offset)) as P; case 38: - return (reader.readBool(offset)) as P; - case 39: return (reader.readString(offset)) as P; + case 39: + return (reader.readBool(offset)) as P; case 40: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 41: - return (reader.readStringList(offset)) as P; + return (reader.readStringOrNull(offset) ?? '[]') as P; case 42: - return (reader.readBool(offset)) as P; - case 43: return (reader.readLong(offset)) as P; + case 43: + return (reader.readStringList(offset)) as P; case 44: - return (reader.readDouble(offset)) as P; + return (reader.readBool(offset)) as P; case 45: - return (reader.readDouble(offset)) as P; + return (reader.readLong(offset)) as P; case 46: + return (reader.readDouble(offset)) as P; + case 47: + return (reader.readDouble(offset)) as P; + case 48: return (reader.readLongList(offset) ?? []) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -1812,6 +1831,16 @@ extension AlarmModelQueryFilter }); } + QueryBuilder + isTaskListEnabledEqualTo(bool value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'isTaskListEnabled', + value: value, + )); + }); + } + QueryBuilder isWeatherEnabledEqualTo(bool value) { return QueryBuilder.apply(this, (query) { @@ -3470,6 +3499,142 @@ extension AlarmModelQueryFilter }); } + QueryBuilder + serializedTaskListEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'serializedTaskList', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'serializedTaskList', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'serializedTaskList', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'serializedTaskList', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'serializedTaskList', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'serializedTaskList', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'serializedTaskList', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'serializedTaskList', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + serializedTaskListIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'serializedTaskList', + value: '', + )); + }); + } + + QueryBuilder + serializedTaskListIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'serializedTaskList', + value: '', + )); + }); + } + QueryBuilder shakeTimesEqualTo( int value) { return QueryBuilder.apply(this, (query) { @@ -4389,6 +4554,19 @@ extension AlarmModelQuerySortBy }); } + QueryBuilder sortByIsTaskListEnabled() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isTaskListEnabled', Sort.asc); + }); + } + + QueryBuilder + sortByIsTaskListEnabledDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isTaskListEnabled', Sort.desc); + }); + } + QueryBuilder sortByIsWeatherEnabled() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'isWeatherEnabled', Sort.asc); @@ -4599,6 +4777,20 @@ extension AlarmModelQuerySortBy }); } + QueryBuilder + sortBySerializedTaskList() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'serializedTaskList', Sort.asc); + }); + } + + QueryBuilder + sortBySerializedTaskListDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'serializedTaskList', Sort.desc); + }); + } + QueryBuilder sortByShakeTimes() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'shakeTimes', Sort.asc); @@ -4942,6 +5134,19 @@ extension AlarmModelQuerySortThenBy }); } + QueryBuilder thenByIsTaskListEnabled() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isTaskListEnabled', Sort.asc); + }); + } + + QueryBuilder + thenByIsTaskListEnabledDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isTaskListEnabled', Sort.desc); + }); + } + QueryBuilder thenByIsWeatherEnabled() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'isWeatherEnabled', Sort.asc); @@ -5164,6 +5369,20 @@ extension AlarmModelQuerySortThenBy }); } + QueryBuilder + thenBySerializedTaskList() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'serializedTaskList', Sort.asc); + }); + } + + QueryBuilder + thenBySerializedTaskListDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'serializedTaskList', Sort.desc); + }); + } + QueryBuilder thenByShakeTimes() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'shakeTimes', Sort.asc); @@ -5378,6 +5597,13 @@ extension AlarmModelQueryWhereDistinct }); } + QueryBuilder + distinctByIsTaskListEnabled() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'isTaskListEnabled'); + }); + } + QueryBuilder distinctByIsWeatherEnabled() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'isWeatherEnabled'); @@ -5494,6 +5720,14 @@ extension AlarmModelQueryWhereDistinct }); } + QueryBuilder distinctBySerializedTaskList( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'serializedTaskList', + caseSensitive: caseSensitive); + }); + } + QueryBuilder distinctByShakeTimes() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'shakeTimes'); @@ -5687,6 +5921,12 @@ extension AlarmModelQueryProperty }); } + QueryBuilder isTaskListEnabledProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'isTaskListEnabled'); + }); + } + QueryBuilder isWeatherEnabledProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'isWeatherEnabled'); @@ -5791,6 +6031,13 @@ extension AlarmModelQueryProperty }); } + QueryBuilder + serializedTaskListProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'serializedTaskList'); + }); + } + QueryBuilder shakeTimesProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'shakeTimes'); diff --git a/lib/app/data/models/profile_model.dart b/lib/app/data/models/profile_model.dart index 04a6b89b..f3717ff1 100644 --- a/lib/app/data/models/profile_model.dart +++ b/lib/app/data/models/profile_model.dart @@ -54,6 +54,8 @@ class ProfileModel { late int guardianTimer; late String guardian; late bool isCall; + late bool isTaskListEnabled; + late String serializedTaskList; @ignore Map? offsetDetails; @@ -101,7 +103,9 @@ class ProfileModel { required this.isGuardian, required this.guardianTimer, required this.guardian, - required this.isCall}); + required this.isCall, + this.isTaskListEnabled = false, + this.serializedTaskList = '[]'}); ProfileModel.fromDocumentSnapshot({ required firestore.DocumentSnapshot documentSnapshot, @@ -167,6 +171,10 @@ class ProfileModel { guardianTimer = documentSnapshot['guardianTimer']; guardian = documentSnapshot['guardian']; isCall = documentSnapshot['isCall']; + + // Task list fields with defaults if they don't exist + isTaskListEnabled = documentSnapshot['isTaskListEnabled'] ?? false; + serializedTaskList = documentSnapshot['serializedTaskList'] ?? '[]'; } ProfileModel.fromMap(Map profileData) { @@ -219,6 +227,10 @@ class ProfileModel { guardian = profileData['guardian']; isCall = profileData['isCall']; ringOn = profileData['ringOn']; + + // Task list fields with defaults if they don't exist + isTaskListEnabled = profileData['isTaskListEnabled'] ?? false; + serializedTaskList = profileData['serializedTaskList'] ?? '[]'; } ProfileModel.fromJson(String profileData, UserModel? user) { @@ -249,8 +261,9 @@ class ProfileModel { 'activityInterval': profileRecord.activityInterval, 'minutesSinceMidnight': profileRecord.minutesSinceMidnight, 'isLocationEnabled': profileRecord.isLocationEnabled, - 'location': profileRecord.location, 'isSharedAlarmEnabled': profileRecord.isSharedAlarmEnabled, + 'offsetDetails': profileRecord.offsetDetails, + 'location': profileRecord.location, 'isMathsEnabled': profileRecord.isMathsEnabled, 'mathsDifficulty': profileRecord.mathsDifficulty, 'numMathsQuestions': profileRecord.numMathsQuestions, @@ -274,7 +287,9 @@ class ProfileModel { 'guardianTimer': profileRecord.guardianTimer, 'guardian': profileRecord.guardian, 'isCall': profileRecord.isCall, - 'ringOn': profileRecord.ringOn + 'ringOn': profileRecord.ringOn, + 'isTaskListEnabled': profileRecord.isTaskListEnabled, + 'serializedTaskList': profileRecord.serializedTaskList }; if (profileRecord.isSharedAlarmEnabled) { diff --git a/lib/app/data/models/task_model.dart b/lib/app/data/models/task_model.dart new file mode 100644 index 00000000..b03b3fc5 --- /dev/null +++ b/lib/app/data/models/task_model.dart @@ -0,0 +1,39 @@ +import 'dart:convert'; + +class TaskModel { + final String id; + final String text; + bool completed; + + TaskModel({ + required this.id, + required this.text, + this.completed = false, + }); + + Map toJson() { + return { + 'id': id, + 'text': text, + 'completed': completed, + }; + } + + factory TaskModel.fromJson(Map json) { + return TaskModel( + id: json['id'], + text: json['text'], + completed: json['completed'], + ); + } + + static String encodeTaskList(List tasks) { + return jsonEncode(tasks.map((task) => task.toJson()).toList()); + } + + static List decodeTaskList(String taskListJson) { + if (taskListJson.isEmpty || taskListJson == '[]') return []; + final List jsonList = jsonDecode(taskListJson); + return jsonList.map((json) => TaskModel.fromJson(json)).toList(); + } +} \ No newline at end of file diff --git a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart index baf81538..7c7cdeae 100644 --- a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart +++ b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart @@ -11,6 +11,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:ultimate_alarm_clock/app/data/models/alarm_model.dart'; import 'package:ultimate_alarm_clock/app/data/models/profile_model.dart'; +import 'package:ultimate_alarm_clock/app/data/models/task_model.dart'; import 'package:ultimate_alarm_clock/app/data/models/user_model.dart'; import 'package:ultimate_alarm_clock/app/data/providers/firestore_provider.dart'; import 'package:ultimate_alarm_clock/app/data/providers/get_storage_provider.dart'; @@ -113,6 +114,16 @@ class AddOrUpdateAlarmController extends GetxController { final RxInt hours = 0.obs, minutes = 0.obs, meridiemIndex = 0.obs; final List meridiem = ['AM'.obs, 'PM'.obs]; + final RxBool isGuardian = false.obs; + final RxInt guardianTimer = 0.obs; + final RxString guardian = ''.obs; + final RxBool isCall = false.obs; + + // Task list properties + final RxBool isTaskListEnabled = false.obs; + final RxList taskList = [].obs; + final RxString serializedTaskList = '[]'.obs; + Future> fetchUserDetailsForSharedUsers() async { List userDetails = []; @@ -137,11 +148,6 @@ class AddOrUpdateAlarmController extends GetxController { late ProfileModel profileModel; final storage = Get.find(); - final RxBool isGuardian = false.obs; - final RxInt guardianTimer = 0.obs; - final RxString guardian = ''.obs; - final RxBool isCall = false.obs; - void toggleIsPlaying() { isPlaying.toggle(); } @@ -828,6 +834,14 @@ class AddOrUpdateAlarmController extends GetxController { alarmRecord.value.mutexLock = false; mutexLock.value = false; } + + // Load task list data + isTaskListEnabled.value = alarmRecord.value.isTaskListEnabled; + if (alarmRecord.value.serializedTaskList.isNotEmpty && + alarmRecord.value.serializedTaskList != '[]') { + taskList.value = TaskModel.decodeTaskList(alarmRecord.value.serializedTaskList); + serializedTaskList.value = alarmRecord.value.serializedTaskList; + } } else { hours.value = selectedTime.value.hour; minutes.value = selectedTime.value.minute; @@ -1075,6 +1089,8 @@ class AddOrUpdateAlarmController extends GetxController { guardian: guardian.value, isCall: isCall.value, ringOn: isFutureDate.value, + isTaskListEnabled: isTaskListEnabled.value, + serializedTaskList: serializedTaskList.value, ); } @@ -1370,6 +1386,8 @@ class AddOrUpdateAlarmController extends GetxController { guardian: guardian.value, isCall: isCall.value, ringOn: isFutureDate.value, + isTaskListEnabled: isTaskListEnabled.value, + serializedTaskList: serializedTaskList.value, ); if (homeController.isProfileUpdate.value) { @@ -1408,7 +1426,6 @@ class AddOrUpdateAlarmController extends GetxController { ); } } -} int orderedCountryCode(Country countryA, Country countryB) { // `??` for null safety of 'dialCode' @@ -1417,3 +1434,21 @@ class AddOrUpdateAlarmController extends GetxController { return int.parse(dialCodeA).compareTo(int.parse(dialCodeB)); } + + // Task list methods + void addTask(TaskModel task) { + taskList.add(task); + updateSerializedTaskList(); + } + + void removeTask(int index) { + if (index >= 0 && index < taskList.length) { + taskList.removeAt(index); + updateSerializedTaskList(); + } + } + + void updateSerializedTaskList() { + serializedTaskList.value = TaskModel.encodeTaskList(taskList); + } +} diff --git a/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart b/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart index aaa14d44..bfd2093b 100644 --- a/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart +++ b/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart @@ -4,6 +4,7 @@ import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/timer/controllers/timer_controller.dart'; +import 'package:get/get_utils/get_utils.dart'; class InputTimeController extends GetxController { SettingsController settingsController = Get.find(); @@ -41,18 +42,26 @@ class InputTimeController extends GetxController { } void initTimeTextField() { - AddOrUpdateAlarmController addOrUpdateAlarmController = Get.find(); - selectedDateTime.value = addOrUpdateAlarmController.selectedTime.value; - - isAM.value = addOrUpdateAlarmController.selectedTime.value.hour < 12; - inputHrsController.text = settingsController.is24HrsEnabled.value - ? selectedDateTime.value.hour.toString() - : (selectedDateTime.value.hour == 0 - ? '12' - : (selectedDateTime.value.hour > 12 - ? (selectedDateTime.value.hour - 12).toString() - : selectedDateTime.value.hour.toString())); - inputMinutesController.text = selectedDateTime.value.minute.toString().padLeft(2, '0'); + try { + // Safely check controllers before using them - if exception occurs during access, they're likely disposed + if (!GetUtils.isNull(inputHrsController) && !GetUtils.isNull(inputMinutesController)) { + AddOrUpdateAlarmController addOrUpdateAlarmController = Get.find(); + selectedDateTime.value = addOrUpdateAlarmController.selectedTime.value; + + isAM.value = addOrUpdateAlarmController.selectedTime.value.hour < 12; + inputHrsController.text = settingsController.is24HrsEnabled.value + ? selectedDateTime.value.hour.toString() + : (selectedDateTime.value.hour == 0 + ? '12' + : (selectedDateTime.value.hour > 12 + ? (selectedDateTime.value.hour - 12).toString() + : selectedDateTime.value.hour.toString())); + inputMinutesController.text = selectedDateTime.value.minute.toString().padLeft(2, '0'); + } + } catch (e) { + debugPrint('Error in initTimeTextField: $e'); + // Controller was likely disposed + } } diff --git a/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart b/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart index 3a33c30b..293ec5c8 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart @@ -5,7 +5,9 @@ import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:numberpicker/numberpicker.dart'; import 'package:ultimate_alarm_clock/app/data/models/alarm_model.dart'; +import 'package:ultimate_alarm_clock/app/data/providers/secure_storage_provider.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/alarm_id_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/alarm_offset_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/ascending_volume.dart'; @@ -26,12 +28,12 @@ import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/shake_to import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/shared_alarm_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/shared_users_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/snooze_duration_tile.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/task_list_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/weather_tile.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; import 'package:ultimate_alarm_clock/app/utils/constants.dart'; import 'package:ultimate_alarm_clock/app/utils/utils.dart'; -import '../controllers/add_or_update_alarm_controller.dart'; import 'alarm_date_tile.dart'; import 'guardian_angel.dart'; @@ -880,6 +882,14 @@ class AddOrUpdateAlarmView extends GetView { color: themeController .primaryDisabledTextColor.value, ), + TaskListTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), QuoteTile( controller: controller, themeController: themeController, @@ -1108,6 +1118,7 @@ class AddOrUpdateAlarmView extends GetView { controller.selectedTime.value, ), ), + isEnabled: true, intervalToAlarm: Utils.getMillisecondsToAlarm( DateTime.now(), controller.selectedTime.value, @@ -1121,9 +1132,9 @@ class AddOrUpdateAlarmView extends GetView { ), isLocationEnabled: controller.isLocationEnabled.value, - weatherTypes: Utils.getIntFromWeatherTypes( - controller.selectedWeather.toList(), - ), + weatherTypes: + Utils.getIntFromWeatherTypes( + controller.selectedWeather.toList()), isWeatherEnabled: controller.isWeatherEnabled.value, location: Utils.geoPointToString( @@ -1133,13 +1144,13 @@ class AddOrUpdateAlarmView extends GetView { ), isSharedAlarmEnabled: controller.isSharedAlarmEnabled.value, - isQrEnabled: controller.isQrEnabled.value, - qrValue: controller.qrValue.value, isMathsEnabled: controller.isMathsEnabled.value, numMathsQuestions: controller.numMathsQuestions.value, mathsDifficulty: controller.mathsDifficulty.value.index, + isQrEnabled: controller.isQrEnabled.value, + qrValue: controller.qrValue.value, isShakeEnabled: controller.isShakeEnabled.value, shakeTimes: controller.shakeTimes.value, isPedometerEnabled: @@ -1160,6 +1171,8 @@ class AddOrUpdateAlarmView extends GetView { .contactTextEditingController.text, isCall: controller.isCall.value, ringOn: controller.isFutureDate.value, + isTaskListEnabled: controller.isTaskListEnabled.value, + serializedTaskList: controller.serializedTaskList.value, ); // Adding offset details to the database if diff --git a/lib/app/modules/addOrUpdateAlarm/views/guardian_angel.dart b/lib/app/modules/addOrUpdateAlarm/views/guardian_angel.dart index 51842047..1406ec87 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/guardian_angel.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/guardian_angel.dart @@ -50,7 +50,7 @@ class GuardianAngel extends StatelessWidget { setSelectorButtonAsPrefixIcon: true, leadingPadding: 0, trailingSpace: false, - countryComparator: orderedCountryCode, + // countryComparator: orderedCountryCode, ), ), ), diff --git a/lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart b/lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart new file mode 100644 index 00000000..b7e1b8db --- /dev/null +++ b/lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart @@ -0,0 +1,237 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:ultimate_alarm_clock/app/data/models/task_model.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; +import 'package:ultimate_alarm_clock/app/utils/constants.dart'; +import 'package:uuid/uuid.dart'; + +class TaskListEditorPage extends StatefulWidget { + final AddOrUpdateAlarmController controller; + final ThemeController themeController; + + const TaskListEditorPage({ + Key? key, + required this.controller, + required this.themeController, + }) : super(key: key); + + @override + State createState() => _TaskListEditorPageState(); +} + +class _TaskListEditorPageState extends State { + final TextEditingController taskController = TextEditingController(); + final FocusNode taskFocusNode = FocusNode(); + + @override + void dispose() { + taskController.dispose(); + taskFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final double width = MediaQuery.of(context).size.width; + + return Scaffold( + backgroundColor: widget.themeController.primaryBackgroundColor.value, + appBar: AppBar( + backgroundColor: widget.themeController.secondaryBackgroundColor.value, + title: Text( + 'Edit Tasks'.tr, + style: TextStyle( + color: widget.themeController.primaryTextColor.value, + fontWeight: FontWeight.bold, + ), + ), + leading: IconButton( + icon: Icon( + Icons.arrow_back, + color: widget.themeController.primaryTextColor.value, + ), + onPressed: () => Get.back(), + ), + actions: [ + IconButton( + icon: Icon( + Icons.check, + color: widget.themeController.primaryTextColor.value, + ), + onPressed: () => Get.back(), + ), + ], + ), + body: Column( + children: [ + // Task input field + Container( + padding: const EdgeInsets.all(16), + color: widget.themeController.secondaryBackgroundColor.value, + child: Row( + children: [ + Expanded( + child: TextField( + controller: taskController, + focusNode: taskFocusNode, + style: TextStyle(color: widget.themeController.primaryTextColor.value), + decoration: InputDecoration( + hintText: 'Add a task'.tr, + hintStyle: TextStyle(color: widget.themeController.primaryDisabledTextColor.value), + filled: true, + fillColor: widget.themeController.primaryBackgroundColor.value, + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide.none, + ), + suffixIcon: IconButton( + icon: const Icon(Icons.add_circle, color: kprimaryColor, size: 28), + onPressed: _addTask, + ), + ), + onSubmitted: (_) => _addTask(), + ), + ), + ], + ), + ), + + // Information banner + Container( + width: width, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + color: widget.themeController.secondaryBackgroundColor.value.withOpacity(0.5), + child: Text( + 'These tasks will be displayed when your alarm rings'.tr, + style: TextStyle( + color: widget.themeController.primaryDisabledTextColor.value, + fontSize: 13, + fontStyle: FontStyle.italic, + ), + ), + ), + + // Task list + Expanded( + child: Obx(() => widget.controller.taskList.isEmpty + ? _buildEmptyState() + : _buildTaskList()), + ), + ], + ), + ); + } + + void _addTask() { + if (taskController.text.isNotEmpty) { + widget.controller.addTask(TaskModel( + id: const Uuid().v4(), + text: taskController.text, + )); + taskController.clear(); + taskFocusNode.requestFocus(); + } + } + + Widget _buildEmptyState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.task_alt, + size: 70, + color: widget.themeController.primaryDisabledTextColor.value.withOpacity(0.3), + ), + const SizedBox(height: 16), + Text( + 'No tasks yet'.tr, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + color: widget.themeController.primaryDisabledTextColor.value, + ), + ), + const SizedBox(height: 8), + Text( + 'Add a task using the field above'.tr, + style: TextStyle( + fontSize: 14, + color: widget.themeController.primaryDisabledTextColor.value, + ), + ), + ], + ), + ); + } + + Widget _buildTaskList() { + return Obx(() => ReorderableListView.builder( + padding: const EdgeInsets.only(top: 8), + itemCount: widget.controller.taskList.length, + onReorder: (oldIndex, newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + final item = widget.controller.taskList.removeAt(oldIndex); + widget.controller.taskList.insert(newIndex, item); + widget.controller.updateSerializedTaskList(); + }, + itemBuilder: (context, index) { + final task = widget.controller.taskList[index]; + return Dismissible( + key: Key(task.id), + background: Container( + color: Colors.red, + alignment: Alignment.centerRight, + padding: const EdgeInsets.only(right: 20), + child: const Icon( + Icons.delete, + color: Colors.white, + ), + ), + direction: DismissDirection.endToStart, + onDismissed: (direction) { + widget.controller.removeTask(index); + }, + child: Container( + margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 16), + decoration: BoxDecoration( + color: widget.themeController.secondaryBackgroundColor.value, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + offset: const Offset(0, 2), + blurRadius: 4, + ), + ], + ), + child: ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + leading: Icon( + Icons.drag_indicator, + color: widget.themeController.primaryDisabledTextColor.value, + ), + title: Text( + task.text, + style: TextStyle( + color: widget.themeController.primaryTextColor.value, + fontSize: 16, + ), + ), + trailing: IconButton( + icon: const Icon(Icons.delete_outline, color: Colors.red), + onPressed: () { + widget.controller.removeTask(index); + }, + ), + ), + ), + ); + }, + )); + } +} \ No newline at end of file diff --git a/lib/app/modules/addOrUpdateAlarm/views/task_list_tile.dart b/lib/app/modules/addOrUpdateAlarm/views/task_list_tile.dart new file mode 100644 index 00000000..4c4c32cb --- /dev/null +++ b/lib/app/modules/addOrUpdateAlarm/views/task_list_tile.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:ultimate_alarm_clock/app/data/models/task_model.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; +import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart'; +import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart'; +import 'package:ultimate_alarm_clock/app/utils/constants.dart'; +import 'package:uuid/uuid.dart'; + +class TaskListTile extends StatelessWidget { + const TaskListTile({ + super.key, + required this.controller, + required this.themeController, + }); + + final AddOrUpdateAlarmController controller; + final ThemeController themeController; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + ListTile( + onTap: () { + if (controller.isTaskListEnabled.value) { + _openTaskListEditor(context); + } + }, + title: Row( + children: [ + FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Obx( + () => Text( + 'Task List'.tr, + style: TextStyle( + color: themeController.primaryTextColor.value, + ), + ), + ), + ), + Obx( + () => IconButton( + icon: Icon( + Icons.info_sharp, + size: 21, + color: themeController.primaryTextColor.value.withOpacity(0.3), + ), + onPressed: () { + Get.defaultDialog( + title: 'Task List'.tr, + middleText: 'Add a small, customizable to-do list that will be displayed when the alarm goes off, reminding you of important tasks or goals right at wake-up.'.tr, + backgroundColor: themeController.secondaryBackgroundColor.value, + titleStyle: TextStyle(color: themeController.primaryTextColor.value), + middleTextStyle: TextStyle(color: themeController.primaryTextColor.value), + radius: 8, + ); + }, + ), + ), + ], + ), + trailing: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Obx( + () { + return Switch.adaptive( + value: controller.isTaskListEnabled.value, + activeColor: ksecondaryColor, + onChanged: (value) { + controller.isTaskListEnabled.value = value; + if (value && controller.taskList.isEmpty) { + _openTaskListEditor(context); + } + }, + ); + }, + ), + ], + ), + ), + Obx(() => controller.isTaskListEnabled.value && controller.taskList.isNotEmpty + ? Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ...controller.taskList.map((task) => _buildTaskItem(task, context)), + TextButton( + onPressed: () => _openTaskListEditor(context), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.edit, size: 16, color: themeController.primaryColor.value), + const SizedBox(width: 4), + Text( + 'Edit Tasks'.tr, + style: TextStyle(color: themeController.primaryColor.value), + ), + ], + ), + ) + ], + ), + ) + : const SizedBox.shrink()), + ], + ); + } + + Widget _buildTaskItem(TaskModel task, BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + children: [ + Icon( + Icons.circle, + size: 8, + color: themeController.primaryTextColor.value, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + task.text, + style: TextStyle( + color: themeController.primaryTextColor.value, + fontSize: 14, + ), + ), + ), + ], + ), + ); + } + + void _openTaskListEditor(BuildContext context) { + Get.to( + () => TaskListEditorPage( + controller: controller, + themeController: themeController, + ), + transition: Transition.rightToLeft, + ); + } +} \ No newline at end of file diff --git a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart index cee4e80c..60ca7f59 100644 --- a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart +++ b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart @@ -10,6 +10,7 @@ import 'package:flutter_volume_controller/flutter_volume_controller.dart'; import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/data/models/alarm_model.dart'; import 'package:ultimate_alarm_clock/app/data/models/quote_model.dart'; +import 'package:ultimate_alarm_clock/app/data/models/task_model.dart'; import 'package:ultimate_alarm_clock/app/data/models/user_model.dart'; @@ -53,6 +54,28 @@ class AlarmControlController extends GetxController { late Timer guardianTimer; RxInt guardianCoundown = 120.obs; RxBool isPreviewMode = false.obs; + + // Task list properties + RxList taskList = [].obs; + RxBool hasTaskList = false.obs; + + // Toggle task completion status + void toggleTaskCompletion(int index) { + if (index >= 0 && index < taskList.length) { + // Create a new copy of the task with the updated completion status + final updatedTask = TaskModel( + id: taskList[index].id, + text: taskList[index].text, + completed: !taskList[index].completed + ); + + // Replace the task at the specified index + taskList[index] = updatedTask; + + // Notify observers of the change + taskList.refresh(); + } + } getNextAlarm() async { UserModel? _userModel = await SecureStorageProvider().retrieveUserModel(); @@ -237,6 +260,9 @@ class AlarmControlController extends GetxController { super.onInit(); startListeningToFlip(); + // Initialize snoozing state + isSnoozing.value = false; + // Extract alarm and preview flag from arguments final args = Get.arguments; if (args is Map) { @@ -246,6 +272,19 @@ class AlarmControlController extends GetxController { currentlyRingingAlarm.value = args; isPreviewMode.value = false; } + + // Load task list if enabled + if (currentlyRingingAlarm.value.isTaskListEnabled && + currentlyRingingAlarm.value.serializedTaskList.isNotEmpty && + currentlyRingingAlarm.value.serializedTaskList != '[]') { + try { + taskList.value = TaskModel.decodeTaskList(currentlyRingingAlarm.value.serializedTaskList); + hasTaskList.value = taskList.isNotEmpty; + } catch (e) { + debugPrint('Error loading task list: $e'); + hasTaskList.value = false; + } + } print('hwyooo ${currentlyRingingAlarm.value.isGuardian}'); if (currentlyRingingAlarm.value.isGuardian) { diff --git a/lib/app/modules/alarmRing/views/alarm_ring_view.dart b/lib/app/modules/alarmRing/views/alarm_ring_view.dart index ac310a6d..bccd7138 100644 --- a/lib/app/modules/alarmRing/views/alarm_ring_view.dart +++ b/lib/app/modules/alarmRing/views/alarm_ring_view.dart @@ -62,180 +62,337 @@ class AlarmControlView extends GetView { child: Scaffold( body: Stack( children: [ - Center( + Padding( + padding: EdgeInsets.symmetric(vertical: height * 0.06), child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Obx( - () => Column( - children: [ - Text( - controller.formattedDate.value, - style: Theme.of(context).textTheme.bodyLarge, - ), - const SizedBox( - height: 10, - width: 0, - ), - Text( - (controller.isSnoozing.value) - ? "${controller.minutes.toString().padLeft(2, '0')}" - ":${controller.seconds.toString().padLeft(2, '0')}" - : (controller.is24HourFormat.value) - ? '${controller.timeNow24Hr}' - : '${controller.timeNow[0]} ${controller.timeNow[1]}', - style: Theme.of(context) - .textTheme - .displayLarge! - .copyWith(fontSize: 50), - ), - const SizedBox( - height: 20, - width: 0, - ), - Obx( - () => Visibility( - visible: controller.isSnoozing.value, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - getAddSnoozeButtons(context, 1, '+1 min'), - getAddSnoozeButtons(context, 2, '+2 min'), - getAddSnoozeButtons(context, 5, '+5 min'), - ], + // Top section with date and time - moved further down + Padding( + padding: EdgeInsets.only(top: height * 0.04), + child: Obx( + () => Column( + children: [ + Text( + controller.formattedDate.value, + style: Theme.of(context).textTheme.bodyLarge, + ), + const SizedBox( + height: 10, + width: 0, + ), + Text( + (controller.isSnoozing.value) + ? "${controller.minutes.toString().padLeft(2, '0')}" + ":${controller.seconds.toString().padLeft(2, '0')}" + : (controller.is24HourFormat.value) + ? '${controller.timeNow24Hr}' + : '${controller.timeNow[0]} ${controller.timeNow[1]}', + style: Theme.of(context) + .textTheme + .displayLarge! + .copyWith(fontSize: 50), + ), + const SizedBox( + height: 20, + width: 0, + ), + Obx( + () => Visibility( + visible: controller.isSnoozing.value, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + getAddSnoozeButtons(context, 1, '+1 min'), + getAddSnoozeButtons(context, 2, '+2 min'), + getAddSnoozeButtons(context, 5, '+5 min'), + ], + ), ), ), - ), - ], + ], + ), ), ), - Obx( - () { - return Visibility( - visible: controller - .currentlyRingingAlarm.value.note.isNotEmpty, - child: Text( - controller.currentlyRingingAlarm.value.note, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: themeController.primaryTextColor.value, - fontSize: 20, - fontWeight: FontWeight.w100, - fontStyle: FontStyle.italic, + + // Middle section with task list + Expanded( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + // Note + Obx( + () { + return Visibility( + visible: controller + .currentlyRingingAlarm.value.note.isNotEmpty, + child: Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: Text( + controller.currentlyRingingAlarm.value.note, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: themeController.primaryTextColor.value, + fontSize: 20, + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ), + ), + ), + ); + }, + ), + + // Task list display + Obx( + () => Visibility( + visible: controller.hasTaskList.value, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: themeController.secondaryBackgroundColor.value, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 10, + spreadRadius: 1, + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Icon( + Icons.task_alt_rounded, + color: kprimaryColor, + size: 22, + ), + const SizedBox(width: 8), + Text( + 'Today\'s Tasks'.tr, + style: TextStyle( + color: themeController.primaryTextColor.value, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 12), + Obx(() { + int completedTasks = controller.taskList + .where((task) => task.completed) + .length; + int totalTasks = controller.taskList.length; + + return Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Row( + children: [ + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: LinearProgressIndicator( + value: totalTasks > 0 ? completedTasks / totalTasks : 0, + backgroundColor: themeController.primaryBackgroundColor.value, + valueColor: AlwaysStoppedAnimation(kprimaryColor), + minHeight: 8, + ), + ), + ), + const SizedBox(width: 10), + Text( + '$completedTasks/$totalTasks', + style: TextStyle( + color: themeController.primaryTextColor.value, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + }), + const SizedBox(height: 10), + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: height * 0.2, // Slightly reduced max height + ), + child: ListView.builder( + padding: EdgeInsets.zero, + shrinkWrap: true, + itemCount: controller.taskList.length, + itemBuilder: (context, index) { + var task = controller.taskList[index]; + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + margin: const EdgeInsets.only(bottom: 8.0), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), + decoration: BoxDecoration( + color: task.completed + ? kprimaryColor.withOpacity(0.15) + : themeController.primaryBackgroundColor.value.withOpacity(0.3), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + children: [ + Transform.scale( + scale: 1.2, + child: Checkbox( + value: task.completed, + activeColor: kprimaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + onChanged: (bool? value) { + controller.toggleTaskCompletion(index); + }, + ), + ), + Expanded( + child: Text( + task.text, + style: TextStyle( + color: themeController.primaryTextColor.value, + fontSize: 16, + decoration: task.completed ? TextDecoration.lineThrough : null, + decorationColor: kprimaryColor, + decorationThickness: 2, + fontWeight: task.completed ? FontWeight.normal : FontWeight.w500, + ), + ), + ), + ], + ), + ); + }, + ), + ), + ], + ), ), - ), - ); - }, + ), + ), + ], + ), + ), ), - Obx( - () => Visibility( - visible: !controller.isSnoozing.value, - child: Obx( - () => Padding( - padding: const EdgeInsets.symmetric(vertical: 90.0), + + // Bottom section with action buttons - moved higher up + Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Snooze button + Obx( + () => Visibility( + visible: !controller.isSnoozing.value, + child: Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: SizedBox( + height: height * 0.07, + width: width * 0.5, + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + themeController.secondaryBackgroundColor.value, + ), + ), + child: Text( + 'Snooze'.tr, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: themeController.primaryTextColor.value, + fontWeight: FontWeight.w600, + ), + ), + onPressed: () { + Utils.hapticFeedback(); + controller.startSnooze(); + }, + ), + ), + ), + ), + ), + + // Dismiss button + Obx( + () => Visibility( + visible: controller.showButton.value, child: SizedBox( height: height * 0.07, - width: width * 0.5, + width: width * 0.8, child: TextButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all( - themeController - .secondaryBackgroundColor.value, + kprimaryColor, ), ), + onPressed: () async { + Utils.hapticFeedback(); + if (controller.currentlyRingingAlarm.value.isGuardian) { + controller.guardianTimer.cancel(); + } + + if (controller.currentlyRingingAlarm.value.days.every((element) => element == false)) { + controller.currentlyRingingAlarm.value.isEnabled = false; + if (controller.currentlyRingingAlarm.value.isSharedAlarmEnabled == false) { + await IsarDb.updateAlarm(controller.currentlyRingingAlarm.value); + } else { + await FirestoreDb.updateAlarm( + controller.currentlyRingingAlarm.value.ownerId, + controller.currentlyRingingAlarm.value, + ); + } + } + if (Utils.isChallengeEnabled( + controller.currentlyRingingAlarm.value, + )) { + Get.toNamed( + '/alarm-challenge', + arguments: controller.currentlyRingingAlarm.value, + ); + } else { + Get.offAllNamed( + '/bottom-navigation-bar', + arguments: controller.currentlyRingingAlarm.value, + ); + } + }, child: Text( - 'Snooze'.tr, + Utils.isChallengeEnabled( + controller.currentlyRingingAlarm.value, + ) + ? 'Start Challenge'.tr + : 'Dismiss'.tr, style: Theme.of(context) .textTheme - .bodyMedium! + .bodyLarge! .copyWith( - color: themeController - .primaryTextColor.value, - fontWeight: FontWeight.w600, + color: themeController.secondaryTextColor.value, + fontWeight: FontWeight.bold, ), ), - onPressed: () { - Utils.hapticFeedback(); - controller.startSnooze(); - }, ), ), ), ), - ), + ], ), ], ), ), - Positioned( - bottom: 80, - left: width * 0.1, - right: width * 0.1, - child: Obx( - () => Visibility( - visible: controller.showButton.value, - child: SizedBox( - height: height * 0.07, - width: width * 0.8, - child: TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - kprimaryColor, - ), - ), - onPressed: () async { - Utils.hapticFeedback(); - if (controller - .currentlyRingingAlarm.value.isGuardian) { - controller.guardianTimer.cancel(); - } - - if (controller.currentlyRingingAlarm.value.days.every((element) => element == false)) { - controller.currentlyRingingAlarm.value.isEnabled = false; - if (controller.currentlyRingingAlarm.value.isSharedAlarmEnabled == false) { - await IsarDb.updateAlarm(controller.currentlyRingingAlarm.value); - } else { - await FirestoreDb.updateAlarm( - controller.currentlyRingingAlarm.value.ownerId, - controller.currentlyRingingAlarm.value, - ); - } - } - if (Utils.isChallengeEnabled( - controller.currentlyRingingAlarm.value, - )) { - Get.toNamed( - '/alarm-challenge', - arguments: controller.currentlyRingingAlarm.value, - ); - } else { - Get.offAllNamed( - '/bottom-navigation-bar', - arguments: controller.currentlyRingingAlarm.value, - ); - } - }, - child: Text( - Utils.isChallengeEnabled( - controller.currentlyRingingAlarm.value, - ) - ? 'Start Challenge'.tr - : 'Dismiss'.tr, - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith( - color: themeController.secondaryTextColor.value, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ), - ), // Exit Preview button - only show in preview mode if (controller.isPreviewMode.value) Positioned( diff --git a/lib/app/utils/utils.dart b/lib/app/utils/utils.dart index 53c16127..e45b1e14 100644 --- a/lib/app/utils/utils.dart +++ b/lib/app/utils/utils.dart @@ -76,6 +76,8 @@ class Utils { guardian: '', isCall: false, ringOn: false, + isTaskListEnabled: false, + serializedTaskList: '[]', ); static String formatDateTimeToHHMMSS(DateTime dateTime) { From 2240fe6e686602e9cd8c55f401bd833fc416cfe4 Mon Sep 17 00:00:00 2001 From: mahendra-918 Date: Sun, 13 Apr 2025 08:17:49 +0530 Subject: [PATCH 2/2] added --- lib/app/data/models/alarm_model.dart | 2 -- lib/app/data/models/profile_model.dart | 2 -- .../add_or_update_alarm_controller.dart | 3 -- .../controllers/input_time_controller.dart | 35 +++++++------------ .../views/task_list_editor_page.dart | 6 ++-- .../controllers/alarm_ring_controller.dart | 7 ---- .../alarmRing/views/alarm_ring_view.dart | 10 ++---- 7 files changed, 17 insertions(+), 48 deletions(-) diff --git a/lib/app/data/models/alarm_model.dart b/lib/app/data/models/alarm_model.dart index c77b479c..02af6dc6 100644 --- a/lib/app/data/models/alarm_model.dart +++ b/lib/app/data/models/alarm_model.dart @@ -184,7 +184,6 @@ class AlarmModel { guardian = documentSnapshot['guardian']; isCall = documentSnapshot['isCall']; - // Task list fields with default values if they don't exist isTaskListEnabled = documentSnapshot['isTaskListEnabled'] ?? false; serializedTaskList = documentSnapshot['serializedTaskList'] ?? '[]'; } @@ -351,7 +350,6 @@ class AlarmModel { isCall = alarmData['isCall']; ringOn = alarmData['ringOn']; - // Task list fields with defaults if they don't exist isTaskListEnabled = alarmData['isTaskListEnabled'] ?? false; serializedTaskList = alarmData['serializedTaskList'] ?? '[]'; } diff --git a/lib/app/data/models/profile_model.dart b/lib/app/data/models/profile_model.dart index f3717ff1..7fd48cda 100644 --- a/lib/app/data/models/profile_model.dart +++ b/lib/app/data/models/profile_model.dart @@ -172,7 +172,6 @@ class ProfileModel { guardian = documentSnapshot['guardian']; isCall = documentSnapshot['isCall']; - // Task list fields with defaults if they don't exist isTaskListEnabled = documentSnapshot['isTaskListEnabled'] ?? false; serializedTaskList = documentSnapshot['serializedTaskList'] ?? '[]'; } @@ -228,7 +227,6 @@ class ProfileModel { isCall = profileData['isCall']; ringOn = profileData['ringOn']; - // Task list fields with defaults if they don't exist isTaskListEnabled = profileData['isTaskListEnabled'] ?? false; serializedTaskList = profileData['serializedTaskList'] ?? '[]'; } diff --git a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart index 7c7cdeae..71db7147 100644 --- a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart +++ b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart @@ -119,7 +119,6 @@ class AddOrUpdateAlarmController extends GetxController { final RxString guardian = ''.obs; final RxBool isCall = false.obs; - // Task list properties final RxBool isTaskListEnabled = false.obs; final RxList taskList = [].obs; final RxString serializedTaskList = '[]'.obs; @@ -835,7 +834,6 @@ class AddOrUpdateAlarmController extends GetxController { mutexLock.value = false; } - // Load task list data isTaskListEnabled.value = alarmRecord.value.isTaskListEnabled; if (alarmRecord.value.serializedTaskList.isNotEmpty && alarmRecord.value.serializedTaskList != '[]') { @@ -1435,7 +1433,6 @@ class AddOrUpdateAlarmController extends GetxController { return int.parse(dialCodeA).compareTo(int.parse(dialCodeB)); } - // Task list methods void addTask(TaskModel task) { taskList.add(task); updateSerializedTaskList(); diff --git a/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart b/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart index bfd2093b..c09a4d33 100644 --- a/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart +++ b/lib/app/modules/addOrUpdateAlarm/controllers/input_time_controller.dart @@ -4,7 +4,6 @@ import 'package:get/get.dart'; import 'package:ultimate_alarm_clock/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/settings/controllers/settings_controller.dart'; import 'package:ultimate_alarm_clock/app/modules/timer/controllers/timer_controller.dart'; -import 'package:get/get_utils/get_utils.dart'; class InputTimeController extends GetxController { SettingsController settingsController = Get.find(); @@ -42,26 +41,18 @@ class InputTimeController extends GetxController { } void initTimeTextField() { - try { - // Safely check controllers before using them - if exception occurs during access, they're likely disposed - if (!GetUtils.isNull(inputHrsController) && !GetUtils.isNull(inputMinutesController)) { - AddOrUpdateAlarmController addOrUpdateAlarmController = Get.find(); - selectedDateTime.value = addOrUpdateAlarmController.selectedTime.value; - - isAM.value = addOrUpdateAlarmController.selectedTime.value.hour < 12; - inputHrsController.text = settingsController.is24HrsEnabled.value - ? selectedDateTime.value.hour.toString() - : (selectedDateTime.value.hour == 0 - ? '12' - : (selectedDateTime.value.hour > 12 - ? (selectedDateTime.value.hour - 12).toString() - : selectedDateTime.value.hour.toString())); - inputMinutesController.text = selectedDateTime.value.minute.toString().padLeft(2, '0'); - } - } catch (e) { - debugPrint('Error in initTimeTextField: $e'); - // Controller was likely disposed - } + AddOrUpdateAlarmController addOrUpdateAlarmController = Get.find(); + selectedDateTime.value = addOrUpdateAlarmController.selectedTime.value; + + isAM.value = addOrUpdateAlarmController.selectedTime.value.hour < 12; + inputHrsController.text = settingsController.is24HrsEnabled.value + ? selectedDateTime.value.hour.toString() + : (selectedDateTime.value.hour == 0 + ? '12' + : (selectedDateTime.value.hour > 12 + ? (selectedDateTime.value.hour - 12).toString() + : selectedDateTime.value.hour.toString())); + inputMinutesController.text = selectedDateTime.value.minute.toString().padLeft(2, '0'); } @@ -238,4 +229,4 @@ class LimitRange extends TextInputFormatter { return newValue; } } -} +} \ No newline at end of file diff --git a/lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart b/lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart index b7e1b8db..658fe36a 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/task_list_editor_page.dart @@ -65,7 +65,6 @@ class _TaskListEditorPageState extends State { ), body: Column( children: [ - // Task input field Container( padding: const EdgeInsets.all(16), color: widget.themeController.secondaryBackgroundColor.value, @@ -97,8 +96,7 @@ class _TaskListEditorPageState extends State { ], ), ), - - // Information banner + Container( width: width, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), @@ -113,7 +111,7 @@ class _TaskListEditorPageState extends State { ), ), - // Task list + Expanded( child: Obx(() => widget.controller.taskList.isEmpty ? _buildEmptyState() diff --git a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart index 60ca7f59..3655c3ab 100644 --- a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart +++ b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart @@ -55,24 +55,19 @@ class AlarmControlController extends GetxController { RxInt guardianCoundown = 120.obs; RxBool isPreviewMode = false.obs; - // Task list properties RxList taskList = [].obs; RxBool hasTaskList = false.obs; - // Toggle task completion status void toggleTaskCompletion(int index) { if (index >= 0 && index < taskList.length) { - // Create a new copy of the task with the updated completion status final updatedTask = TaskModel( id: taskList[index].id, text: taskList[index].text, completed: !taskList[index].completed ); - // Replace the task at the specified index taskList[index] = updatedTask; - // Notify observers of the change taskList.refresh(); } } @@ -260,7 +255,6 @@ class AlarmControlController extends GetxController { super.onInit(); startListeningToFlip(); - // Initialize snoozing state isSnoozing.value = false; // Extract alarm and preview flag from arguments @@ -273,7 +267,6 @@ class AlarmControlController extends GetxController { isPreviewMode.value = false; } - // Load task list if enabled if (currentlyRingingAlarm.value.isTaskListEnabled && currentlyRingingAlarm.value.serializedTaskList.isNotEmpty && currentlyRingingAlarm.value.serializedTaskList != '[]') { diff --git a/lib/app/modules/alarmRing/views/alarm_ring_view.dart b/lib/app/modules/alarmRing/views/alarm_ring_view.dart index bccd7138..fbce57c8 100644 --- a/lib/app/modules/alarmRing/views/alarm_ring_view.dart +++ b/lib/app/modules/alarmRing/views/alarm_ring_view.dart @@ -67,7 +67,6 @@ class AlarmControlView extends GetView { child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - // Top section with date and time - moved further down Padding( padding: EdgeInsets.only(top: height * 0.04), child: Obx( @@ -115,7 +114,6 @@ class AlarmControlView extends GetView { ), ), - // Middle section with task list Expanded( child: Center( child: Column( @@ -147,7 +145,6 @@ class AlarmControlView extends GetView { }, ), - // Task list display Obx( () => Visibility( visible: controller.hasTaskList.value, @@ -225,7 +222,7 @@ class AlarmControlView extends GetView { const SizedBox(height: 10), ConstrainedBox( constraints: BoxConstraints( - maxHeight: height * 0.2, // Slightly reduced max height + maxHeight: height * 0.2, ), child: ListView.builder( padding: EdgeInsets.zero, @@ -286,12 +283,10 @@ class AlarmControlView extends GetView { ), ), ), - - // Bottom section with action buttons - moved higher up + Column( mainAxisSize: MainAxisSize.min, children: [ - // Snooze button Obx( () => Visibility( visible: !controller.isSnoozing.value, @@ -326,7 +321,6 @@ class AlarmControlView extends GetView { ), ), - // Dismiss button Obx( () => Visibility( visible: controller.showButton.value,