diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 64507121e..69e9e148a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -15,6 +15,9 @@ + + + @@ -100,12 +103,6 @@ android:theme="@style/LaunchTheme" android:windowSoftInputMode="adjustResize"> - @@ -122,10 +119,6 @@ android:hardwareAccelerated="true" android:theme="@style/LaunchTheme" android:windowSoftInputMode="adjustResize" /> - diff --git a/lib/app/data/models/alarm_model.dart b/lib/app/data/models/alarm_model.dart index 56345b7d3..09fb4eb4e 100644 --- a/lib/app/data/models/alarm_model.dart +++ b/lib/app/data/models/alarm_model.dart @@ -60,58 +60,61 @@ class AlarmModel { late int guardianTimer; late String guardian; late bool isCall; + late int challengeDuration; // --- ADDED THIS FOR THE DYNAMIC TIMER --- @ignore Map? offsetDetails; AlarmModel( {required this.alarmTime, - required this.alarmID, - this.sharedUserIds = const [], - required this.ownerId, - required this.ownerName, - required this.lastEditedUserId, - required this.mutexLock, - this.isEnabled = true, - required this.days, - required this.intervalToAlarm, - required this.isActivityEnabled, - required this.minutesSinceMidnight, - required this.isLocationEnabled, - required this.isSharedAlarmEnabled, - required this.isWeatherEnabled, - required this.location, - required this.weatherTypes, - required this.isMathsEnabled, - required this.mathsDifficulty, - required this.numMathsQuestions, - required this.isShakeEnabled, - required this.shakeTimes, - required this.isQrEnabled, - required this.qrValue, - required this.isPedometerEnabled, - required this.numberOfSteps, - required this.activityInterval, - this.offsetDetails = const {}, - required this.mainAlarmTime, - required this.label, - required this.isOneTime, - required this.snoozeDuration, - this.maxSnoozeCount = 3, - required this.gradient, - required this.ringtoneName, - required this.note, - required this.deleteAfterGoesOff, - required this.showMotivationalQuote, - required this.volMax, - required this.volMin, - required this.activityMonitor, - required this.ringOn, - required this.alarmDate, - required this.profile, - required this.isGuardian, - required this.guardianTimer, - required this.guardian, - required this.isCall}); + required this.alarmID, + this.sharedUserIds = const [], + required this.ownerId, + required this.ownerName, + required this.lastEditedUserId, + required this.mutexLock, + this.isEnabled = true, + required this.days, + required this.intervalToAlarm, + required this.isActivityEnabled, + required this.minutesSinceMidnight, + required this.isLocationEnabled, + required this.isSharedAlarmEnabled, + required this.isWeatherEnabled, + required this.location, + required this.weatherTypes, + required this.isMathsEnabled, + required this.mathsDifficulty, + required this.numMathsQuestions, + required this.isShakeEnabled, + required this.shakeTimes, + required this.isQrEnabled, + required this.qrValue, + required this.isPedometerEnabled, + required this.numberOfSteps, + required this.activityInterval, + this.offsetDetails = const {}, + required this.mainAlarmTime, + required this.label, + required this.isOneTime, + required this.snoozeDuration, + this.maxSnoozeCount = 3, + required this.gradient, + required this.ringtoneName, + required this.note, + required this.deleteAfterGoesOff, + required this.showMotivationalQuote, + required this.volMax, + required this.volMin, + required this.activityMonitor, + required this.ringOn, + required this.alarmDate, + required this.profile, + required this.isGuardian, + required this.guardianTimer, + required this.guardian, + required this.isCall, + this.challengeDuration = 15 // --- DEFAULT TO 15 SECONDS --- + }); AlarmModel.fromDocumentSnapshot({ required firestore.DocumentSnapshot documentSnapshot, @@ -121,13 +124,11 @@ class AlarmModel { documentSnapshot.data() as Map, ); - // Making sure the alarms work with the offsets isSharedAlarmEnabled = _asBool(data['isSharedAlarmEnabled'], false); offsetDetails = _asMap(data['offsetDetails']); if (isSharedAlarmEnabled && user != null && offsetDetails?[user.id] != null) { mainAlarmTime = _asString(data['alarmTime'], '00:00'); - // Using offsetted time only if it is enabled final userOffset = _asMap(offsetDetails?[user.id]); final offsetDuration = _asInt(userOffset?['offsetDuration'], 0); final offsettedTime = _asString( @@ -136,7 +137,7 @@ class AlarmModel { ); alarmTime = - (offsetDuration != 0) ? offsettedTime : _asString(data['alarmTime'], '00:00'); + (offsetDuration != 0) ? offsettedTime : _asString(data['alarmTime'], '00:00'); minutesSinceMidnight = Utils.timeOfDayToInt( Utils.stringToTimeOfDay(offsettedTime), ); @@ -192,6 +193,9 @@ class AlarmModel { guardian = _asString(data['guardian'], ''); isCall = _asBool(data['isCall'], false); ringOn = _asBool(data['ringOn'], false); + + // --- GRAB SAVED TIME OR DEFAULT TO 15 --- + challengeDuration = _asInt(data['challengeDuration'], 15); } AlarmModel fromMapSQFlite(Map map) { @@ -245,6 +249,7 @@ class AlarmModel { guardian: map['guardian'], isCall: map['isCall'] == 1, ringOn: map['ringOn'] == 1, + challengeDuration: map['challengeDuration'] ?? 15, // --- ADDED THIS --- ); } @@ -298,11 +303,11 @@ class AlarmModel { 'guardianTimer': guardianTimer, 'guardian': guardian, 'isCall': isCall ? 1 : 0, + 'challengeDuration': challengeDuration, // --- ADDED THIS --- }; } AlarmModel.fromMap(Map alarmData) { - // Making sure the alarms work with the offsets final data = Map.from(alarmData); snoozeDuration = _asInt(data['snoozeDuration'], 0); maxSnoozeCount = _asInt(data['maxSnoozeCount'], 3); @@ -360,6 +365,9 @@ class AlarmModel { ? _asString(data['mainAlarmTime'], alarmTime) : null; offsetDetails = _asMap(data['offsetDetails']); + + // --- GRAB SAVED TIME OR DEFAULT TO 15 --- + challengeDuration = _asInt(data['challengeDuration'], 15); } AlarmModel.fromJson(String alarmData, UserModel? user) @@ -417,7 +425,8 @@ class AlarmModel { 'guardianTimer': alarmRecord.guardianTimer, 'guardian': alarmRecord.guardian, 'isCall': alarmRecord.isCall, - 'ringOn': alarmRecord.ringOn + 'ringOn': alarmRecord.ringOn, + 'challengeDuration': alarmRecord.challengeDuration, // --- ADDED THIS --- }; if (alarmRecord.isSharedAlarmEnabled) { @@ -428,17 +437,13 @@ class AlarmModel { } String boolListToString(List boolList) { - // Rotate the list to start with Sunday var rotatedList = [boolList.last] + boolList.sublist(0, boolList.length - 1); - // Convert the list of bools to a string of 1s and 0s return rotatedList.map((b) => b ? '1' : '0').join(); } List stringToBoolList(String s) { - // Rotate the string to start with Monday final rotatedString = s.substring(1) + s[0]; - // Convert the rotated string to a list of boolean values return rotatedString.split('').map((c) => c == '1').toList(); } @@ -495,4 +500,4 @@ class AlarmModel { } return null; } -} +} \ No newline at end of file diff --git a/lib/app/data/models/alarm_model.g.dart b/lib/app/data/models/alarm_model.g.dart index 7cba153fa..c4eb73854 100644 --- a/lib/app/data/models/alarm_model.g.dart +++ b/lib/app/data/models/alarm_model.g.dart @@ -42,218 +42,223 @@ const AlarmModelSchema = CollectionSchema( name: r'alarmTime', type: IsarType.string, ), - r'days': PropertySchema( + r'challengeDuration': PropertySchema( id: 5, + name: r'challengeDuration', + type: IsarType.long, + ), + r'days': PropertySchema( + id: 6, name: r'days', type: IsarType.boolList, ), r'deleteAfterGoesOff': PropertySchema( - id: 6, + id: 7, name: r'deleteAfterGoesOff', type: IsarType.bool, ), r'firestoreId': PropertySchema( - id: 7, + id: 8, name: r'firestoreId', type: IsarType.string, ), r'gradient': PropertySchema( - id: 8, + id: 9, name: r'gradient', type: IsarType.long, ), r'guardian': PropertySchema( - id: 9, + id: 10, name: r'guardian', type: IsarType.string, ), r'guardianTimer': PropertySchema( - id: 10, + id: 11, name: r'guardianTimer', type: IsarType.long, ), r'intervalToAlarm': PropertySchema( - id: 11, + id: 12, name: r'intervalToAlarm', type: IsarType.long, ), r'isActivityEnabled': PropertySchema( - id: 12, + id: 13, name: r'isActivityEnabled', type: IsarType.bool, ), r'isCall': PropertySchema( - id: 13, + id: 14, name: r'isCall', type: IsarType.bool, ), r'isEnabled': PropertySchema( - id: 14, + id: 15, name: r'isEnabled', type: IsarType.bool, ), r'isGuardian': PropertySchema( - id: 15, + id: 16, name: r'isGuardian', type: IsarType.bool, ), r'isLocationEnabled': PropertySchema( - id: 16, + id: 17, name: r'isLocationEnabled', type: IsarType.bool, ), r'isMathsEnabled': PropertySchema( - id: 17, + id: 18, name: r'isMathsEnabled', type: IsarType.bool, ), r'isOneTime': PropertySchema( - id: 18, + id: 19, name: r'isOneTime', type: IsarType.bool, ), r'isPedometerEnabled': PropertySchema( - id: 19, + id: 20, name: r'isPedometerEnabled', type: IsarType.bool, ), r'isQrEnabled': PropertySchema( - id: 20, + id: 21, name: r'isQrEnabled', type: IsarType.bool, ), r'isShakeEnabled': PropertySchema( - id: 21, + id: 22, name: r'isShakeEnabled', type: IsarType.bool, ), r'isSharedAlarmEnabled': PropertySchema( - id: 22, + id: 23, name: r'isSharedAlarmEnabled', type: IsarType.bool, ), r'isWeatherEnabled': PropertySchema( - id: 23, + 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'maxSnoozeCount': PropertySchema( - id: 29, + id: 30, name: r'maxSnoozeCount', type: IsarType.long, ), r'minutesSinceMidnight': PropertySchema( - id: 30, + id: 31, name: r'minutesSinceMidnight', type: IsarType.long, ), r'mutexLock': PropertySchema( - id: 31, + id: 32, name: r'mutexLock', type: IsarType.bool, ), r'note': PropertySchema( - id: 32, + id: 33, name: r'note', type: IsarType.string, ), r'numMathsQuestions': PropertySchema( - id: 33, + id: 34, name: r'numMathsQuestions', type: IsarType.long, ), r'numberOfSteps': PropertySchema( - id: 34, + id: 35, name: r'numberOfSteps', type: IsarType.long, ), r'ownerId': PropertySchema( - id: 35, + id: 36, name: r'ownerId', type: IsarType.string, ), r'ownerName': PropertySchema( - id: 36, + id: 37, name: r'ownerName', type: IsarType.string, ), r'profile': PropertySchema( - id: 37, + id: 38, name: r'profile', type: IsarType.string, ), r'qrValue': PropertySchema( - id: 38, + id: 39, name: r'qrValue', type: IsarType.string, ), r'ringOn': PropertySchema( - id: 39, + id: 40, name: r'ringOn', type: IsarType.bool, ), r'ringtoneName': PropertySchema( - id: 40, + id: 41, name: r'ringtoneName', type: IsarType.string, ), r'shakeTimes': PropertySchema( - id: 41, + id: 42, name: r'shakeTimes', type: IsarType.long, ), r'sharedUserIds': PropertySchema( - id: 42, + id: 43, name: r'sharedUserIds', type: IsarType.stringList, ), r'showMotivationalQuote': PropertySchema( - id: 43, + id: 44, name: r'showMotivationalQuote', type: IsarType.bool, ), r'snoozeDuration': PropertySchema( - id: 44, + id: 45, name: r'snoozeDuration', type: IsarType.long, ), r'volMax': PropertySchema( - id: 45, + id: 46, name: r'volMax', type: IsarType.double, ), r'volMin': PropertySchema( - id: 46, + id: 47, name: r'volMin', type: IsarType.double, ), r'weatherTypes': PropertySchema( - id: 47, + id: 48, name: r'weatherTypes', type: IsarType.longList, ) @@ -331,49 +336,50 @@ void _alarmModelSerialize( writer.writeString(offsets[2], object.alarmDate); writer.writeString(offsets[3], object.alarmID); writer.writeString(offsets[4], object.alarmTime); - writer.writeBoolList(offsets[5], object.days); - writer.writeBool(offsets[6], object.deleteAfterGoesOff); - writer.writeString(offsets[7], object.firestoreId); - writer.writeLong(offsets[8], object.gradient); - writer.writeString(offsets[9], object.guardian); - writer.writeLong(offsets[10], object.guardianTimer); - writer.writeLong(offsets[11], object.intervalToAlarm); - writer.writeBool(offsets[12], object.isActivityEnabled); - writer.writeBool(offsets[13], object.isCall); - writer.writeBool(offsets[14], object.isEnabled); - writer.writeBool(offsets[15], object.isGuardian); - writer.writeBool(offsets[16], object.isLocationEnabled); - writer.writeBool(offsets[17], object.isMathsEnabled); - writer.writeBool(offsets[18], object.isOneTime); - writer.writeBool(offsets[19], object.isPedometerEnabled); - 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.maxSnoozeCount); - 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.writeLong(offsets[41], object.shakeTimes); - writer.writeStringList(offsets[42], object.sharedUserIds); - writer.writeBool(offsets[43], object.showMotivationalQuote); - writer.writeLong(offsets[44], object.snoozeDuration); - writer.writeDouble(offsets[45], object.volMax); - writer.writeDouble(offsets[46], object.volMin); - writer.writeLongList(offsets[47], object.weatherTypes); + writer.writeLong(offsets[5], object.challengeDuration); + writer.writeBoolList(offsets[6], object.days); + writer.writeBool(offsets[7], object.deleteAfterGoesOff); + writer.writeString(offsets[8], object.firestoreId); + writer.writeLong(offsets[9], object.gradient); + writer.writeString(offsets[10], object.guardian); + writer.writeLong(offsets[11], object.guardianTimer); + writer.writeLong(offsets[12], object.intervalToAlarm); + writer.writeBool(offsets[13], object.isActivityEnabled); + writer.writeBool(offsets[14], object.isCall); + writer.writeBool(offsets[15], object.isEnabled); + writer.writeBool(offsets[16], object.isGuardian); + writer.writeBool(offsets[17], object.isLocationEnabled); + writer.writeBool(offsets[18], object.isMathsEnabled); + writer.writeBool(offsets[19], object.isOneTime); + writer.writeBool(offsets[20], object.isPedometerEnabled); + writer.writeBool(offsets[21], object.isQrEnabled); + writer.writeBool(offsets[22], object.isShakeEnabled); + writer.writeBool(offsets[23], object.isSharedAlarmEnabled); + 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.maxSnoozeCount); + writer.writeLong(offsets[31], object.minutesSinceMidnight); + writer.writeBool(offsets[32], object.mutexLock); + writer.writeString(offsets[33], object.note); + writer.writeLong(offsets[34], object.numMathsQuestions); + writer.writeLong(offsets[35], object.numberOfSteps); + writer.writeString(offsets[36], object.ownerId); + writer.writeString(offsets[37], object.ownerName); + writer.writeString(offsets[38], object.profile); + writer.writeString(offsets[39], object.qrValue); + writer.writeBool(offsets[40], object.ringOn); + writer.writeString(offsets[41], object.ringtoneName); + 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( @@ -388,50 +394,51 @@ AlarmModel _alarmModelDeserialize( alarmDate: reader.readString(offsets[2]), alarmID: reader.readString(offsets[3]), alarmTime: reader.readString(offsets[4]), - days: reader.readBoolList(offsets[5]) ?? [], - deleteAfterGoesOff: reader.readBool(offsets[6]), - gradient: reader.readLong(offsets[8]), - guardian: reader.readString(offsets[9]), - guardianTimer: reader.readLong(offsets[10]), - intervalToAlarm: reader.readLong(offsets[11]), - isActivityEnabled: reader.readBool(offsets[12]), - isCall: reader.readBool(offsets[13]), - isEnabled: reader.readBoolOrNull(offsets[14]) ?? true, - isGuardian: reader.readBool(offsets[15]), - isLocationEnabled: reader.readBool(offsets[16]), - isMathsEnabled: reader.readBool(offsets[17]), - isOneTime: reader.readBool(offsets[18]), - isPedometerEnabled: reader.readBool(offsets[19]), - 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]), - maxSnoozeCount: reader.readLongOrNull(offsets[29]) ?? 3, - 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]), - shakeTimes: reader.readLong(offsets[41]), - sharedUserIds: reader.readStringList(offsets[42]), - showMotivationalQuote: reader.readBool(offsets[43]), - snoozeDuration: reader.readLong(offsets[44]), - volMax: reader.readDouble(offsets[45]), - volMin: reader.readDouble(offsets[46]), - weatherTypes: reader.readLongList(offsets[47]) ?? [], + challengeDuration: reader.readLongOrNull(offsets[5]) ?? 15, + days: reader.readBoolList(offsets[6]) ?? [], + deleteAfterGoesOff: reader.readBool(offsets[7]), + gradient: reader.readLong(offsets[9]), + guardian: reader.readString(offsets[10]), + guardianTimer: reader.readLong(offsets[11]), + intervalToAlarm: reader.readLong(offsets[12]), + isActivityEnabled: reader.readBool(offsets[13]), + isCall: reader.readBool(offsets[14]), + isEnabled: reader.readBoolOrNull(offsets[15]) ?? true, + isGuardian: reader.readBool(offsets[16]), + isLocationEnabled: reader.readBool(offsets[17]), + isMathsEnabled: reader.readBool(offsets[18]), + isOneTime: reader.readBool(offsets[19]), + isPedometerEnabled: reader.readBool(offsets[20]), + isQrEnabled: reader.readBool(offsets[21]), + isShakeEnabled: reader.readBool(offsets[22]), + isSharedAlarmEnabled: reader.readBool(offsets[23]), + 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]), + maxSnoozeCount: reader.readLongOrNull(offsets[30]) ?? 3, + minutesSinceMidnight: reader.readLong(offsets[31]), + mutexLock: reader.readBool(offsets[32]), + note: reader.readString(offsets[33]), + numMathsQuestions: reader.readLong(offsets[34]), + numberOfSteps: reader.readLong(offsets[35]), + ownerId: reader.readString(offsets[36]), + ownerName: reader.readString(offsets[37]), + profile: reader.readString(offsets[38]), + qrValue: reader.readString(offsets[39]), + ringOn: reader.readBool(offsets[40]), + ringtoneName: reader.readString(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.firestoreId = reader.readStringOrNull(offsets[8]); object.isarId = id; return object; } @@ -454,27 +461,27 @@ P _alarmModelDeserializeProp

( case 4: return (reader.readString(offset)) as P; case 5: - return (reader.readBoolList(offset) ?? []) as P; + return (reader.readLongOrNull(offset) ?? 15) as P; case 6: - return (reader.readBool(offset)) as P; + return (reader.readBoolList(offset) ?? []) as P; case 7: - return (reader.readStringOrNull(offset)) as P; + return (reader.readBool(offset)) as P; case 8: - return (reader.readLong(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 9: - return (reader.readString(offset)) as P; - case 10: return (reader.readLong(offset)) as P; + case 10: + return (reader.readString(offset)) as P; case 11: return (reader.readLong(offset)) as P; case 12: - return (reader.readBool(offset)) as P; + return (reader.readLong(offset)) as P; case 13: return (reader.readBool(offset)) as P; case 14: - return (reader.readBoolOrNull(offset) ?? true) as P; - case 15: return (reader.readBool(offset)) as P; + case 15: + return (reader.readBoolOrNull(offset) ?? true) as P; case 16: return (reader.readBool(offset)) as P; case 17: @@ -492,29 +499,29 @@ P _alarmModelDeserializeProp

( case 23: return (reader.readBool(offset)) 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.readLongOrNull(offset) ?? 3) as P; - case 30: return (reader.readLong(offset)) as P; + case 30: + return (reader.readLongOrNull(offset) ?? 3) as P; case 31: - return (reader.readBool(offset)) as P; + return (reader.readLong(offset)) as P; case 32: - return (reader.readString(offset)) as P; + return (reader.readBool(offset)) as P; case 33: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 34: return (reader.readLong(offset)) as P; case 35: - return (reader.readString(offset)) as P; + return (reader.readLong(offset)) as P; case 36: return (reader.readString(offset)) as P; case 37: @@ -522,22 +529,24 @@ P _alarmModelDeserializeProp

( case 38: return (reader.readString(offset)) as P; case 39: - return (reader.readBool(offset)) as P; - case 40: return (reader.readString(offset)) as P; + case 40: + return (reader.readBool(offset)) as P; case 41: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 42: - return (reader.readStringList(offset)) as P; + return (reader.readLong(offset)) as P; case 43: - return (reader.readBool(offset)) as P; + return (reader.readStringList(offset)) as P; case 44: - return (reader.readLong(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'); @@ -1151,6 +1160,62 @@ extension AlarmModelQueryFilter }); } + QueryBuilder + challengeDurationEqualTo(int value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'challengeDuration', + value: value, + )); + }); + } + + QueryBuilder + challengeDurationGreaterThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'challengeDuration', + value: value, + )); + }); + } + + QueryBuilder + challengeDurationLessThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'challengeDuration', + value: value, + )); + }); + } + + QueryBuilder + challengeDurationBetween( + int lower, + int upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'challengeDuration', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + QueryBuilder daysElementEqualTo(bool value) { return QueryBuilder.apply(this, (query) { @@ -4239,6 +4304,19 @@ extension AlarmModelQuerySortBy }); } + QueryBuilder sortByChallengeDuration() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'challengeDuration', Sort.asc); + }); + } + + QueryBuilder + sortByChallengeDurationDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'challengeDuration', Sort.desc); + }); + } + QueryBuilder sortByDeleteAfterGoesOff() { return QueryBuilder.apply(this, (query) { @@ -4805,6 +4883,19 @@ extension AlarmModelQuerySortThenBy }); } + QueryBuilder thenByChallengeDuration() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'challengeDuration', Sort.asc); + }); + } + + QueryBuilder + thenByChallengeDurationDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'challengeDuration', Sort.desc); + }); + } + QueryBuilder thenByDeleteAfterGoesOff() { return QueryBuilder.apply(this, (query) { @@ -5354,6 +5445,13 @@ extension AlarmModelQueryWhereDistinct }); } + QueryBuilder + distinctByChallengeDuration() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'challengeDuration'); + }); + } + QueryBuilder distinctByDays() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'days'); @@ -5673,6 +5771,12 @@ extension AlarmModelQueryProperty }); } + QueryBuilder challengeDurationProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'challengeDuration'); + }); + } + QueryBuilder, QQueryOperations> daysProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'days'); diff --git a/lib/app/data/providers/isar_provider.dart b/lib/app/data/providers/isar_provider.dart index 3b15b118a..2001e1475 100644 --- a/lib/app/data/providers/isar_provider.dart +++ b/lib/app/data/providers/isar_provider.dart @@ -157,8 +157,8 @@ class IsarDb { guardianTimer INTEGER, guardian TEXT, isCall INTEGER, - ringOn INTEGER - + ringOn INTEGER, + challengeDuration INTEGER NOT NULL DEFAULT 15 ) '''); await db.execute(''' @@ -252,7 +252,7 @@ class IsarDb { final isarProvider = IsarDb(); final sql = await IsarDb().getAlarmSQLiteDatabase(); final db = await isarProvider.db; - + await db.writeTxn(() async { await db.alarmModels.put(alarmRecord); }); @@ -306,8 +306,8 @@ class IsarDb { static Future profileExists(String name) async { final isarProvider = IsarDb(); final db = await isarProvider.db; - final a = - await db.profileModels.filter().profileNameEqualTo(name).findFirst(); + final a = + await db.profileModels.filter().profileNameEqualTo(name).findFirst(); return a != null; } @@ -316,7 +316,7 @@ class IsarDb { final isarProvider = IsarDb(); final db = await isarProvider.db; final a = - await db.profileModels.filter().profileNameEqualTo(name).findFirst(); + await db.profileModels.filter().profileNameEqualTo(name).findFirst(); return a == null ? 'null' : a.isarId; } @@ -338,16 +338,16 @@ class IsarDb { final isarProvider = IsarDb(); final db = await isarProvider.db; final alarms = - await db.alarmModels.where().filter().alarmIDEqualTo(alarmID).findAll(); + await db.alarmModels.where().filter().alarmIDEqualTo(alarmID).findAll(); print('checkEmpty ${alarms[0].alarmID} ${alarms.isNotEmpty}'); return alarms.isNotEmpty; } static Future getLatestAlarm( - AlarmModel alarmRecord, - bool wantNextAlarm, - ) async { + AlarmModel alarmRecord, + bool wantNextAlarm, + ) async { int nowInMinutes = 0; final isarProvider = IsarDb(); final db = await isarProvider.db; @@ -426,7 +426,7 @@ class IsarDb { return aTimeUntilNextAlarm < bTimeUntilNextAlarm ? a : b; }); - + return closestAlarm; } } @@ -447,18 +447,18 @@ class IsarDb { ); } - + static Future fixMaxSnoozeCountInAlarms() async { final isarProvider = IsarDb(); final db = await isarProvider.db; final sql = await IsarDb().getAlarmSQLiteDatabase(); - - + + final alarms = await db.alarmModels.where().findAll(); - - + + for (final alarm in alarms) { - + await sql!.update( 'alarms', {'maxSnoozeCount': alarm.maxSnoozeCount}, @@ -629,7 +629,7 @@ class IsarDb { isarProvider.db.then((db) { final stream = db.timerModels.where().watch(fireImmediately: true); stream.listen( - (data) => controller.add(data), + (data) => controller.add(data), onError: (error) => controller.addError(error), onDone: () => controller.close(), ); @@ -659,7 +659,7 @@ class IsarDb { static Future getNumberOfTimers() async { final sql = await IsarDb().getTimerSQLiteDatabase(); List> x = - await sql!.rawQuery('SELECT COUNT (*) from timers'); + await sql!.rawQuery('SELECT COUNT (*) from timers'); sql.close(); int result = Sqflite.firstIntValue(x)!; return result; @@ -667,8 +667,8 @@ class IsarDb { // Ringtone functions static Future addCustomRingtone( - RingtoneModel customRingtone, - ) async { + RingtoneModel customRingtone, + ) async { try { final isarProvider = IsarDb(); final db = await isarProvider.db; @@ -797,4 +797,4 @@ class IsarDb { }); } } -} +} \ 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 0b0316c88..2e8b16256 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 @@ -51,10 +51,10 @@ class AddOrUpdateAlarmController extends GetxController { final shakeTimes = 0.obs; final isPedometerEnabled = false.obs; final numberOfSteps = 0.obs; - var ownerId = ''.obs; // id -> owner of the alarm - var ownerName = ''.obs; // name -> owner of the alarm - var userId = ''.obs; // id -> loggedin user - var userName = ''.obs; // name -> loggedin user + var ownerId = ''.obs; + var ownerName = ''.obs; + var userId = ''.obs; + var userName = ''.obs; final mutexLock = false.obs; var lastEditedUserId = ''.obs; final sharedUserIds = [].obs; @@ -62,14 +62,18 @@ class AddOrUpdateAlarmController extends GetxController { final RxMap offsetDetails = {}.obs; final offsetDuration = 0.obs; final isOffsetBefore = true.obs; + + // --- ADDED TIMER DURATION STATE --- + final challengeDuration = 15.obs; + var qrController = MobileScannerController( autoStart: false, detectionSpeed: DetectionSpeed.noDuplicates, facing: CameraFacing.back, torchEnabled: false, ); - final qrValue = ''.obs; // qrvalue stored in alarm - final detectedQrValue = ''.obs; // QR value detected by camera + final qrValue = ''.obs; + final detectedQrValue = ''.obs; final isQrEnabled = false.obs; final mathsSliderValue = 0.0.obs; @@ -82,8 +86,7 @@ class AddOrUpdateAlarmController extends GetxController { final daysRepeating = 'Never'.tr.obs; final weatherTypes = 'Off'.tr.obs; final selectedWeather = [].obs; - final repeatDays = - [false, false, false, false, false, false, false].obs; + final repeatDays = [false, false, false, false, false, false, false].obs; final RxBool isOneTime = true.obs; final RxString label = ''.obs; final RxInt snoozeDuration = 1.obs; @@ -109,30 +112,24 @@ class AddOrUpdateAlarmController extends GetxController { final RxList selectedEmails = [].obs; TextEditingController profileTextEditingController = TextEditingController(); - TextEditingController contactTextEditingController = TextEditingController(); - TextEditingController emailTextEditingController = TextEditingController(); final RxInt hours = 0.obs, minutes = 0.obs, meridiemIndex = 0.obs; final List meridiem = ['AM'.obs, 'PM'.obs]; - TextEditingController inputHrsController = TextEditingController(); TextEditingController inputMinutesController = TextEditingController(); - - + final isTimePicker = false.obs; final isAM = true.obs; int? _previousDisplayHour; Future> fetchUserDetailsForSharedUsers() async { List userDetails = []; - for (String userId in alarmRecord.value.sharedUserIds ?? []) { userDetails.add(await FirestoreDb.fetchUserDetails(userId)); } - return userDetails; } @@ -141,7 +138,6 @@ class AddOrUpdateAlarmController extends GetxController { RxBool isCustomSelected = false.obs; final RxBool isPlaying = false.obs; - // to check whether alarm data is updated or not Map initialValues = {}; Map changedFields = {}; @@ -205,11 +201,11 @@ class AddOrUpdateAlarmController extends GetxController { color: themeController.primaryTextColor.value, ), contentPadding: - const EdgeInsets.symmetric(vertical: 20, horizontal: 20), + const EdgeInsets.symmetric(vertical: 20, horizontal: 20), titlePadding: const EdgeInsets.only(top: 30, right: 40), content: const Text( 'This app requires permission to draw overlays,send notifications' - ' and Ignore batter optimization.', + ' and Ignore batter optimization.', ), actions: [ TextButton( @@ -236,7 +232,6 @@ class AddOrUpdateAlarmController extends GetxController { Get.back(); if (Platform.isAndroid) { - // Request overlay permission if (!(await Permission.systemAlertWindow.isGranted)) { final status = await Permission.systemAlertWindow.request(); if (!status.isGranted) { @@ -258,7 +253,6 @@ class AddOrUpdateAlarmController extends GetxController { } } - // Request notification permission if (!await Permission.notification.isGranted) { final status = await Permission.notification.request(); if (status != PermissionStatus.granted) { @@ -312,8 +306,8 @@ class AddOrUpdateAlarmController extends GetxController { child: Text( 'Cancel'.tr, style: Theme.of(context).textTheme.displaySmall!.copyWith( - color: kprimaryBackgroundColor, - ), + color: kprimaryBackgroundColor, + ), ), ), OutlinedButton( @@ -330,8 +324,8 @@ class AddOrUpdateAlarmController extends GetxController { child: Text( 'Leave'.tr, style: Theme.of(context).textTheme.displaySmall!.copyWith( - color: Colors.red, - ), + color: Colors.red, + ), ), ), ], @@ -361,23 +355,20 @@ class AddOrUpdateAlarmController extends GetxController { Future checkAndRequestPermission({bool? background}) async { if (!await FlLocation.isLocationServicesEnabled) { - // Location services are disabled. return false; } var locationPermission = await FlLocation.checkLocationPermission(); if (locationPermission == LocationPermission.deniedForever) { - // Cannot request runtime permission because location permission - // is denied forever. return false; } else if (locationPermission == LocationPermission.denied || - locationPermission == LocationPermission.whileInUse) { + locationPermission == LocationPermission.whileInUse) { bool? shouldAskPermission = await Get.defaultDialog( backgroundColor: themeController.secondaryBackgroundColor.value, barrierDismissible: false, title: 'Location Permission', contentPadding: - const EdgeInsets.symmetric(vertical: 20, horizontal: 20), + const EdgeInsets.symmetric(vertical: 20, horizontal: 20), titlePadding: const EdgeInsets.only(top: 30, right: 40), titleStyle: TextStyle( color: themeController.primaryTextColor.value, @@ -413,24 +404,20 @@ class AddOrUpdateAlarmController extends GetxController { ); if (shouldAskPermission == false) { - // User declined the permission request. return false; } - // Ask the user for location permission (must be LocationPermission.always). locationPermission = await FlLocation.requestLocationPermission(); if (locationPermission == LocationPermission.denied || locationPermission == LocationPermission.deniedForever || locationPermission == LocationPermission.whileInUse) return false; } - - // Location services has been enabled and permission have been granted. return true; } createAlarm(AlarmModel alarmData) async { if (isSharedAlarmEnabled.value == true) { alarmRecord.value = - await FirestoreDb.addAlarm(userModel.value, alarmData); + await FirestoreDb.addAlarm(userModel.value, alarmData); } else { alarmRecord.value = await IsarDb.addAlarm(alarmData); } @@ -450,95 +437,95 @@ class AddOrUpdateAlarmController extends GetxController { title: 'Scan a QR/Bar Code', titleStyle: Theme.of(Get.context!).textTheme.displaySmall, content: Obx( - () => Column( + () => Column( children: [ detectedQrValue.value.isEmpty ? SizedBox( - height: 300, - width: 300, - child: MobileScanner( - controller: qrController, - fit: BoxFit.cover, - onDetect: (capture) { - final List barcodes = capture.barcodes; - for (final barcode in barcodes) { - detectedQrValue.value = barcode.rawValue.toString(); - debugPrint(barcode.rawValue.toString()); - } - }, - ), - ) + height: 300, + width: 300, + child: MobileScanner( + controller: qrController, + fit: BoxFit.cover, + onDetect: (capture) { + final List barcodes = capture.barcodes; + for (final barcode in barcodes) { + detectedQrValue.value = barcode.rawValue.toString(); + debugPrint(barcode.rawValue.toString()); + } + }, + ), + ) : Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: Text(detectedQrValue.value), - ), + padding: const EdgeInsets.only(bottom: 15.0), + child: Text(detectedQrValue.value), + ), (detectedQrValue.value.isNotEmpty) ? Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(kprimaryColor), - ), - child: Text( - 'Save', - style: Theme.of(Get.context!) - .textTheme - .displaySmall! - .copyWith( - color: themeController.secondaryTextColor.value, - ), - ), - onPressed: () { - qrValue.value = detectedQrValue.value; - isQrEnabled.value = true; - Get.back(); - }, - ), - TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(kprimaryColor), - ), - child: Text( - 'Retake', - style: Theme.of(Get.context!) - .textTheme - .displaySmall! - .copyWith( - color: themeController.secondaryTextColor.value, - ), - ), - onPressed: () async { - qrController.dispose(); - restartQRCodeController(true); - }, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Save', + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: themeController.secondaryTextColor.value, + ), + ), + onPressed: () { + qrValue.value = detectedQrValue.value; + isQrEnabled.value = true; + Get.back(); + }, + ), + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Retake', + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: themeController.secondaryTextColor.value, + ), + ), + onPressed: () async { + qrController.dispose(); + restartQRCodeController(true); + }, + ), + if (isQrEnabled.value) + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + 'Disable', + style: Theme.of(Get.context!) + .textTheme + .displaySmall! + .copyWith( + color: + themeController.secondaryTextColor.value, ), - if (isQrEnabled.value) - TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(kprimaryColor), - ), - child: Text( - 'Disable', - style: Theme.of(Get.context!) - .textTheme - .displaySmall! - .copyWith( - color: - themeController.secondaryTextColor.value, - ), - ), - onPressed: () { - isQrEnabled.value = false; - qrValue.value = ''; - Get.back(); - }, - ), - ], - ) + ), + onPressed: () { + isQrEnabled.value = false; + qrValue.value = ''; + Get.back(); + }, + ), + ], + ) : const SizedBox(), ], ), @@ -561,7 +548,7 @@ class AddOrUpdateAlarmController extends GetxController { left: 10, ), contentPadding: - const EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 23), + const EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 23), content: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -574,13 +561,12 @@ class AddOrUpdateAlarmController extends GetxController { ], ), onCancel: () { - Get.back(); // Close the alert box + Get.back(); }, onConfirm: () async { - Get.back(); // Close the alert box + Get.back(); PermissionStatus permissionStatus = await Permission.camera.request(); if (permissionStatus.isGranted) { - // Permission granted, proceed with QR code scanning showQRDialog(); } }, @@ -589,25 +575,24 @@ class AddOrUpdateAlarmController extends GetxController { backgroundColor: MaterialStateProperty.all(kprimaryColor), ), child: Obx( - () => Text( + () => Text( 'OK', style: Theme.of(context).textTheme.displaySmall!.copyWith( - color: themeController.secondaryTextColor.value, - ), + color: themeController.secondaryTextColor.value, + ), ), ), onPressed: () async { - Get.back(); // Close the alert box + Get.back(); PermissionStatus permissionStatus = - await Permission.camera.request(); + await Permission.camera.request(); if (permissionStatus.isGranted) { - // Permission granted, proceed with QR code scanning showQRDialog(); } }, ), cancel: Obx( - () => TextButton( + () => TextButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all( themeController.primaryTextColor.value.withOpacity(0.5), @@ -616,11 +601,11 @@ class AddOrUpdateAlarmController extends GetxController { child: Text( 'Cancel', style: Theme.of(context).textTheme.displaySmall!.copyWith( - color: themeController.primaryTextColor.value, - ), + color: themeController.primaryTextColor.value, + ), ), onPressed: () { - Get.back(); // Close the alert box + Get.back(); }, ), ), @@ -631,7 +616,6 @@ class AddOrUpdateAlarmController extends GetxController { } restartQRCodeController(bool retake) async { - // Camera permission already granted, proceed with QR code scanning qrController = MobileScannerController( autoStart: true, detectionSpeed: DetectionSpeed.noDuplicates, @@ -642,26 +626,20 @@ class AddOrUpdateAlarmController extends GetxController { } updateAlarm(AlarmModel alarmData) async { - // Adding the ID's so it can update depending on the db if (isSharedAlarmEnabled.value == true) { - // Making sure the alarm wasn't suddenly updated to be an - // online (shared) alarm if (await IsarDb.doesAlarmExist(alarmRecord.value.alarmID) == false) { alarmData.firestoreId = alarmRecord.value.firestoreId; await FirestoreDb.updateAlarm(alarmRecord.value.ownerId, alarmData); } else { - // Deleting alarm on IsarDB to ensure no duplicate entry await IsarDb.deleteAlarm(alarmRecord.value.isarId); createAlarm(alarmData); } } else { - // Making sure the alarm wasn't suddenly updated to be an offline alarm print('aid = ${alarmRecord.value.alarmID}'); if (await IsarDb.doesAlarmExist(alarmRecord.value.alarmID) == true) { alarmData.isarId = alarmRecord.value.isarId; await IsarDb.updateAlarm(alarmData); } else { - // Deleting alarm on firestore to ensure no duplicate entry await FirestoreDb.deleteAlarm( userModel.value, alarmRecord.value.firestoreId!, @@ -699,7 +677,6 @@ class AddOrUpdateAlarmController extends GetxController { } IsarDb.loadDefaultRingtones(); - // listens to the userModel declared in homeController and updates on signup event homeController.userModel.stream.listen((UserModel? user) { userModel.value = user; if (user != null) { @@ -717,7 +694,7 @@ class AddOrUpdateAlarmController extends GetxController { guardian.value = alarmRecord.value.guardian; guardianTimer.value = alarmRecord.value.guardianTimer; isActivityMonitorenabled.value = - alarmRecord.value.isActivityEnabled ? 1 : 0; + alarmRecord.value.isActivityEnabled ? 1 : 0; snoozeDuration.value = alarmRecord.value.snoozeDuration; maxSnoozeCount.value = alarmRecord.value.maxSnoozeCount; gradient.value = alarmRecord.value.gradient; @@ -731,7 +708,6 @@ class AddOrUpdateAlarmController extends GetxController { showMotivationalQuote.value = alarmRecord.value.showMotivationalQuote; sharedUserIds.value = alarmRecord.value.sharedUserIds!; - // Reinitializing all values here selectedTime.value = Utils.timeOfDayToDateTime( Utils.stringToTimeOfDay(alarmRecord.value.alarmTime), ); @@ -751,7 +727,7 @@ class AddOrUpdateAlarmController extends GetxController { meridiemIndex.value = 0; } } - // Shows the "Rings in" time + timeToAlarm.value = Utils.timeUntilAlarm( TimeOfDay.fromDateTime(selectedTime.value), repeatDays, @@ -759,17 +735,14 @@ class AddOrUpdateAlarmController extends GetxController { ); repeatDays.value = alarmRecord.value.days; - // Shows the selected days in UI daysRepeating.value = Utils.getRepeatDays(repeatDays); - // Setting the old values for all the auto dismissal isActivityenabled.value = alarmRecord.value.isActivityEnabled; useScreenActivity.value = alarmRecord.value.isActivityEnabled; activityInterval.value = alarmRecord.value.activityInterval ~/ 60000; isLocationEnabled.value = alarmRecord.value.isLocationEnabled; selectedPoint.value = Utils.stringToLatLng(alarmRecord.value.location); - // Shows the marker in UI markersList.add( Marker( point: selectedPoint.value, @@ -787,7 +760,7 @@ class AddOrUpdateAlarmController extends GetxController { isMathsEnabled.value = alarmRecord.value.isMathsEnabled; numMathsQuestions.value = alarmRecord.value.numMathsQuestions; mathsDifficulty.value = - Difficulty.values[alarmRecord.value.mathsDifficulty]; + Difficulty.values[alarmRecord.value.mathsDifficulty]; mathsSliderValue.value = alarmRecord.value.mathsDifficulty.toDouble(); isShakeEnabled.value = alarmRecord.value.isShakeEnabled; @@ -800,12 +773,13 @@ class AddOrUpdateAlarmController extends GetxController { qrValue.value = alarmRecord.value.qrValue; detectedQrValue.value = alarmRecord.value.qrValue; + // --- LOAD SAVED TIMER DURATION --- + challengeDuration.value = alarmRecord.value.challengeDuration; + alarmID = alarmRecord.value.alarmID == '' ? const Uuid().v4() : alarmRecord.value.alarmID; - // if alarmRecord is null or alarmRecord.ownerId is null, - // then assign the current logged-in user as the owner. if (alarmRecord.value.ownerId.isEmpty) { ownerId.value = userId.value; ownerName.value = userName.value; @@ -832,7 +806,6 @@ class AddOrUpdateAlarmController extends GetxController { .value.offsetDetails![userModel.value!.id]['isOffsetBefore']; } - // Set lock only if its not locked if (isSharedAlarmEnabled.value == true && alarmRecord.value.mutexLock == false) { alarmRecord.value.mutexLock = true; @@ -864,12 +837,11 @@ class AddOrUpdateAlarmController extends GetxController { } timeToAlarm.value = Utils.timeUntilAlarm( - TimeOfDay.fromDateTime(selectedTime.value), - repeatDays, - selectedDate.value + TimeOfDay.fromDateTime(selectedTime.value), + repeatDays, + selectedDate.value ); - // store initial values of the variables initialValues.addAll({ 'selectedTime': selectedTime.value, 'daysRepeating': daysRepeating.value, @@ -886,7 +858,7 @@ class AddOrUpdateAlarmController extends GetxController { 'activityInterval': activityInterval.value, 'weatherTypes': weatherTypes.value, 'location': - '${selectedPoint.value.latitude} ${selectedPoint.value.longitude}', + '${selectedPoint.value.latitude} ${selectedPoint.value.longitude}', 'shakeTimes': shakeTimes.value, 'qrValue': qrValue.value, 'mathsDifficulty': mathsDifficulty.value, @@ -896,6 +868,7 @@ class AddOrUpdateAlarmController extends GetxController { 'isSharedAlarmEnabled': isSharedAlarmEnabled.value, 'offsetDuration': offsetDuration.value, 'isOffsetBefore': isOffsetBefore.value, + 'challengeDuration': challengeDuration.value, // --- TRACK THIS AS WELL --- }); addListeners(); @@ -905,22 +878,18 @@ class AddOrUpdateAlarmController extends GetxController { weatherApiKeyExists.value = true; } - // If there's an argument sent, we are in update mode - - isTimePicker.value = true; initTimeTextField(); } void addListeners() { - // Updating UI to show time to alarm selectedTime.listen((time) { debugPrint('CHANGED CHANGED CHANGED CHANGED'); timeToAlarm.value = Utils.timeUntilAlarm(TimeOfDay.fromDateTime(time), repeatDays, selectedDate.value); _compareAndSetChange('selectedTime', time); }); - + selectedDate.listen((date) { debugPrint('CHANGED CHANGED CHANGED CHANGED'); timeToAlarm.value = @@ -928,7 +897,6 @@ class AddOrUpdateAlarmController extends GetxController { _compareAndSetChange('selectedTime', date); }); - //Updating UI to show repeated days repeatDays.listen((days) { daysRepeating.value = Utils.getRepeatDays(days); _compareAndSetChange('daysRepeating', daysRepeating.value); @@ -946,7 +914,6 @@ class AddOrUpdateAlarmController extends GetxController { setupListener(showMotivationalQuote, 'showMotivationalQuote'); setupListener(activityInterval, 'activityInterval'); - // Updating UI to show weather types selectedWeather.listen((weather) { if (weather.toList().isEmpty) { isWeatherEnabled.value = false; @@ -955,16 +922,13 @@ class AddOrUpdateAlarmController extends GetxController { } weatherTypes.value = Utils.getFormattedWeatherTypes(weather); _compareAndSetChange('weatherTypes', weatherTypes.value); - // if location based is disabled and weather based is disabled, reset location if (weatherTypes.value == 'Off' && !isLocationEnabled.value) { selectedPoint.value = LatLng(0, 0); } }); - // Adding to markers list, to display on map - // (MarkersLayer takes only List) selectedPoint.listen( - (point) { + (point) { selectedPoint.value = point; markersList.clear(); markersList.add( @@ -984,7 +948,6 @@ class AddOrUpdateAlarmController extends GetxController { }, ); - // reset selectedPoint to default value if isLocationEnabled is false and weather based is off isLocationEnabled.listen((value) { if (!value && weatherTypes.value == 'Off') { selectedPoint.value = LatLng(0, 0); @@ -1001,17 +964,15 @@ class AddOrUpdateAlarmController extends GetxController { setupListener(isSharedAlarmEnabled, 'isSharedAlarmEnabled'); setupListener(offsetDuration, 'offsetDuration'); setupListener(isOffsetBefore, 'isOffsetBefore'); + setupListener(challengeDuration, 'challengeDuration'); // --- LISTENER ADDED --- } - // adds listener to rxVar variable void setupListener(Rx rxVar, String fieldName) { rxVar.listen((value) { _compareAndSetChange(fieldName, value); }); } - // if initialValues map contains fieldName and newValue is equal to currentValue - // then set changeFields map field to true void _compareAndSetChange(String fieldName, dynamic currentValue) { if (initialValues.containsKey(fieldName)) { bool hasChanged = initialValues[fieldName] != currentValue; @@ -1027,10 +988,6 @@ class AddOrUpdateAlarmController extends GetxController { playingSystemRingtoneUri.value = ''; if (Get.arguments == null) { - // Shared alarm was not suddenly enabled, so we can update doc - // on firestore - // We also make sure the doc was not already locked - // If it was suddenly enabled, it will be created newly anyway if (isSharedAlarmEnabled.value == true && alarmRecord.value.isSharedAlarmEnabled == true && alarmRecord.value.mutexLock == false) { @@ -1047,9 +1004,6 @@ class AddOrUpdateAlarmController extends GetxController { String ownerId = ''; String ownerName = ''; - // if alarmRecord is null or alarmRecord.ownerId is null, - // then assign the current logged-in user as the owner. - if (alarmRecord.value.ownerId.isEmpty) { ownerId = userId.value; ownerName = userName.value; @@ -1067,7 +1021,7 @@ class AddOrUpdateAlarmController extends GetxController { isOneTime: isOneTime.value, deleteAfterGoesOff: deleteAfterGoesOff.value, mainAlarmTime: - Utils.timeOfDayToString(TimeOfDay.fromDateTime(selectedTime.value)), + Utils.timeOfDayToString(TimeOfDay.fromDateTime(selectedTime.value)), offsetDetails: offsetDetails, sharedUserIds: sharedUserIds, lastEditedUserId: lastEditedUserId.value, @@ -1078,12 +1032,12 @@ class AddOrUpdateAlarmController extends GetxController { activityInterval: activityInterval.value * 60000, days: repeatDays.toList(), alarmTime: - Utils.timeOfDayToString(TimeOfDay.fromDateTime(selectedTime.value)), + Utils.timeOfDayToString(TimeOfDay.fromDateTime(selectedTime.value)), intervalToAlarm: - Utils.getMillisecondsToAlarm(DateTime.now(), selectedTime.value), + Utils.getMillisecondsToAlarm(DateTime.now(), selectedTime.value), isActivityEnabled: isActivityenabled.value, minutesSinceMidnight: - Utils.timeOfDayToInt(TimeOfDay.fromDateTime(selectedTime.value)), + Utils.timeOfDayToInt(TimeOfDay.fromDateTime(selectedTime.value)), isLocationEnabled: isLocationEnabled.value, weatherTypes: Utils.getIntFromWeatherTypes(selectedWeather.toList()), isWeatherEnabled: isWeatherEnabled.value, @@ -1111,6 +1065,7 @@ class AddOrUpdateAlarmController extends GetxController { guardian: guardian.value, isCall: isCall.value, ringOn: isFutureDate.value, + challengeDuration: challengeDuration.value, // --- PASS IT HERE --- ); } @@ -1155,10 +1110,8 @@ class AddOrUpdateAlarmController extends GetxController { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String ringtonesDirectoryPath = '${documentsDirectory.path}/ringtones'; - // Create the ringtones directory if it doesn't exist Directory(ringtonesDirectoryPath).createSync(recursive: true); - // Copy the picked audio files to the ringtones directory File pickedFile = File(filePath); String newFilePath = '$ringtonesDirectoryPath/${pickedFile.uri.pathSegments.last}'; @@ -1179,7 +1132,7 @@ class AddOrUpdateAlarmController extends GetxController { String? filePath = customRingtoneResult.files.single.path; String? savedFilePath = - await saveToDocumentsDirectory(filePath: filePath!); + await saveToDocumentsDirectory(filePath: filePath!); if (savedFilePath != null) { RingtoneModel customRingtone = RingtoneModel( @@ -1202,7 +1155,7 @@ class AddOrUpdateAlarmController extends GetxController { Future> getAllCustomRingtoneNames() async { try { List customRingtones = - await IsarDb.getAllCustomRingtones(); + await IsarDb.getAllCustomRingtones(); return customRingtones .map((customRingtone) => customRingtone.ringtoneName) @@ -1220,7 +1173,7 @@ class AddOrUpdateAlarmController extends GetxController { try { int customRingtoneId = AudioUtils.fastHash(ringtoneName); RingtoneModel? customRingtone = - await IsarDb.getCustomRingtone(customRingtoneId: customRingtoneId); + await IsarDb.getCustomRingtone(customRingtoneId: customRingtoneId); if (customRingtone != null) { int currentCounterOfUsage = customRingtone.currentCounterOfUsage; @@ -1288,27 +1241,27 @@ class AddOrUpdateAlarmController extends GetxController { datePicker(BuildContext context) async { selectedDate.value = (await showDatePicker( - builder: (BuildContext context, Widget? child) { - return Theme( - data: themeController.currentTheme.value == ThemeMode.light - ? ThemeData.light().copyWith( - colorScheme: const ColorScheme.light( - primary: kprimaryColor, - ), - ) - : ThemeData.dark().copyWith( - colorScheme: const ColorScheme.dark( - primary: kprimaryColor, - ), - ), - child: child!, - ); - }, - context: context, - currentDate: selectedDate.value, - firstDate: DateTime.now(), - lastDate: DateTime.now().add(const Duration(days: 355)), - )) ?? + builder: (BuildContext context, Widget? child) { + return Theme( + data: themeController.currentTheme.value == ThemeMode.light + ? ThemeData.light().copyWith( + colorScheme: const ColorScheme.light( + primary: kprimaryColor, + ), + ) + : ThemeData.dark().copyWith( + colorScheme: const ColorScheme.dark( + primary: kprimaryColor, + ), + ), + child: child!, + ); + }, + context: context, + currentDate: selectedDate.value, + firstDate: DateTime.now(), + lastDate: DateTime.now().add(const Duration(days: 355)), + )) ?? DateTime.now(); isFutureDate.value = selectedDate.value.difference(DateTime.now()).inHours > 0; @@ -1365,66 +1318,66 @@ class AddOrUpdateAlarmController extends GetxController { } profileModel = ProfileModel( - profileName: profileTextEditingController.text, - deleteAfterGoesOff: deleteAfterGoesOff.value, - snoozeDuration: snoozeDuration.value, - volMax: volMax.value, - volMin: volMin.value, - gradient: gradient.value, - offsetDetails: offsetDetails, - label: label.value, - note: note.value, - showMotivationalQuote: showMotivationalQuote.value, - isOneTime: isOneTime.value, - lastEditedUserId: lastEditedUserId.value, - mutexLock: mutexLock.value, - ownerId: ownerId.value, - ownerName: ownerName.value, - activityInterval: activityInterval.value * 60000, - days: repeatDays.toList(), - intervalToAlarm: Utils.getMillisecondsToAlarm( - DateTime.now(), - selectedTime.value, - ), - isActivityEnabled: isActivityenabled.value, - minutesSinceMidnight: Utils.timeOfDayToInt( - TimeOfDay.fromDateTime( + profileName: profileTextEditingController.text, + deleteAfterGoesOff: deleteAfterGoesOff.value, + snoozeDuration: snoozeDuration.value, + volMax: volMax.value, + volMin: volMin.value, + gradient: gradient.value, + offsetDetails: offsetDetails, + label: label.value, + note: note.value, + showMotivationalQuote: showMotivationalQuote.value, + isOneTime: isOneTime.value, + lastEditedUserId: lastEditedUserId.value, + mutexLock: mutexLock.value, + ownerId: ownerId.value, + ownerName: ownerName.value, + activityInterval: activityInterval.value * 60000, + days: repeatDays.toList(), + intervalToAlarm: Utils.getMillisecondsToAlarm( + DateTime.now(), selectedTime.value, ), - ), - isLocationEnabled: isLocationEnabled.value, - weatherTypes: Utils.getIntFromWeatherTypes( - selectedWeather.toList(), - ), - isWeatherEnabled: isWeatherEnabled.value, - location: Utils.geoPointToString( - Utils.latLngToGeoPoint( - selectedPoint.value, + isActivityEnabled: isActivityenabled.value, + minutesSinceMidnight: Utils.timeOfDayToInt( + TimeOfDay.fromDateTime( + selectedTime.value, + ), ), - ), - isSharedAlarmEnabled: isSharedAlarmEnabled.value, - isQrEnabled: isQrEnabled.value, - qrValue: qrValue.value, - isMathsEnabled: isMathsEnabled.value, - numMathsQuestions: numMathsQuestions.value, - mathsDifficulty: mathsDifficulty.value.index, - isShakeEnabled: isShakeEnabled.value, - shakeTimes: shakeTimes.value, - isPedometerEnabled: isPedometerEnabled.value, - numberOfSteps: numberOfSteps.value, - ringtoneName: customRingtoneName.value, - activityMonitor: isActivityMonitorenabled.value, - alarmDate: selectedDate.value.toString().substring(0, 11), - isGuardian: isGuardian.value, - guardianTimer: guardianTimer.value, - guardian: guardian.value, - isCall: isCall.value, - ringOn: isFutureDate.value, + isLocationEnabled: isLocationEnabled.value, + weatherTypes: Utils.getIntFromWeatherTypes( + selectedWeather.toList(), + ), + isWeatherEnabled: isWeatherEnabled.value, + location: Utils.geoPointToString( + Utils.latLngToGeoPoint( + selectedPoint.value, + ), + ), + isSharedAlarmEnabled: isSharedAlarmEnabled.value, + isQrEnabled: isQrEnabled.value, + qrValue: qrValue.value, + isMathsEnabled: isMathsEnabled.value, + numMathsQuestions: numMathsQuestions.value, + mathsDifficulty: mathsDifficulty.value.index, + isShakeEnabled: isShakeEnabled.value, + shakeTimes: shakeTimes.value, + isPedometerEnabled: isPedometerEnabled.value, + numberOfSteps: numberOfSteps.value, + ringtoneName: customRingtoneName.value, + activityMonitor: isActivityMonitorenabled.value, + alarmDate: selectedDate.value.toString().substring(0, 11), + isGuardian: isGuardian.value, + guardianTimer: guardianTimer.value, + guardian: guardian.value, + isCall: isCall.value, + ringOn: isFutureDate.value, ); if (homeController.isProfileUpdate.value) { var profileId = - await IsarDb.profileId(homeController.selectedProfile.value); + await IsarDb.profileId(homeController.selectedProfile.value); print(profileId); if (profileId != 'null') profileModel.isarId = profileId; print(profileModel.isarId); @@ -1465,16 +1418,16 @@ class AddOrUpdateAlarmController extends GetxController { initTimeTextField(); } } - + void changePeriod(String period) { isAM.value = period == 'AM'; } - + void confirmTimeInput() { setTime(); changeDatePicker(); } - + void toggleIfAtBoundary() { if (!settingsController.is24HrsEnabled.value) { final rawHourText = inputHrsController.text.trim(); @@ -1498,7 +1451,7 @@ class AddOrUpdateAlarmController extends GetxController { _previousDisplayHour = newHour; } } - + void setTime() { selectedTime.value = selectedTime.value; toggleIfAtBoundary(); @@ -1507,7 +1460,7 @@ class AddOrUpdateAlarmController extends GetxController { int hour = int.parse(inputHrsController.text); if (!settingsController.is24HrsEnabled.value) { if (isAM.value) { - if (hour == 12) hour = 0; + if (hour == 12) hour = 0; } else { if (hour != 12) hour = hour + 12; } @@ -1562,22 +1515,21 @@ class AddOrUpdateAlarmController extends GetxController { } return value; } - + void initTimeTextField() { isAM.value = selectedTime.value.hour < 12; - + inputHrsController.text = settingsController.is24HrsEnabled.value ? selectedTime.value.hour.toString() : (selectedTime.value.hour == 0 - ? '12' - : (selectedTime.value.hour > 12 - ? (selectedTime.value.hour - 12).toString() - : selectedTime.value.hour.toString())); + ? '12' + : (selectedTime.value.hour > 12 + ? (selectedTime.value.hour - 12).toString() + : selectedTime.value.hour.toString())); inputMinutesController.text = selectedTime.value.minute.toString().padLeft(2, '0'); } int orderedCountryCode(Country countryA, Country countryB) { - // `??` for null safety of 'dialCode' String dialCodeA = countryA.dialCode ?? '0'; String dialCodeB = countryB.dialCode ?? '0'; @@ -1605,4 +1557,4 @@ class LimitRange extends TextInputFormatter { return newValue; } } -} +} \ No newline at end of file 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 d6c9bbf2b..6cc00a15f 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 @@ -44,8 +44,6 @@ class AddOrUpdateAlarmView extends GetView { Widget build(BuildContext context) { final double width = MediaQuery.of(context).size.width; final double height = MediaQuery.of(context).size.height; - // var width = Get.width; - // var height = Get.height; return PopScope( canPop: false, onPopInvoked: (bool didPop) { @@ -55,12 +53,10 @@ class AddOrUpdateAlarmView extends GetView { controller.checkUnsavedChangesAndNavigate(context); }, child: Scaffold( - // floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, - appBar: PreferredSize( preferredSize: Size.fromHeight(height * 0.08), child: Obx( - () => AppBar( + () => AppBar( backgroundColor: themeController.primaryBackgroundColor.value, elevation: 0.0, centerTitle: true, @@ -68,18 +64,18 @@ class AddOrUpdateAlarmView extends GetView { title: (controller.mutexLock.value == true) ? const Text('') : controller.homeController.isProfile.value - ? const Text('Edit Profile') - : Obx( - () => Text( - 'Rings in @timeToAlarm'.trParams( - { - 'timeToAlarm': - controller.timeToAlarm.value.toString(), - }, - ), - style: Theme.of(context).textTheme.titleSmall, - ), - ), + ? const Text('Edit Profile') + : Obx( + () => Text( + 'Rings in @timeToAlarm'.trParams( + { + 'timeToAlarm': + controller.timeToAlarm.value.toString(), + }, + ), + style: Theme.of(context).textTheme.titleSmall, + ), + ), ), ), ), @@ -89,1110 +85,1142 @@ class AddOrUpdateAlarmView extends GetView { child: SingleChildScrollView( child: (controller.mutexLock.value == true) ? Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Padding( - padding: const EdgeInsets.all(20.0), - child: Obx( - () => Text( - 'Uh-oh!'.tr, - style: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - color: themeController - .primaryDisabledTextColor.value, - ), - ), - ), - ), - SvgPicture.asset( - 'assets/images/locked.svg', - height: height * 0.24, - width: width * 0.5, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: const EdgeInsets.all(20.0), + child: Obx( + () => Text( + 'Uh-oh!'.tr, + style: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + color: themeController + .primaryDisabledTextColor.value, ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Obx( - () => Text( - // 'This alarm is currently being edited!', - 'alarmEditing'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController - .primaryDisabledTextColor.value, - ), - ), - ), + ), + ), + ), + SvgPicture.asset( + 'assets/images/locked.svg', + height: height * 0.24, + width: width * 0.5, + ), + Padding( + padding: const EdgeInsets.all(20.0), + child: Obx( + () => Text( + 'alarmEditing'.tr, + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + color: themeController + .primaryDisabledTextColor.value, ), - TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(kprimaryColor), - ), - child: Obx( - () => Text( - 'Go back'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController - .secondaryTextColor.value, - ), - ), - ), - onPressed: () { - Utils.hapticFeedback(); - Get.back(); - }, + ), + ), + ), + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), + ), + child: Obx( + () => Text( + 'Go back'.tr, + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + color: themeController + .secondaryTextColor.value, ), - ], + ), ), - ) + onPressed: () { + Utils.hapticFeedback(); + Get.back(); + }, + ), + ], + ), + ) : Column( - children: [ - !controller.homeController.isProfile.value - ? Padding( - padding: EdgeInsets.only( - top: height * 0.02, - left: width * 0.04, - right: width * 0.04, - ), - child: Obx( - () => Container( - decoration: BoxDecoration( - color: themeController - .secondaryBackgroundColor.value, - borderRadius: - BorderRadius.circular(500), - ), - height: height * 0.25, - child: Obx( - () { - return InkWell( - onTap: () { - Utils.hapticFeedback(); - controller.changeDatePicker(); - }, - child: controller - .isTimePicker.value - ? Obx( - () => Row( - mainAxisAlignment: - MainAxisAlignment - .center, - crossAxisAlignment: - CrossAxisAlignment - .center, - children: [ - NumberPicker( - minValue: - settingsController - .is24HrsEnabled - .value - ? 0 - : 1, - maxValue: - settingsController - .is24HrsEnabled - .value - ? 23 - : 12, - value: controller - .hours.value, - onChanged: (value) { - Utils - .hapticFeedback(); - controller.hours - .value = value; - - // Update the selected time with proper format handling - int hourValue; - if (settingsController - .is24HrsEnabled - .value) { - // In 24-hour mode, use the value directly - hourValue = value; - } else { - // In 12-hour mode, convert based on AM/PM - hourValue = - controller - .convert24( - value, - controller - .meridiemIndex - .value, - ); - } + children: [ + !controller.homeController.isProfile.value + ? Padding( + padding: EdgeInsets.only( + top: height * 0.02, + left: width * 0.04, + right: width * 0.04, + ), + child: Obx( + () => Container( + decoration: BoxDecoration( + color: themeController + .secondaryBackgroundColor.value, + borderRadius: + BorderRadius.circular(500), + ), + height: height * 0.25, + child: Obx( + () { + return InkWell( + onTap: () { + Utils.hapticFeedback(); + controller.changeDatePicker(); + }, + child: controller + .isTimePicker.value + ? Obx( + () => Row( + mainAxisAlignment: + MainAxisAlignment + .center, + crossAxisAlignment: + CrossAxisAlignment + .center, + children: [ + NumberPicker( + minValue: + settingsController + .is24HrsEnabled + .value + ? 0 + : 1, + maxValue: + settingsController + .is24HrsEnabled + .value + ? 23 + : 12, + value: controller + .hours.value, + onChanged: (value) { + Utils + .hapticFeedback(); + controller.hours + .value = value; - controller - .selectedTime - .value = - DateTime( - controller - .selectedTime - .value - .year, - controller - .selectedTime - .value - .month, - controller - .selectedTime - .value - .day, - hourValue, - controller - .selectedTime - .value - .minute, - ); + int hourValue; + if (settingsController + .is24HrsEnabled + .value) { + hourValue = value; + } else { + hourValue = + controller + .convert24( + value, + controller + .meridiemIndex + .value, + ); + } - // Update text controllers to reflect current format - controller - .inputHrsController - .text = - controller - .hours.value - .toString(); - controller - .inputMinutesController - .text = - controller - .minutes - .value - .toString(); + controller + .selectedTime + .value = + DateTime( + controller + .selectedTime + .value + .year, + controller + .selectedTime + .value + .month, + controller + .selectedTime + .value + .day, + hourValue, + controller + .selectedTime + .value + .minute, + ); - // Only update period for 12-hour format - if (!settingsController - .is24HrsEnabled - .value) { - controller - .changePeriod( - controller.meridiemIndex - .value == - 0 - ? 'AM' - : 'PM', - ); - } + controller + .inputHrsController + .text = + controller + .hours.value + .toString(); + controller + .inputMinutesController + .text = + controller + .minutes + .value + .toString(); - controller - .setTime(); - }, - infiniteLoop: true, - itemWidth: - width * 0.17, - zeroPad: true, - selectedTextStyle: - Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontSize: controller - .homeController - .scalingFactor * - 40, - fontWeight: - FontWeight - .bold, - color: - kprimaryColor, - ), - textStyle: Theme.of( - context) - .textTheme - .displayMedium! - .copyWith( - fontSize: controller - .homeController - .scalingFactor * - 20, - color: themeController - .primaryDisabledTextColor - .value, - ), - ), - Padding( - padding: EdgeInsets - .symmetric( - horizontal: - width * 0.02, - ), - child: Text( - ':', - style: Theme.of( - context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: - FontWeight - .bold, - color: themeController - .primaryDisabledTextColor - .value, - ), - ), - ), - NumberPicker( - minValue: 0, - maxValue: 59, - value: controller - .minutes.value, - onChanged: (value) { - Utils - .hapticFeedback(); - controller.minutes - .value = value; - controller - .selectedTime - .value = - DateTime( - controller - .selectedTime - .value - .year, - controller - .selectedTime - .value - .month, - controller - .selectedTime - .value - .day, - controller - .selectedTime - .value - .hour, - controller.minutes - .value, - ); - controller - .inputHrsController - .text = - controller - .hours.value - .toString(); - controller - .inputMinutesController - .text = - controller - .minutes - .value - .toString(); - controller - .changePeriod( - controller.meridiemIndex - .value == - 0 - ? 'AM' - : 'PM', - ); - }, - infiniteLoop: true, - itemWidth: - width * 0.17, - zeroPad: true, - selectedTextStyle: - Theme.of(context) - .textTheme - .displayLarge! - .copyWith( - fontSize: controller - .homeController - .scalingFactor * - 40, - fontWeight: - FontWeight - .bold, - color: - kprimaryColor, - ), - textStyle: Theme.of( - context) - .textTheme - .displayMedium! - .copyWith( - fontSize: controller - .homeController - .scalingFactor * - 20, - color: themeController - .primaryDisabledTextColor - .value, - ), - ), - Visibility( - visible: - settingsController - .is24HrsEnabled - .value - ? false - : true, - child: Padding( - padding: EdgeInsets - .symmetric( - horizontal: - width * 0.02, - ), - child: Text( - ':', - style: Theme.of( - context) - .textTheme - .displayLarge! - .copyWith( - fontWeight: - FontWeight - .bold, - color: themeController - .primaryDisabledTextColor - .value, - ), - ), - ), - ), - Visibility( - visible: - settingsController - .is24HrsEnabled - .value - ? false - : true, - child: NumberPicker( - minValue: 0, - maxValue: 1, - value: controller - .meridiemIndex - .value, - onChanged: (value) { - Utils - .hapticFeedback(); - value == 0 - ? controller - .meridiemIndex - .value = 0 - : controller - .meridiemIndex - .value = 1; - controller - .selectedTime - .value = - DateTime( - controller - .selectedTime - .value - .year, - controller - .selectedTime - .value - .month, - controller - .selectedTime - .value - .day, - controller - .convert24( - controller - .hours - .value, - controller - .meridiemIndex - .value, - ), - controller - .minutes - .value, - ); - controller - .inputHrsController - .text = - controller - .hours - .value - .toString(); - controller - .inputMinutesController - .text = - controller - .minutes - .value - .toString(); - controller - .changePeriod( - controller.meridiemIndex - .value == - 0 - ? 'AM' - : 'PM', - ); - }, - textMapper: - (numberText) { - return controller - .meridiem[ - int.parse( - numberText, - )] - .value; - }, - itemWidth: - width * 0.2, - selectedTextStyle: - Theme.of( - context) - .textTheme - .displayLarge! - .copyWith( - fontSize: - Utils.getFontSize( - context), - fontWeight: - FontWeight - .bold, - color: - kprimaryColor, - ), - textStyle: Theme.of( - context) - .textTheme - .displayMedium! - .copyWith( - fontSize: Utils - .getFontSize( - context), - color: themeController - .primaryDisabledTextColor - .value, - ), - ), - ), - ], - ), - ) - : Row( - mainAxisAlignment: - MainAxisAlignment - .center, - children: [ - SizedBox( - width: 80, - child: TextField( - onChanged: (_) { - if (int.parse(controller - .inputHrsController - .text) == - 12 && - int.parse(controller - .inputMinutesController - .text) == - 0) { - controller - .isAM - .toggle(); - } - controller - .setTime(); - }, - decoration: - const InputDecoration( - hintText: 'HH', - border: InputBorder - .none, - ), - textAlign: - TextAlign.center, - controller: - controller - .inputHrsController, - keyboardType: - TextInputType - .number, - inputFormatters: [ - FilteringTextInputFormatter - .allow(RegExp( - '[0-9]')), - LengthLimitingTextInputFormatter( - 2), - LimitRange( - settingsController.is24HrsEnabled.value ? 0 : 1, - settingsController.is24HrsEnabled.value ? 23 : 12, - ), - ], - ), - ), - SizedBox( - width: 16, - child: Text( - ':', - textAlign: - TextAlign.center, - style: - Theme.of(context) - .textTheme - .titleMedium, - ), - ), - SizedBox( - width: 80, - child: TextField( - onChanged: (_) { - controller - .setTime(); - }, - decoration: - const InputDecoration( - hintText: 'MM', - border: InputBorder - .none, - ), - textAlign: - TextAlign.center, - controller: - controller - .inputMinutesController, - keyboardType: - TextInputType - .number, - inputFormatters: [ - FilteringTextInputFormatter - .allow( - RegExp( - '[1,2,3,4,5,6,7,8,9,0]', - ), - ), - LengthLimitingTextInputFormatter( - 2, - ), - LimitRange(00, 59), - ], - ), - ), - const SizedBox( - width: 16, - ), - Visibility( - visible: - !settingsController - .is24HrsEnabled - .value, - child: DropdownButton( - underline: - Container(), - value: - controller - .isAM - .value - ? 'AM' - : 'PM', - dropdownColor: - themeController - .primaryBackgroundColor - .value, - items: [ - 'AM', - 'PM' - ].map( - (String period) { - return DropdownMenuItem< - String>( - value: period, - child: - Text(period), - ); - }).toList(), - onChanged: - (getPeriod) { - controller - .changePeriod( - getPeriod!); + if (!settingsController + .is24HrsEnabled + .value) { + controller + .changePeriod( + controller.meridiemIndex + .value == + 0 + ? 'AM' + : 'PM', + ); + } - controller - .setTime(); - }, - ), - ), - const SizedBox( - width: 12, - ), - Visibility( - visible: - controller - .isTimePicker - .isFalse, - child: InkWell( - onTap: () { - Utils - .hapticFeedback(); - controller - .confirmTimeInput(); - }, - child: Container( - decoration: - BoxDecoration( - borderRadius: - BorderRadius - .circular( - 50.0, - ), - border: - Border.all( - color: - kprimaryColor, - width: 1.0, - ), - ), - padding: - const EdgeInsets - .all(5.0), - child: const Icon( - Icons.done, - color: - kprimaryColor, - ), - ), - ), - ), - ], - ), - ); + controller + .setTime(); }, + infiniteLoop: true, + itemWidth: + width * 0.17, + zeroPad: true, + selectedTextStyle: + Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontSize: controller + .homeController + .scalingFactor * + 40, + fontWeight: + FontWeight + .bold, + color: + kprimaryColor, + ), + textStyle: Theme.of( + context) + .textTheme + .displayMedium! + .copyWith( + fontSize: controller + .homeController + .scalingFactor * + 20, + color: themeController + .primaryDisabledTextColor + .value, + ), ), - ), - ), - ) - : Obx( - () => Padding( - padding: const EdgeInsets.all(16.0), - child: TextField( - decoration: InputDecoration( - hintText: 'Profile Name', - fillColor: controller.themeController - .secondaryBackgroundColor.value, - filled: true, - ), - controller: controller - .profileTextEditingController, - ), - ), - ), - SettingSelector(), - Obx( - () => controller.alarmSettingType.value == 0 - ? Column( - children: [ - AlarmDateTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - RepeatTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - Obx( - () => (!controller.repeatDays.every( - (element) => element == false)) - ? RepeatOnceTile( - controller: controller, - themeController: - themeController, - ) - : const SizedBox(), + Padding( + padding: EdgeInsets + .symmetric( + horizontal: + width * 0.02, + ), + child: Text( + ':', + style: Theme.of( + context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: + FontWeight + .bold, + color: themeController + .primaryDisabledTextColor + .value, + ), + ), ), - Obx( - () => (!controller.repeatDays.every( - (element) => element == false)) - ? Divider( - color: themeController - .primaryDisabledTextColor + NumberPicker( + minValue: 0, + maxValue: 59, + value: controller + .minutes.value, + onChanged: (value) { + Utils + .hapticFeedback(); + controller.minutes + .value = value; + controller + .selectedTime + .value = + DateTime( + controller + .selectedTime + .value + .year, + controller + .selectedTime + .value + .month, + controller + .selectedTime + .value + .day, + controller + .selectedTime + .value + .hour, + controller.minutes .value, - ) - : const SizedBox(), - ), - SnoozeSettingsTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - Obx( - () => (controller.repeatDays.every( - (element) => element == false)) - ? DeleteAfterGoesOff( - controller: controller, - themeController: - themeController, - ) - : const SizedBox(), - ), - LabelTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, + ); + controller + .inputHrsController + .text = + controller + .hours.value + .toString(); + controller + .inputMinutesController + .text = + controller + .minutes + .value + .toString(); + controller + .changePeriod( + controller.meridiemIndex + .value == + 0 + ? 'AM' + : 'PM', + ); + }, + infiniteLoop: true, + itemWidth: + width * 0.17, + zeroPad: true, + selectedTextStyle: + Theme.of(context) + .textTheme + .displayLarge! + .copyWith( + fontSize: controller + .homeController + .scalingFactor * + 40, + fontWeight: + FontWeight + .bold, + color: + kprimaryColor, + ), + textStyle: Theme.of( + context) + .textTheme + .displayMedium! + .copyWith( + fontSize: controller + .homeController + .scalingFactor * + 20, + color: themeController + .primaryDisabledTextColor + .value, + ), ), - NoteTile( - controller: controller, - themeController: themeController, + Visibility( + visible: + settingsController + .is24HrsEnabled + .value + ? false + : true, + child: Padding( + padding: EdgeInsets + .symmetric( + horizontal: + width * 0.02, + ), + child: Text( + ':', + style: Theme.of( + context) + .textTheme + .displayLarge! + .copyWith( + fontWeight: + FontWeight + .bold, + color: themeController + .primaryDisabledTextColor + .value, + ), + ), + ), ), - Divider( - color: themeController - .primaryDisabledTextColor.value, + Visibility( + visible: + settingsController + .is24HrsEnabled + .value + ? false + : true, + child: NumberPicker( + minValue: 0, + maxValue: 1, + value: controller + .meridiemIndex + .value, + onChanged: (value) { + Utils + .hapticFeedback(); + value == 0 + ? controller + .meridiemIndex + .value = 0 + : controller + .meridiemIndex + .value = 1; + controller + .selectedTime + .value = + DateTime( + controller + .selectedTime + .value + .year, + controller + .selectedTime + .value + .month, + controller + .selectedTime + .value + .day, + controller + .convert24( + controller + .hours + .value, + controller + .meridiemIndex + .value, + ), + controller + .minutes + .value, + ); + controller + .inputHrsController + .text = + controller + .hours + .value + .toString(); + controller + .inputMinutesController + .text = + controller + .minutes + .value + .toString(); + controller + .changePeriod( + controller.meridiemIndex + .value == + 0 + ? 'AM' + : 'PM', + ); + }, + textMapper: + (numberText) { + return controller + .meridiem[ + int.parse( + numberText, + )] + .value; + }, + itemWidth: + width * 0.2, + selectedTextStyle: + Theme.of( + context) + .textTheme + .displayLarge! + .copyWith( + fontSize: + Utils.getFontSize( + context), + fontWeight: + FontWeight + .bold, + color: + kprimaryColor, + ), + textStyle: Theme.of( + context) + .textTheme + .displayMedium! + .copyWith( + fontSize: Utils + .getFontSize( + context), + color: themeController + .primaryDisabledTextColor + .value, + ), + ), ), - ChooseRingtoneTile( - controller: controller, - themeController: themeController, - height: height, - width: width, + ], + ), + ) + : Row( + mainAxisAlignment: + MainAxisAlignment + .center, + children: [ + SizedBox( + width: 80, + child: TextField( + onChanged: (_) { + if (int.parse(controller + .inputHrsController + .text) == + 12 && + int.parse(controller + .inputMinutesController + .text) == + 0) { + controller + .isAM + .toggle(); + } + controller + .setTime(); + }, + decoration: + const InputDecoration( + hintText: 'HH', + border: InputBorder + .none, + ), + textAlign: + TextAlign.center, + controller: + controller + .inputHrsController, + keyboardType: + TextInputType + .number, + inputFormatters: [ + FilteringTextInputFormatter + .allow(RegExp( + '[0-9]')), + LengthLimitingTextInputFormatter( + 2), + LimitRange( + settingsController.is24HrsEnabled.value ? 0 : 1, + settingsController.is24HrsEnabled.value ? 23 : 12, + ), + ], ), - Divider( - color: themeController - .primaryDisabledTextColor.value, + ), + SizedBox( + width: 16, + child: Text( + ':', + textAlign: + TextAlign.center, + style: + Theme.of(context) + .textTheme + .titleMedium, ), - AscendingVolumeTile( - controller: controller, - themeController: themeController, + ), + SizedBox( + width: 80, + child: TextField( + onChanged: (_) { + controller + .setTime(); + }, + decoration: + const InputDecoration( + hintText: 'MM', + border: InputBorder + .none, + ), + textAlign: + TextAlign.center, + controller: + controller + .inputMinutesController, + keyboardType: + TextInputType + .number, + inputFormatters: [ + FilteringTextInputFormatter + .allow( + RegExp( + '[1,2,3,4,5,6,7,8,9,0]', + ), + ), + LengthLimitingTextInputFormatter( + 2, + ), + LimitRange(00, 59), + ], ), - Divider( - color: themeController - .primaryDisabledTextColor.value, + ), + const SizedBox( + width: 16, + ), + Visibility( + visible: + !settingsController + .is24HrsEnabled + .value, + child: DropdownButton( + underline: + Container(), + value: + controller + .isAM + .value + ? 'AM' + : 'PM', + dropdownColor: + themeController + .primaryBackgroundColor + .value, + items: [ + 'AM', + 'PM' + ].map( + (String period) { + return DropdownMenuItem< + String>( + value: period, + child: + Text(period), + ); + }).toList(), + onChanged: + (getPeriod) { + controller + .changePeriod( + getPeriod!); + + controller + .setTime(); + }, ), - QuoteTile( - controller: controller, - themeController: themeController, + ), + const SizedBox( + width: 12, + ), + Visibility( + visible: + controller + .isTimePicker + .isFalse, + child: InkWell( + onTap: () { + Utils + .hapticFeedback(); + controller + .confirmTimeInput(); + }, + child: Container( + decoration: + BoxDecoration( + borderRadius: + BorderRadius + .circular( + 50.0, + ), + border: + Border.all( + color: + kprimaryColor, + width: 1.0, + ), + ), + padding: + const EdgeInsets + .all(5.0), + child: const Icon( + Icons.done, + color: + kprimaryColor, + ), + ), ), - ], - ) - : const SizedBox(), + ), + ], + ), + ); + }, + ), + ), + ), + ) + : Obx( + () => Padding( + padding: const EdgeInsets.all(16.0), + child: TextField( + decoration: InputDecoration( + hintText: 'Profile Name', + fillColor: controller.themeController + .secondaryBackgroundColor.value, + filled: true, + ), + controller: controller + .profileTextEditingController, + ), + ), + ), + SettingSelector(), + Obx( + () => controller.alarmSettingType.value == 0 + ? Column( + children: [ + AlarmDateTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + RepeatTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, ), Obx( - () => controller.alarmSettingType.value == 1 - ? Column( - children: [ - ScreenActivityTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - WeatherTile( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - LocationTile( - controller: controller, - height: height, - width: width, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - GuardianAngel( - controller: controller, - themeController: themeController, - ), - ], - ) + () => (!controller.repeatDays.every( + (element) => element == false)) + ? RepeatOnceTile( + controller: controller, + themeController: + themeController, + ) : const SizedBox(), ), Obx( - () => controller.alarmSettingType.value == 2 - ? Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - ShakeToDismiss( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - QrBarCode( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - MathsChallenge( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - PedometerChallenge( - controller: controller, - themeController: themeController, - ), - ], - ) + () => (!controller.repeatDays.every( + (element) => element == false)) + ? Divider( + color: themeController + .primaryDisabledTextColor + .value, + ) : const SizedBox(), ), + SnoozeSettingsTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), Obx( - () => controller.alarmSettingType.value == 3 - ? Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - SharedAlarm( - controller: controller, - themeController: themeController, - ), - Divider( - color: themeController - .primaryDisabledTextColor.value, - ), - AlarmIDTile( - controller: controller, - width: width, - themeController: themeController, - ), - Obx( - () => Container( - child: (controller - .isSharedAlarmEnabled.value) - ? Divider( - color: themeController - .primaryDisabledTextColor - .value, - ) - : const SizedBox(), - ), - ), - AlarmOffset( - controller: controller, - themeController: themeController, - ), - Obx( - () => Container( - child: (controller - .isSharedAlarmEnabled.value) - ? Divider( - color: themeController - .primaryDisabledTextColor - .value, - ) - : const SizedBox(), - ), - ), - SharedUsers( - controller: controller, - themeController: themeController, - ), - ], - ) - : SizedBox( - height: height * 0.15, + () => (controller.repeatDays.every( + (element) => element == false)) + ? DeleteAfterGoesOff( + controller: controller, + themeController: + themeController, + ) + : const SizedBox(), + ), + LabelTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + NoteTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + ChooseRingtoneTile( + controller: controller, + themeController: themeController, + height: height, + width: width, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + AscendingVolumeTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + QuoteTile( + controller: controller, + themeController: themeController, + ), + ], + ) + : const SizedBox(), + ), + Obx( + () => controller.alarmSettingType.value == 1 + ? Column( + children: [ + ScreenActivityTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + WeatherTile( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + LocationTile( + controller: controller, + height: height, + width: width, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + GuardianAngel( + controller: controller, + themeController: themeController, + ), + ], + ) + : const SizedBox(), + ), + Obx( + () => controller.alarmSettingType.value == 2 + ? Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + // --- ADDED THE DURATION SLIDER HERE --- + ListTile( + title: Row( + children: [ + Text( + 'Challenge Timer', + style: TextStyle( + color: themeController + .primaryTextColor.value, + ), + ), + const Spacer(), + Obx(() => Text( + '${controller.challengeDuration.value}s', + style: TextStyle( + color: themeController + .primaryTextColor.value, + fontWeight: FontWeight.bold, ), + )), + ], + ), + subtitle: Obx( + () => Slider( + value: controller.challengeDuration.value.toDouble(), + min: 5, + max: 60, + divisions: 11, // 5, 10, 15, 20... + activeColor: kprimaryColor, + onChanged: (value) { + controller.challengeDuration.value = value.toInt(); + }, + ), + ), + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + // ---------------------------------------- + ShakeToDismiss( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + QrBarCode( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + MathsChallenge( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + PedometerChallenge( + controller: controller, + themeController: themeController, + ), + ], + ) + : const SizedBox(), + ), + Obx( + () => controller.alarmSettingType.value == 3 + ? Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + SharedAlarm( + controller: controller, + themeController: themeController, + ), + Divider( + color: themeController + .primaryDisabledTextColor.value, + ), + AlarmIDTile( + controller: controller, + width: width, + themeController: themeController, + ), + Obx( + () => Container( + child: (controller + .isSharedAlarmEnabled.value) + ? Divider( + color: themeController + .primaryDisabledTextColor + .value, + ) + : const SizedBox(), + ), + ), + AlarmOffset( + controller: controller, + themeController: themeController, + ), + Obx( + () => Container( + child: (controller + .isSharedAlarmEnabled.value) + ? Divider( + color: themeController + .primaryDisabledTextColor + .value, + ) + : const SizedBox(), + ), + ), + SharedUsers( + controller: controller, + themeController: themeController, ), ], + ) + : SizedBox( + height: height * 0.15, ), + ), + ], + ), ), ), (controller.mutexLock.value == true) ? const SizedBox() : Padding( - padding: const EdgeInsets.all(18.0), - child: SizedBox( - height: height * 0.06, - width: width * 0.8, - child: TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(kprimaryColor), - ), - child: Text( - (controller.alarmRecord.value.alarmID == '') - ? 'Save'.tr - : 'Update'.tr, - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - color: themeController.secondaryTextColor.value, - ), - ), - onPressed: () async { - Utils.hapticFeedback(); - await controller.checkOverlayPermissionAndNavigate(); + padding: const EdgeInsets.all(18.0), + child: SizedBox( + height: height * 0.06, + width: width * 0.8, + child: TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(kprimaryColor), + ), + child: Text( + (controller.alarmRecord.value.alarmID == '') + ? 'Save'.tr + : 'Update'.tr, + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith( + color: themeController.secondaryTextColor.value, + ), + ), + onPressed: () async { + Utils.hapticFeedback(); + await controller.checkOverlayPermissionAndNavigate(); - if ((await Permission.systemAlertWindow.isGranted) && - (await Permission - .ignoreBatteryOptimizations.isGranted)) { - if (!controller.homeController.isProfile.value) { - if (controller.userModel.value != null) { - controller.offsetDetails[ - controller.userModel.value!.id] = { - 'offsettedTime': Utils.timeOfDayToString( - TimeOfDay.fromDateTime( - Utils.calculateOffsetAlarmTime( - controller.selectedTime.value, - controller.isOffsetBefore.value, - controller.offsetDuration.value, - ), - ), - ), - 'offsetDuration': - controller.offsetDuration.value, - 'isOffsetBefore': - controller.isOffsetBefore.value, - }; - } else { - controller.offsetDetails.value = {}; - } - AlarmModel alarmRecord = AlarmModel( - deleteAfterGoesOff: - controller.deleteAfterGoesOff.value, - snoozeDuration: controller.snoozeDuration.value, - maxSnoozeCount: controller.maxSnoozeCount.value, - volMax: controller.volMax.value, - volMin: controller.volMin.value, - gradient: controller.gradient.value, - offsetDetails: controller.offsetDetails, - label: controller.label.value, - note: controller.note.value, - showMotivationalQuote: - controller.showMotivationalQuote.value, - isOneTime: controller.isOneTime.value, - lastEditedUserId: - controller.lastEditedUserId.value, - mutexLock: controller.mutexLock.value, - alarmID: controller.alarmID, - ownerId: controller.ownerId.value, - ownerName: controller.ownerName.value, - activityInterval: - controller.activityInterval.value * 60000, - days: controller.repeatDays.toList(), - alarmTime: Utils.timeOfDayToString( - TimeOfDay.fromDateTime( - controller.selectedTime.value, - ), - ), - mainAlarmTime: Utils.timeOfDayToString( - TimeOfDay.fromDateTime( - controller.selectedTime.value, - ), - ), - intervalToAlarm: Utils.getMillisecondsToAlarm( - DateTime.now(), + // --- REMOVED BATTERY OPTIMIZATION CHECK HERE --- + if (await Permission.systemAlertWindow.isGranted) { + if (!controller.homeController.isProfile.value) { + if (controller.userModel.value != null) { + controller.offsetDetails[ + controller.userModel.value!.id] = { + 'offsettedTime': Utils.timeOfDayToString( + TimeOfDay.fromDateTime( + Utils.calculateOffsetAlarmTime( controller.selectedTime.value, + controller.isOffsetBefore.value, + controller.offsetDuration.value, ), - isActivityEnabled: - controller.isActivityenabled.value, - minutesSinceMidnight: Utils.timeOfDayToInt( - TimeOfDay.fromDateTime( - controller.selectedTime.value, - ), - ), - isLocationEnabled: - controller.isLocationEnabled.value, - weatherTypes: Utils.getIntFromWeatherTypes( - controller.selectedWeather.toList(), - ), - isWeatherEnabled: - controller.isWeatherEnabled.value, - location: Utils.geoPointToString( - Utils.latLngToGeoPoint( - controller.selectedPoint.value, - ), + ), + ), + 'offsetDuration': + controller.offsetDuration.value, + 'isOffsetBefore': + controller.isOffsetBefore.value, + }; + } else { + controller.offsetDetails.value = {}; + } + AlarmModel alarmRecord = AlarmModel( + deleteAfterGoesOff: + controller.deleteAfterGoesOff.value, + snoozeDuration: controller.snoozeDuration.value, + maxSnoozeCount: controller.maxSnoozeCount.value, + volMax: controller.volMax.value, + volMin: controller.volMin.value, + gradient: controller.gradient.value, + offsetDetails: controller.offsetDetails, + label: controller.label.value, + note: controller.note.value, + showMotivationalQuote: + controller.showMotivationalQuote.value, + isOneTime: controller.isOneTime.value, + lastEditedUserId: + controller.lastEditedUserId.value, + mutexLock: controller.mutexLock.value, + alarmID: controller.alarmID, + ownerId: controller.ownerId.value, + ownerName: controller.ownerName.value, + activityInterval: + controller.activityInterval.value * 60000, + days: controller.repeatDays.toList(), + alarmTime: Utils.timeOfDayToString( + TimeOfDay.fromDateTime( + controller.selectedTime.value, + ), + ), + mainAlarmTime: Utils.timeOfDayToString( + TimeOfDay.fromDateTime( + controller.selectedTime.value, + ), + ), + intervalToAlarm: Utils.getMillisecondsToAlarm( + DateTime.now(), + controller.selectedTime.value, + ), + isActivityEnabled: + controller.isActivityenabled.value, + minutesSinceMidnight: Utils.timeOfDayToInt( + TimeOfDay.fromDateTime( + controller.selectedTime.value, + ), + ), + isLocationEnabled: + controller.isLocationEnabled.value, + weatherTypes: Utils.getIntFromWeatherTypes( + controller.selectedWeather.toList(), + ), + isWeatherEnabled: + controller.isWeatherEnabled.value, + location: Utils.geoPointToString( + Utils.latLngToGeoPoint( + controller.selectedPoint.value, + ), + ), + 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, + isShakeEnabled: controller.isShakeEnabled.value, + shakeTimes: controller.shakeTimes.value, + isPedometerEnabled: + controller.isPedometerEnabled.value, + numberOfSteps: controller.numberOfSteps.value, + ringtoneName: + controller.customRingtoneName.value, + activityMonitor: + controller.isActivityMonitorenabled.value, + alarmDate: controller.selectedDate.value + .toString() + .substring(0, 11), + profile: controller + .homeController.selectedProfile.value, + isGuardian: controller.isGuardian.value, + guardianTimer: 0, + guardian: controller + .contactTextEditingController.text, + isCall: controller.isCall.value, + ringOn: controller.isFutureDate.value, + challengeDuration: controller.challengeDuration.value, // --- SAVING TO DB --- + ); + + if (controller.isSharedAlarmEnabled.value) { + alarmRecord.offsetDetails = + controller.offsetDetails; + alarmRecord.mainAlarmTime = + Utils.timeOfDayToString( + TimeOfDay.fromDateTime( + controller.selectedTime.value, ), - 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, - isShakeEnabled: controller.isShakeEnabled.value, - shakeTimes: controller.shakeTimes.value, - isPedometerEnabled: - controller.isPedometerEnabled.value, - numberOfSteps: controller.numberOfSteps.value, - ringtoneName: - controller.customRingtoneName.value, - activityMonitor: - controller.isActivityMonitorenabled.value, - alarmDate: controller.selectedDate.value - .toString() - .substring(0, 11), - profile: controller - .homeController.selectedProfile.value, - isGuardian: controller.isGuardian.value, - guardianTimer: 0, - guardian: controller - .contactTextEditingController.text, - isCall: controller.isCall.value, - ringOn: controller.isFutureDate.value, ); - - // Adding offset details to the database if - // its a shared alarm - if (controller.isSharedAlarmEnabled.value) { - alarmRecord.offsetDetails = - controller.offsetDetails; - alarmRecord.mainAlarmTime = - Utils.timeOfDayToString( - TimeOfDay.fromDateTime( - controller.selectedTime.value, - ), - ); - } - try { - if (controller.alarmRecord.value.alarmID == - '') { - await controller.createAlarm(alarmRecord); - } else { - AlarmModel updatedAlarmModel = - controller.updatedAlarmModel(); - await controller - .updateAlarm(updatedAlarmModel); - } - } catch (e) { - debugPrint(e.toString()); - } - } else { - controller.createProfile(); - } + } + try { + if (controller.alarmRecord.value.alarmID == + '') { + await controller.createAlarm(alarmRecord); + } else { + AlarmModel updatedAlarmModel = + controller.updatedAlarmModel(); + await controller + .updateAlarm(updatedAlarmModel); } - }, - ), - ), - ), + } catch (e) { + debugPrint(e.toString()); + } + } else { + controller.createProfile(); + } + } + }, + ), + ), + ), ], ), ), ); } -} +} \ No newline at end of file diff --git a/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart b/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart index f20ab030b..f4457e111 100644 --- a/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart +++ b/lib/app/modules/alarmChallenge/controllers/alarm_challenge_controller.dart @@ -14,8 +14,12 @@ import 'package:ultimate_alarm_clock/app/utils/utils.dart'; class AlarmChallengeController extends GetxController { AlarmModel alarmRecord = Get.arguments; + // Kept for backward compatibility with your other screens final RxDouble progress = 1.0.obs; - int _timerSessionId = 0; + + // --- NEW: Clean integer timer --- + final RxInt timeRemaining = 15.obs; + Timer? _challengeTimer; final RxInt shakedCount = 0.obs; final isShakeOngoing = Status.initialized.obs; @@ -90,6 +94,7 @@ class AlarmChallengeController extends GetxController { @override void onInit() async { super.onInit(); + _startTimer(); String ringtoneName = alarmRecord.ringtoneName; @@ -163,7 +168,7 @@ class AlarmChallengeController extends GetxController { if (alarmRecord.isPedometerEnabled) { final PermissionStatus status = - await Permission.activityRecognition.request(); + await Permission.activityRecognition.request(); if (status == PermissionStatus.granted) { numberOfSteps = alarmRecord.numberOfSteps; @@ -200,65 +205,37 @@ class AlarmChallengeController extends GetxController { } } - void _startTimer() async { - const duration = Duration(seconds: 15); - const totalIterations = 1500000; - const decrement = 0.000001; + // --- THE NEW 1-SECOND TIMER ENGINE --- + void _startTimer() { + _challengeTimer?.cancel(); - // Capture the current session ID for this specific async loop - final int currentSessionId = _timerSessionId; - - for (var i = totalIterations; i > 0; i--) { - // If the global session ID has changed, kill this orphaned loop immediately - if (currentSessionId != _timerSessionId) { - break; - } + int duration = alarmRecord.challengeDuration; + timeRemaining.value = duration; + progress.value = 1.0; + // Ticks exactly once per second, stopping the emulator crashes! + _challengeTimer = Timer.periodic(const Duration(seconds: 1), (timer) { if (!isTimerEnabled) { - debugPrint('THIS IS THE BUG'); - break; + timer.cancel(); + return; } - if (progress.value <= 0.0) { + + if (timeRemaining.value > 0) { + timeRemaining.value--; + progress.value = timeRemaining.value / duration; // Keeps your other screens happy + } else { + timer.cancel(); + progress.value = 0.0; shouldProcessStepCount = false; Get.until((route) => route.settings.name == '/alarm-ring'); - break; } - await Future.delayed(duration ~/ i); - progress.value -= decrement; - } + }); } restartTimer() { - _timerSessionId++; // Increment ID to kill any existing async loops - progress.value = 1.0; // Reset the progress to its initial value - _startTimer(); // Start a new timer + _startTimer(); } - // void _startTimer() async { - // const duration = Duration(seconds: 15); - // const totalIterations = 1500000; - // const decrement = 0.000001; - - // for (var i = totalIterations; i > 0; i--) { - // if (!isTimerEnabled) { - // debugPrint('THIS IS THE BUG'); - // break; - // } - // if (progress.value <= 0.0) { - // shouldProcessStepCount = false; - // Get.until((route) => route.settings.name == '/alarm-ring'); - // break; - // } - // await Future.delayed(duration ~/ i); - // progress.value -= decrement; - // } - // } - - // restartTimer() { - // progress.value = 1.0; // Reset the progress to its initial value - // _startTimer(); // Start a new timer - // } - isChallengesComplete() { if (!Utils.isChallengeEnabled(alarmRecord)) { isNumMathQuestionsSet = false; @@ -269,6 +246,8 @@ class AlarmChallengeController extends GetxController { @override void onClose() async { + _challengeTimer?.cancel(); + super.onClose(); shouldProcessStepCount = false; @@ -281,12 +260,13 @@ class AlarmChallengeController extends GetxController { AudioUtils.playAlarm(alarmRecord: alarmRecord); } } + void removeDigit() { - if (displayValue.value.isNotEmpty) { - displayValue.value = displayValue.value.substring( - 0, - displayValue.value.length - 1 - ); + if (displayValue.value.isNotEmpty) { + displayValue.value = displayValue.value.substring( + 0, + displayValue.value.length - 1 + ); + } } -} -} +} \ No newline at end of file diff --git a/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart b/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart index 6d6f69f0a..0446cf05d 100644 --- a/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/maths_challenge_view.dart @@ -5,7 +5,6 @@ import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_cont import 'package:ultimate_alarm_clock/app/utils/constants.dart'; import 'package:ultimate_alarm_clock/app/utils/utils.dart'; -// ignore: must_be_immutable class MathsChallengeView extends GetView { MathsChallengeView({Key? key}) : super(key: key); @@ -13,8 +12,6 @@ class MathsChallengeView extends GetView { @override Widget build(BuildContext context) { - // var height = Get.height; - // var width = Get.width; final double width = MediaQuery.of(context).size.width; final double height = MediaQuery.of(context).size.height; return GestureDetector( @@ -29,74 +26,86 @@ class MathsChallengeView extends GetView { body: Center( child: Column( children: [ - Obx( - () => LinearProgressIndicator( - minHeight: 2, - value: controller.progress.value, - backgroundColor: Colors.grey, - valueColor: - const AlwaysStoppedAnimation(kprimaryColor), - ), - ), + // --- THE OPTIMIZED TEXT TIMER --- + Obx(() { + // Now it reads the pure integer once per second! + int secondsLeft = controller.timeRemaining.value; + String timerText = "00:${secondsLeft.toString().padLeft(2, '0')}"; + + return Padding( + padding: const EdgeInsets.only(top: 20.0, bottom: 10.0), + child: Text( + timerText, + style: TextStyle( + fontSize: 48, + fontWeight: FontWeight.bold, + color: secondsLeft <= 5 + ? Colors.red + : themeController.primaryTextColor.value, + ), + ), + ); + }), + // ----------------------------------- Expanded( child: Obx( - () => Column( + () => Column( mainAxisAlignment: MainAxisAlignment.center, children: [ (controller.isMathsOngoing.value == Status.ongoing) ? Column( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 30.0), - child: Obx( - () => Text( - 'Question @noMathQ'.trParams({ - 'noMathQ' : controller.numMathsQuestions.value.toString(), - }), - style: Theme.of(context).textTheme.displayMedium?.copyWith( - letterSpacing: 1.5, - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Obx( - () => Text( - controller.questionText.value, - style: Theme.of(context) - .textTheme - .displayLarge, - ), - ), + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 30.0), + child: Obx( + () => Text( + 'Question @noMathQ'.trParams({ + 'noMathQ' : controller.numMathsQuestions.value.toString(), + }), + style: Theme.of(context).textTheme.displayMedium?.copyWith( + letterSpacing: 1.5, ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Obx( - () => Text( - controller.displayValue.value, - style: Theme.of(context) - .textTheme - .displayMedium, - ), - ), - ), - ], - ) - : Padding( - padding: const EdgeInsets.all(16.0), - child: (controller.correctAnswer.value) - ? Icon( - Icons.done, - size: height * 0.08, - color: Colors.green, - ) - : Icon( - Icons.close, - size: height * 0.08, - color: Colors.red, - ), + ), ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Obx( + () => Text( + controller.questionText.value, + style: Theme.of(context) + .textTheme + .displayLarge, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Obx( + () => Text( + controller.displayValue.value, + style: Theme.of(context) + .textTheme + .displayMedium, + ), + ), + ), + ], + ) + : Padding( + padding: const EdgeInsets.all(16.0), + child: (controller.correctAnswer.value) + ? Icon( + Icons.done, + size: height * 0.08, + color: Colors.green, + ) + : Icon( + Icons.close, + size: height * 0.08, + color: Colors.red, + ), + ), Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( @@ -106,7 +115,7 @@ class MathsChallengeView extends GetView { children: [ Row( mainAxisAlignment: - MainAxisAlignment.spaceEvenly, + MainAxisAlignment.spaceEvenly, children: [ _buildNumberButton('7'), _buildNumberButton('8'), @@ -116,7 +125,7 @@ class MathsChallengeView extends GetView { const SizedBox(height: 8), Row( mainAxisAlignment: - MainAxisAlignment.spaceEvenly, + MainAxisAlignment.spaceEvenly, children: [ _buildNumberButton('4'), _buildNumberButton('5'), @@ -126,7 +135,7 @@ class MathsChallengeView extends GetView { const SizedBox(height: 8), Row( mainAxisAlignment: - MainAxisAlignment.spaceEvenly, + MainAxisAlignment.spaceEvenly, children: [ _buildNumberButton('1'), _buildNumberButton('2'), @@ -136,7 +145,7 @@ class MathsChallengeView extends GetView { const SizedBox(height: 8), Row( mainAxisAlignment: - MainAxisAlignment.spaceEvenly, + MainAxisAlignment.spaceEvenly, children: [ _buildClearButton(), _buildNumberButton('0'), @@ -160,7 +169,7 @@ class MathsChallengeView extends GetView { Widget _buildNumberButton(String number) { return Obx( - () => ElevatedButton( + () => ElevatedButton( onPressed: () { Utils.hapticFeedback(); controller.onButtonPressed(number); @@ -178,7 +187,7 @@ class MathsChallengeView extends GetView { Widget _buildClearButton() { return Obx( - () => ElevatedButton( + () => ElevatedButton( onPressed: () { Utils.hapticFeedback(); controller.removeDigit(); @@ -200,7 +209,7 @@ class MathsChallengeView extends GetView { Widget _buildDoneButton() { return Obx( - () => ElevatedButton( + () => ElevatedButton( onPressed: () { Utils.hapticFeedback(); if (controller.mathsAnswer.toString() == @@ -227,5 +236,4 @@ class MathsChallengeView extends GetView { ), ); } -} - +} \ No newline at end of file diff --git a/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart b/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart index 2e5572d32..013b4d51b 100644 --- a/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/pedometer_challenge_view.dart @@ -14,9 +14,7 @@ class PedometerChallengeView extends GetView { @override Widget build(BuildContext context) { - // var height = Get.height; - // ignore: unused_local_variable - final double width = MediaQuery.of(context).size.width; + final double width = MediaQuery.of(context).size.width; final double height = MediaQuery.of(context).size.height; return Scaffold( @@ -31,14 +29,29 @@ class PedometerChallengeView extends GetView { }, child: Column( children: [ - Obx( - () => LinearProgressIndicator( - minHeight: 2, - value: controller.progress.value, - backgroundColor: Colors.grey, - valueColor: const AlwaysStoppedAnimation(kprimaryColor), - ), - ), + // --- THE NEW MASSIVE TEXT TIMER --- + // --- THE OPTIMIZED TEXT TIMER --- + Obx(() { + // Directly read the clean integer from the new engine! + int secondsLeft = controller.timeRemaining.value; + String timerText = "00:${secondsLeft.toString().padLeft(2, '0')}"; + + return Padding( + padding: const EdgeInsets.only(top: 20.0, bottom: 10.0), + child: Text( + timerText, + style: TextStyle( + fontSize: 48, + fontWeight: FontWeight.bold, + color: secondsLeft <= 5 + ? Colors.red + : themeController.primaryTextColor.value, + ), + ), + ); + }), + // ----------------------------------- + // ----------------------------------- Expanded( child: Center( child: SingleChildScrollView( @@ -49,22 +62,22 @@ class PedometerChallengeView extends GetView { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Obx( - () => Text( + () => Text( 'Walk it Out!', style: Theme.of(context) .textTheme .displayMedium! .copyWith( - fontWeight: FontWeight.w500, - color: themeController.primaryTextColor.value.withOpacity(0.7), - ), + fontWeight: FontWeight.w500, + color: themeController.primaryTextColor.value.withOpacity(0.7), + ), ), ), SizedBox( height: height * 0.08, ), Obx( - () => Icon( + () => Icon( Icons.directions_walk, size: height * 0.2, color: themeController.primaryTextColor.value.withOpacity(0.7), @@ -74,13 +87,13 @@ class PedometerChallengeView extends GetView { height: height * 0.08, ), Obx( - () => Text( + () => Text( (controller.alarmRecord.numberOfSteps - - controller.stepsCount.value >= - 0 - ? controller.alarmRecord.numberOfSteps - - controller.stepsCount.value - : 0) + controller.stepsCount.value >= + 0 + ? controller.alarmRecord.numberOfSteps - + controller.stepsCount.value + : 0) .toString(), style: const TextStyle(fontSize: 35), ), @@ -97,4 +110,4 @@ class PedometerChallengeView extends GetView { ), ); } -} +} \ No newline at end of file diff --git a/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart b/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart index bb1ffce1f..edab09102 100644 --- a/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/qr_challenge_view.dart @@ -16,10 +16,6 @@ class QRChallengeView extends GetView { @override Widget build(BuildContext context) { - // ignore: unused_local_variable - // var width = Get.width; - // var height = Get.height; - // ignore: unused_local_variable final double width = MediaQuery.of(context).size.width; final double height = MediaQuery.of(context).size.height; @@ -35,14 +31,29 @@ class QRChallengeView extends GetView { }, child: Column( children: [ - Obx( - () => LinearProgressIndicator( - minHeight: 2, - value: controller.progress.value, - backgroundColor: Colors.grey, - valueColor: const AlwaysStoppedAnimation(kprimaryColor), - ), - ), + // --- THE NEW MASSIVE TEXT TIMER --- + // --- THE OPTIMIZED TEXT TIMER --- + Obx(() { + // Directly read the clean integer from the new engine! + int secondsLeft = controller.timeRemaining.value; + String timerText = "00:${secondsLeft.toString().padLeft(2, '0')}"; + + return Padding( + padding: const EdgeInsets.only(top: 20.0, bottom: 10.0), + child: Text( + timerText, + style: TextStyle( + fontSize: 48, + fontWeight: FontWeight.bold, + color: secondsLeft <= 5 + ? Colors.red + : themeController.primaryTextColor.value, + ), + ), + ); + }), + // ----------------------------------- + // ----------------------------------- Expanded( child: Center( child: SingleChildScrollView( @@ -52,128 +63,128 @@ class QRChallengeView extends GetView { child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Obx( - () => Text( - 'Scan your QR/Bar Code!'.tr, - style: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - fontWeight: FontWeight.w500, - color: themeController.primaryTextColor.value.withOpacity(0.7), - ), + Obx( + () => Text( + 'Scan your QR/Bar Code!'.tr, + style: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontWeight: FontWeight.w500, + color: themeController.primaryTextColor.value.withOpacity(0.7), + ), ), ), SizedBox( height: height * 0.08, ), Obx( - () => Column( + () => Column( children: [ (controller.isQrOngoing.value == - Status.initialized) + Status.initialized) ? SizedBox( - height: 300, - width: 300, - child: MobileScanner( - controller: controller.qrController, - fit: BoxFit.cover, - onDetect: (capture) { - final List barcodes = - capture.barcodes; - for (final barcode in barcodes) { - controller.qrValue.value = - barcode.rawValue.toString(); + height: 300, + width: 300, + child: MobileScanner( + controller: controller.qrController, + fit: BoxFit.cover, + onDetect: (capture) { + final List barcodes = + capture.barcodes; + for (final barcode in barcodes) { + controller.qrValue.value = + barcode.rawValue.toString(); - if (controller.qrValue.value != - controller - .alarmRecord.qrValue) { - controller.isQrOngoing.value = - Status.ongoing; - } else { - controller.isQrOngoing.value = - Status.completed; - } - } - }, - ), - ) + if (controller.qrValue.value != + controller + .alarmRecord.qrValue) { + controller.isQrOngoing.value = + Status.ongoing; + } else { + controller.isQrOngoing.value = + Status.completed; + } + } + }, + ), + ) : SizedBox( - height: 300, - width: 300, - child: Center( - child: (controller.qrValue.value == - controller - .alarmRecord.qrValue) - ? Icon( - Icons.done, - size: height * 0.2, - color: themeController.primaryTextColor.value - .withOpacity(0.7), - ) - : Column( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Icon( - Icons.close, - size: height * 0.2, - color: themeController.primaryTextColor.value - .withOpacity( - 0.7, - ), - ), - Text( - 'Wrong Code Scanned!'.tr, - style: Theme.of( - context, - ) - .textTheme - .bodyMedium! - .copyWith( - fontWeight: - FontWeight.w500, - color: themeController.primaryTextColor.value - .withOpacity( - 0.7, - ), - ), - ), - TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty - .all( - kprimaryColor, - ), - ), - child: Text( - 'Retake'.tr, - style: Theme.of( - context, - ) - .textTheme - .displaySmall! - .copyWith( - color: themeController.secondaryTextColor.value, - ), - ), - onPressed: () async { - Utils.hapticFeedback(); - controller.qrController! - .dispose(); - controller - .restartQRCodeController(); - controller.isQrOngoing - .value = - Status.initialized; - }, - ), - ], - ), + height: 300, + width: 300, + child: Center( + child: (controller.qrValue.value == + controller + .alarmRecord.qrValue) + ? Icon( + Icons.done, + size: height * 0.2, + color: themeController.primaryTextColor.value + .withOpacity(0.7), + ) + : Column( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Icon( + Icons.close, + size: height * 0.2, + color: themeController.primaryTextColor.value + .withOpacity( + 0.7, + ), + ), + Text( + 'Wrong Code Scanned!'.tr, + style: Theme.of( + context, + ) + .textTheme + .bodyMedium! + .copyWith( + fontWeight: + FontWeight.w500, + color: themeController.primaryTextColor.value + .withOpacity( + 0.7, + ), + ), ), - ), + TextButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty + .all( + kprimaryColor, + ), + ), + child: Text( + 'Retake'.tr, + style: Theme.of( + context, + ) + .textTheme + .displaySmall! + .copyWith( + color: themeController.secondaryTextColor.value, + ), + ), + onPressed: () async { + Utils.hapticFeedback(); + controller.qrController! + .dispose(); + controller + .restartQRCodeController(); + controller.isQrOngoing + .value = + Status.initialized; + }, + ), + ], + ), + ), + ), ], ), ), @@ -189,4 +200,4 @@ class QRChallengeView extends GetView { ), ); } -} +} \ No newline at end of file diff --git a/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart b/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart index a56851148..636026bd7 100644 --- a/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart +++ b/lib/app/modules/alarmChallenge/views/shake_challenge_view.dart @@ -15,10 +15,6 @@ class ShakeChallengeView extends GetView { @override Widget build(BuildContext context) { - - // var width = Get.width; - // var height = Get.height; - // ignore: unused_local_variable final double width = MediaQuery.of(context).size.width; final double height = MediaQuery.of(context).size.height; @@ -34,14 +30,29 @@ class ShakeChallengeView extends GetView { }, child: Column( children: [ - Obx( - () => LinearProgressIndicator( - minHeight: 2, - value: controller.progress.value, - backgroundColor: Colors.grey, - valueColor: const AlwaysStoppedAnimation(kprimaryColor), - ), + // --- ADDED REPAINT BOUNDARY TO STOP FLICKERING --- + RepaintBoundary( + child: Obx(() { + // Directly read the clean integer from the new engine! + int secondsLeft = controller.timeRemaining.value; + String timerText = "00:${secondsLeft.toString().padLeft(2, '0')}"; + + return Padding( + padding: const EdgeInsets.only(top: 20.0, bottom: 10.0), + child: Text( + timerText, + style: TextStyle( + fontSize: 48, + fontWeight: FontWeight.bold, + color: secondsLeft <= 5 + ? Colors.red + : themeController.primaryTextColor.value, + ), + ), + ); + }), ), + // ----------------------------------- Expanded( child: Center( child: SingleChildScrollView( @@ -51,23 +62,23 @@ class ShakeChallengeView extends GetView { child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Obx( - () => Text( - 'Shake your phone!'.tr, - style: Theme.of(context) - .textTheme - .displayMedium! - .copyWith( - fontWeight: FontWeight.w500, - color: themeController.primaryTextColor.value.withOpacity(0.7), - ), + Obx( + () => Text( + 'Shake your phone!'.tr, + style: Theme.of(context) + .textTheme + .displayMedium! + .copyWith( + fontWeight: FontWeight.w500, + color: themeController.primaryTextColor.value.withOpacity(0.7), + ), ), ), SizedBox( height: height * 0.08, ), Obx( - () => Transform.rotate( + () => Transform.rotate( angle: -10 * math.pi / 180, child: Icon( Icons.vibration, @@ -80,7 +91,7 @@ class ShakeChallengeView extends GetView { height: height * 0.08, ), Obx( - () => Text( + () => Text( controller.shakedCount.value.toString(), style: const TextStyle(fontSize: 35), ), @@ -98,3 +109,4 @@ class ShakeChallengeView extends GetView { ); } } +//here \ No newline at end of file