fix toggle

pull/152/head
Fatimah.Alshammari 2 months ago
parent 27ad4e0764
commit 77242825bb

@ -5,36 +5,24 @@ import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescri
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class ActivePrescriptionsViewModel extends ChangeNotifier {
bool isActivePrescriptionsDetailsLoading = false;
late ActivePrescriptionsRepo activePrescriptionsRepo;
late ErrorHandlerService errorHandlerService;
List<ActivePrescriptionsResponseModel> activePrescriptionsDetailsList = [];
ActivePrescriptionsViewModel({
required this.activePrescriptionsRepo,
required this.errorHandlerService,
});
List<ActivePrescriptionsResponseModel> activePrescriptionsDetailsList = [];
initActivePrescriptionsViewModel() {
getActiveMedications();
notifyListeners();
}
setPrescriptionsDetailsLoading() {
isActivePrescriptionsDetailsLoading = true;
notifyListeners();
}
// Get medications list
Future<void> getActiveMedications({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
final result = await activePrescriptionsRepo.getActivePrescriptionsDetails();
final result =
await activePrescriptionsRepo.getActivePrescriptionsDetails();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async =>
await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 1) {
activePrescriptionsDetailsList = apiResponse.data ?? [];
@ -56,140 +44,58 @@ class ActivePrescriptionsViewModel extends ChangeNotifier {
return DateTime.tryParse(date) ?? DateTime.now();
}
// Extract numeric value ( "3 / week" 3)
int extractNumberFromFrequency(String? frequency) {
if (frequency == null) return 1;
final m = RegExp(r'(\d+)').firstMatch(frequency);
if (m != null) return int.tryParse(m.group(1)!) ?? 1;
return 1;
}
// Generate medication days based on frequency text
List<DateTime> generateMedicationDays(ActivePrescriptionsResponseModel med) {
final start = parseDate(med.startDate);
final duration = med.days ?? 0;
final frequency = (med.frequency ?? "").toLowerCase().trim();
if (duration <= 0) return [];
final f = (med.frequency ?? "").toLowerCase().trim();
int intervalDays = 1;
List<DateTime> result = [];
if (duration <= 0) return result;
// Every N hours ( "Every Six Hours", "Every 8 hours")
if (frequency.contains("hour")) {
final match = RegExp(r'every\s+(\d+)').firstMatch(frequency);
int intervalHours = 0;
if (match != null) {
intervalHours = int.tryParse(match.group(1)!) ?? 0;
} else {
// handle text numbers like "Every six hours"
final textNum = {
"one": 1,
"two": 2,
"three": 3,
"four": 4,
"five": 5,
"six": 6,
"seven": 7,
"eight": 8,
"nine": 9,
"ten": 10,
"twelve": 12,
};
for (var key in textNum.keys) {
if (frequency.contains(key)) {
intervalHours = textNum[key]!;
break;
}
}
}
if (intervalHours > 0) {
for (int day = 0; day < duration; day++) {
final dayStart = start.add(Duration(days: day));
for (int hour = 0; hour < 24; hour += intervalHours) {
result.add(DateTime(dayStart.year, dayStart.month, dayStart.day, hour));
}
}
return result;
if (f.contains("every six hours") ||
f.contains("every 6 hours") ||
f.contains("every four hours") ||
f.contains("every 4 hours") ||
f.contains("every eight hours") ||
f.contains("every 8 hours") ||
f.contains("every 12 hours") ||
f.contains("every twelve hours") ||
f.contains("every 24 hours") ||
f.contains("3 times a day") ||
f.contains("once a day")) {
intervalDays = 1;
}
else if (f.contains("once a week")) {
intervalDays = 7;
}
// Daily (every day)
if (frequency.contains("day") &&
!frequency.contains("every other") &&
!frequency.contains("every ")) {
for (int i = 0; i < duration; i++) {
result.add(start.add(Duration(days: i)));
else if (f.contains("every 3 days")) {
intervalDays = 3;
}
else if (f.contains("every other day")) {
intervalDays = 2;
}
// Every other day
else if (frequency.contains("every other day")) {
for (int i = 0; i < duration; i += 2) {
result.add(start.add(Duration(days: i)));
}
}
// Every N days e.g. "Every 3 days", "Every 5 days"
else if (frequency.contains("every") && frequency.contains("day")) {
final match = RegExp(r'every\s+(\d+)').firstMatch(frequency);
final interval = match != null ? int.tryParse(match.group(1)!) ?? 1 : 1;
for (int i = 0; i < duration; i += interval) {
result.add(start.add(Duration(days: i)));
}
}
// Once or twice a week
else if (frequency.contains("once a week")) {
for (int i = 0; i < duration; i += 7) {
result.add(start.add(Duration(days: i)));
}
} else if (frequency.contains("twice a week")) {
for (int i = 0; i < duration; i += 3) {
result.add(start.add(Duration(days: i)));
}
}
// Numeric frequency like "3 / week", "2 / week"
else if (frequency.contains("week")) {
int timesPerWeek = extractNumberFromFrequency(frequency);
double interval = 7 / timesPerWeek;
double dayPointer = 0;
for (int i = 0; i < duration; i++) {
if (i >= dayPointer.floor()) {
result.add(start.add(Duration(days: i)));
dayPointer += interval;
}
}
}
else {
result.add(start);
}
final unique = <String, DateTime>{};
for (final d in result) {
unique["${d.year}-${d.month}-${d.day}"] = d;
List<DateTime> result = [];
for (int offset = 0; offset < duration; offset += intervalDays) {
result.add(start.add(Duration(days: offset)));
}
return unique.values.toList()..sort((a, b) => a.compareTo(b));
return result;
}
bool sameYMD(DateTime a, DateTime b) =>
a.year == b.year && a.month == b.month && a.day == b.day;
// Filter medications for selected day
List<ActivePrescriptionsResponseModel> getMedsForSelectedDay(DateTime selectedDate) {
final target = DateTime(selectedDate.year, selectedDate.month, selectedDate.day);
List<ActivePrescriptionsResponseModel> getMedsForSelectedDay(
DateTime selectedDate) {
final clean = DateTime(selectedDate.year, selectedDate.month, selectedDate.day);
return activePrescriptionsDetailsList.where((med) {
final days = generateMedicationDays(med);
return days.any((d) => sameYMD(d, target));
return days.any((d) => sameYMD(d, clean));
}).toList();
}
}

@ -35,7 +35,7 @@ class ActivePrescriptionsResponseModel {
int? scaleOffset;
String? startDate;
// Added for reminder feature
// Added for reminder feature
List<String?> selectedDoseTimes = [];
bool isReminderOn = false; // toggle status

@ -18,6 +18,7 @@ import '../../widgets/buttons/custom_button.dart';
import '../../widgets/chip/app_custom_chip_widget.dart'; // for date formatting
import 'package:provider/provider.dart';
import '../../widgets/loader/bottomsheet_loader.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ActiveMedicationPage extends StatefulWidget {
@ -32,42 +33,97 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
late DateTime selectedDate;
List<ActivePrescriptionsResponseModel> selectedDayMeds = [];
ActivePrescriptionsViewModel? activePreVM;
Map<int, bool> medReminderStatus = {};
Map<String, bool> medReminderStatus = {};
String _buildMedKey(ActivePrescriptionsResponseModel med) {
return "${med.itemId}_${med.startDate}_${med.days}_${med.frequency}";
}
int _getDosesCount(ActivePrescriptionsResponseModel med) {
return med.frequencyNumber ?? 1;
}
@override
void initState() {
super.initState();
currentDate = DateTime.now();
selectedDate = currentDate;
WidgetsBinding.instance.addPostFrameCallback((_) async {
activePreVM = Provider.of<ActivePrescriptionsViewModel>(context, listen: false);
activePreVM =
Provider.of<ActivePrescriptionsViewModel>(context, listen: false);
LoaderBottomSheet.showLoader();
await activePreVM!.getActiveMedications(
onSuccess: (_) {
onSuccess: (_) async {
LoaderBottomSheet.hideLoader();
final todayMeds = activePreVM!.getMedsForSelectedDay(selectedDate);
setState(() {
selectedDayMeds = todayMeds;
final todayMeds =
activePreVM!.getMedsForSelectedDay(selectedDate);
setState(() => selectedDayMeds = todayMeds);
WidgetsBinding.instance.addPostFrameCallback((_) async {
await loadSavedReminders();
});
},
onError: (_) {
LoaderBottomSheet.hideLoader();
},
);
activePreVM!.addListener(() {
if (!mounted) return;
final medsForDay = activePreVM!.getMedsForSelectedDay(selectedDate);
final medsForDay =
activePreVM!.getMedsForSelectedDay(selectedDate);
setState(() => selectedDayMeds = medsForDay);
});
});
}
Future<void> loadSavedReminders() async {
final prefs = await SharedPreferences.getInstance();
for (final med in activePreVM!.activePrescriptionsDetailsList) {
final medKey = _buildMedKey(med);
final doses = _getDosesCount(med);
med.selectedDoseTimes =
List<String?>.filled(doses, null, growable: false);
for (int i = 0; i < doses; i++) {
final saved = prefs.getString("doseTime_${medKey}_$i");
if (saved != null) {
med.selectedDoseTimes[i] = saved;
}
}
final reminderOn =
prefs.getBool("reminderStatus_$medKey") ?? false;
med.isReminderOn = reminderOn;
medReminderStatus[medKey] = reminderOn;
}
setState(() {});
}
Future<void> saveReminderStatus(String medKey, bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool("reminderStatus_$medKey", value);
}
Future<void> saveDoseTime(
String medKey, int doseIndex, String time) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString("doseTime_${medKey}_$doseIndex", time);
}
List<DateTime> getUpcomingDays() =>
List.generate(7, (index) => currentDate.add(Duration(days: index)));
List<DateTime> getUpcomingDays() => List.generate(7, (index) => currentDate.add(Duration(days: index)));
@override
Widget build(BuildContext context) {
final days = getUpcomingDays();
final dateText = "${selectedDate.day}${getSuffix(selectedDate.day)} ${DateFormat.MMMM().format(selectedDate)}";
return Scaffold(
backgroundColor: AppColors.scaffoldBgColor,
appBar: CustomAppBar(
@ -115,7 +171,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
child: Transform.translate(
offset: const Offset(0, -4),
child: Text(
getSuffix(selectedDate.day),
_getSuffix(selectedDate.day),
style: const TextStyle(
fontSize: 12,
color: AppColors.textColor,
@ -150,10 +206,22 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
itemCount: selectedDayMeds.length,
itemBuilder: (context, index) {
final med = selectedDayMeds[index];
final doses = med.doseDailyQuantity ?? 1;
med.selectedDoseTimes ??= List.filled(doses, null);
final doses = _getDosesCount(med);
if (med.selectedDoseTimes.length != doses) {
final old = med.selectedDoseTimes;
med.selectedDoseTimes =
List<String?>.filled(doses, null,
growable: false);
for (int i = 0;
i < old.length && i < doses;
i++) {
med.selectedDoseTimes[i] = old[i];
}
}
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: true,
@ -163,12 +231,21 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
children: [
_buildMedHeader(med),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
// Utils.buildSvgWithAssets(
// icon: AppAssets.,
// height: 18.h,
// width: 18.h,
// iconColor:
// AppColors.lightGreyTextColor,
// ),
Icon(
Icons.info_outline,
color: AppColors.lightGreyTextColor,
size: 20,
color: AppColors
.lightGreyTextColor,
size: 18,
),
SizedBox(width: 6.h),
Expanded(
@ -176,18 +253,25 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
text: TextSpan(
children: [
TextSpan(
text: "Remarks: ".needTranslation,
text: "Remarks: "
.needTranslation,
style: TextStyle(
color: AppColors.textColor,
fontWeight: FontWeight.w600,
color:
AppColors.textColor,
fontWeight:
FontWeight.w600,
fontSize: 10,
),
),
TextSpan(
text: "some remarks about the prescription will be here".needTranslation,
text:
"some remarks about the prescription will be here"
.needTranslation,
style: TextStyle(
color: AppColors.lightGreyTextColor,
fontWeight: FontWeight.normal,
color: AppColors
.lightGreyTextColor,
fontWeight:
FontWeight.normal,
fontSize: 10,
),
),
@ -197,10 +281,10 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
),
],
).paddingOnly(left: 16, right: 16),
const Divider(color: AppColors.greyColor),
// Reminder Section
const Divider(
color: AppColors.greyColor),
GestureDetector(
onTap: () => showDoseDialog(med, index),
onTap: () => showDoseDialog(med),
child: Row(
children: [
Container(
@ -209,13 +293,16 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
alignment: Alignment.center,
decoration: BoxDecoration(
color: AppColors.greyColor,
borderRadius: BorderRadius.circular(10),
borderRadius:
BorderRadius.circular(10),
),
child: Utils.buildSvgWithAssets(
child:
Utils.buildSvgWithAssets(
icon: AppAssets.bell,
height: 24.h,
width: 24.h,
iconColor: AppColors.greyTextColor,
iconColor:
AppColors.greyTextColor,
),
),
SizedBox(width: 12.h),
@ -224,32 +311,43 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text("Set Reminder".needTranslation,
Text(
"Set Reminder"
.needTranslation,
style: TextStyle(
fontSize: 14.f,
fontWeight: FontWeight.w600,
color: AppColors.textColor)),
Text("Notify me before the consumption time".needTranslation,
fontWeight:
FontWeight.w600,
color: AppColors
.textColor)),
Text(
"Notify me before the consumption time"
.needTranslation,
style: TextStyle(
fontSize: 12.f,
color: AppColors.textColorLight,
color: AppColors
.textColorLight,
)),
],
),
),
_buildToggle(index)
_buildToggle(med),
],
).paddingAll(16),
),
const Divider(color: AppColors.greyColor),
const Divider(
color: AppColors.greyColor),
_buildButtons(),
],
),
);
},
)
: Utils.getNoDataWidget(context,
noDataText: "No medications today".needTranslation),
: Utils.getNoDataWidget(
context,
noDataText:
"No medications today".needTranslation,
),
),
),
],
@ -257,8 +355,9 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
);
}
//medicine card
Widget _buildMedHeader(ActivePrescriptionsResponseModel med) => Padding(
// medicine card
Widget _buildMedHeader(ActivePrescriptionsResponseModel med) =>
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -269,14 +368,16 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
child: Container(
width: 59.h,
height: 59.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(
color: AppColors.spacerLineColor,
borderRadius: 30.r,
hasShadow: false,
),
child: Utils.buildImgWithNetwork(
url: med.productImageString ?? "" ).circle(52.h)
),
url: med.productImageString ?? "",
iconColor: Colors.transparent)
.circle(52.h)),
),
SizedBox(width: 12.h),
Expanded(
@ -294,10 +395,19 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
spacing: 4,
runSpacing: 4,
children: [
AppCustomChipWidget(labelText: "Route: ${med.route}".needTranslation),
AppCustomChipWidget(labelText: "Frequency: ${med.frequency}".needTranslation),
AppCustomChipWidget(labelText: "Daily Dose: ${med.doseDailyQuantity}".needTranslation),
AppCustomChipWidget(labelText: "Duration: ${med.days}".needTranslation),
AppCustomChipWidget(
labelText:
"Route: ${med.route}".needTranslation),
AppCustomChipWidget(
labelText:
"Frequency: ${med.frequency}".needTranslation),
AppCustomChipWidget(
labelText:
"Daily Dose: ${med.doseDailyQuantity}"
.needTranslation),
AppCustomChipWidget(
labelText:
"Duration: ${med.days}".needTranslation),
],
),
],
@ -320,21 +430,25 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
SizedBox(width: 12.h),
Expanded(
child: CustomButton(
text: "Read Instructions".needTranslation, fontSize: 13.f, onPressed: () {})),
text: "Read Instructions".needTranslation,
fontSize: 13.f,
onPressed: () {})),
]),
);
Widget _buildToggle(int index) {
final value = medReminderStatus[index] ?? false;
Widget _buildToggle(ActivePrescriptionsResponseModel med) {
final medKey = _buildMedKey(med);
final value = medReminderStatus[medKey] ?? false;
return GestureDetector(
onTap: () async {
await showDoseDialog(selectedDayMeds[index], index);
setState(() {
if ((selectedDayMeds[index].selectedDoseTimes ?? []).any((t) => t != null)) {
medReminderStatus[index] = true;
}
});
await showDoseDialog(med);
final hasTime =
(med.selectedDoseTimes).any((t) => t != null);
medReminderStatus[medKey] = hasTime;
await saveReminderStatus(medKey, hasTime);
setState(() {});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
@ -342,11 +456,14 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
height: 28.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: value ? AppColors.lightGreenColor : AppColors.greyColor.withOpacity(0.3),
color: value
? AppColors.lightGreenColor
: AppColors.greyColor.withOpacity(0.3),
),
child: AnimatedAlign(
duration: const Duration(milliseconds: 200),
alignment: value ? Alignment.centerRight : Alignment.centerLeft,
alignment:
value ? Alignment.centerRight : Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.all(3),
child: Container(
@ -354,7 +471,9 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
height: 22.h,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: value ? AppColors.textGreenColor : AppColors.greyTextColor,
color: value
? AppColors.textGreenColor
: AppColors.greyTextColor,
),
),
),
@ -363,10 +482,16 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
);
}
Future<void> showDoseDialog(ActivePrescriptionsResponseModel med, int medIndex) {
final doses = med.frequencyNumber ?? 1;
Future<void> showDoseDialog(ActivePrescriptionsResponseModel med) {
final doses = _getDosesCount(med);
if (med.selectedDoseTimes.length != doses) {
med.selectedDoseTimes = List.generate(doses, (_) => null);
final old = med.selectedDoseTimes;
med.selectedDoseTimes =
List<String?>.filled(doses, null, growable: false);
for (int i = 0; i < old.length && i < doses; i++) {
med.selectedDoseTimes[i] = old[i];
}
}
return showModalBottomSheet(
@ -378,17 +503,20 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
height: 520.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bottomSheetBgColor,
customBorder: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
customBorder: const BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24),
),
hasShadow: true,
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"Reminders".needTranslation,
@ -400,7 +528,13 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
),
GestureDetector(
onTap: () => Navigator.pop(context),
child: Icon(Icons.close, color:AppColors.blackBgColor),
child: Utils.buildSvgWithAssets(
icon: AppAssets.close_bottom_sheet_icon,
height: 24.h,
width: 24.h,
iconColor:
AppColors.blackBgColor,
),
),
],
),
@ -415,45 +549,67 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
AppColors.labelColorYellow,
AppColors.purpleBg
][doseIndex % 4];
final doseLabel = "${doseIndex + 1}${getSuffix(doseIndex + 1)}";
final time = med.selectedDoseTimes[doseIndex] ?? "Not set yet";
final doseLabel =
"${doseIndex + 1}${_getSuffix(doseIndex + 1)}";
final time =
med.selectedDoseTimes[doseIndex] ??
"Not set yet";
return GestureDetector(
onTap: () {
Navigator.pop(context);
showTimePickerSheet(med, medIndex, doseIndex);
showTimePickerSheet(med, doseIndex);
},
child: Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(
vertical: 6, horizontal: 14),
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 14),
decoration: BoxDecoration(
color: badgeColor,
borderRadius: BorderRadius.circular(12),
),
child: Text(
doseLabel,
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "${doseIndex + 1}",
style: TextStyle(
color: AppColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 16.f,
),
),
WidgetSpan(
child: Transform.translate(
offset: const Offset(0, -4),
child: Text(
_getSuffix(doseIndex + 1),
style: TextStyle(
color: AppColors.whiteColor,
fontSize: 10.f,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
),
SizedBox(height: 8.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
@ -465,8 +621,13 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
),
),
),
Icon(Icons.arrow_forward_outlined,
size: 24.w, color: AppColors.textColor),
Utils.buildSvgWithAssets(
icon: AppAssets.arrow_forward,
height: 24.h,
width: 24.h,
iconColor:
AppColors.textColor,
),
],
),
SizedBox(height: 4.h),
@ -494,7 +655,7 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
void showTimePickerSheet(
ActivePrescriptionsResponseModel med, int medIndex, int doseIndex) {
ActivePrescriptionsResponseModel med, int doseIndex) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
@ -502,20 +663,24 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
builder: (_) => Container(
width: double.infinity,
height: 460.h,
decoration: BoxDecoration(
decoration: const BoxDecoration(
color: AppColors.bottomSheetBgColor,
borderRadius:
BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24),
),
),
child: ReminderTimerDialog(
med: med,
frequencyNumber: med.doseDailyQuantity ?? 1,
frequencyNumber: _getDosesCount(med),
doseIndex: doseIndex,
onTimeSelected: (String time) {
setState(() {
onTimeSelected: (String time) async {
final medKey = _buildMedKey(med);
med.selectedDoseTimes[doseIndex] = time;
medReminderStatus[medIndex] = true;
});
await saveDoseTime(medKey, doseIndex, time);
medReminderStatus[medKey] = true;
await saveReminderStatus(medKey, true);
setState(() {});
},
),
),
@ -529,7 +694,8 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
return GestureDetector(
onTap: () {
final vm =
Provider.of<ActivePrescriptionsViewModel>(context, listen: false);
Provider.of<ActivePrescriptionsViewModel>(context,
listen: false);
setState(() {
selectedDate = date;
selectedDayMeds = vm.getMedsForSelectedDay(date);
@ -547,7 +713,8 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
color: isSelected
? AppColors.primaryRedBorderColor
: AppColors.spacerLineColor,
width: 1),
width: 1,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
@ -577,14 +744,14 @@ class _ActiveMedicationPageState extends State<ActiveMedicationPage> {
);
}
String getSuffix(int day) {
String _getSuffix(int day) {
if (day == 1 || day == 21 || day == 31) return "st";
if (day == 2 || day == 22) return "nd";
if (day == 3 || day == 23) return "rd";
return "th";
}
}
}
class ReminderTimerDialog extends StatefulWidget {
@ -617,32 +784,94 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
["06:00 PM", "07:00 PM", "08:00 PM", "09:00 PM"], // Evening
];
String _getSuffix(int number) {
if (number == 1 || number == 21 || number == 31) return "st";
if (number == 2 || number == 22) return "nd";
if (number == 3 || number == 23) return "rd";
return "th";
}
@override
Widget build(BuildContext context) {
final int bucket = widget.doseIndex.clamp(0, 2);
final List<String> times = presetTimes[bucket];
return Padding(
padding: const EdgeInsets.all(16),
child: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bottomSheetBgColor,
customBorder: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
customBorder: const BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24),
),
hasShadow: true,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Time for ${widget.doseIndex + 1} dose".needTranslation,
style: TextStyle(fontSize: 18.f, fontWeight: FontWeight.bold),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: "Time for ",
style: TextStyle(
fontSize: 18.f,
fontWeight: FontWeight.bold,
color: AppColors.textColor,
),
),
TextSpan(
text: "${widget.doseIndex + 1}",
style: TextStyle(
fontSize: 18.f,
fontWeight: FontWeight.bold,
color: AppColors.textColor,
),
),
WidgetSpan(
child: Transform.translate(
offset: const Offset(0, -6),
child: Text(
_getSuffix(widget.doseIndex + 1),
style: TextStyle(
fontSize: 12.f,
fontWeight: FontWeight.bold,
color: AppColors.textColor,
),
),
),
),
TextSpan(
text: " reminder",
style: TextStyle(
fontSize: 18.f,
fontWeight: FontWeight.bold,
color: AppColors.textColor,
),
),
],
),
),
GestureDetector(
onTap: () => Navigator.pop(context),
child:Utils.buildSvgWithAssets(
icon: AppAssets.close_bottom_sheet_icon,
height: 24.h,
width: 24.h,
iconColor:
AppColors.blackBgColor,
),),
],
),
SizedBox(height: 12.h),
// Preset times
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.start,
children: times.map((t) {
bool selected = _selectedTime == t;
return AppCustomChipWidget(
@ -660,7 +889,7 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
),
borderRadius: BorderRadius.circular(12),
),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 14),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14),
onChipTap: () {
setState(() {
_selectedTime = t;
@ -675,9 +904,7 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
SizedBox(height: 25.h),
GestureDetector(
onTap: () {
setState(() {
showPicker = !showPicker;
});
setState(() => showPicker = !showPicker);
},
child: Center(
child: Column(
@ -687,7 +914,7 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
style: TextStyle(
fontSize: 48.f,
fontWeight: FontWeight.bold,
color: AppColors.textColor
color: AppColors.textColor,
),
),
Text(
@ -703,7 +930,6 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
),
),
SizedBox(height: 15.h),
// Time picker
if (showPicker)
SizedBox(
height: 100.h,
@ -717,15 +943,11 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
selectedTime.hour,
selectedTime.minute,
),
onDateTimeChanged: (DateTime newTime) {
onDateTimeChanged: (newTime) {
setState(() {
_selectedTime = null;
selectedTime = TimeOfDay(
hour: newTime.hour,
minute: newTime.minute,
);
bigTimeText =
selectedTime.format(context).split(" ")[0];
selectedTime = TimeOfDay(hour: newTime.hour, minute: newTime.minute);
bigTimeText = selectedTime.format(context).split(" ")[0];
});
},
),
@ -745,8 +967,7 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
),
),
onPressed: () async {
final selectedFormattedTime =
selectedTime.format(context);
final selectedFormattedTime = selectedTime.format(context);
widget.onTimeSelected(selectedFormattedTime);
try {
final parts = selectedFormattedTime.split(":");
@ -756,7 +977,6 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
if (isPM && hour != 12) hour += 12;
if (!isPM && hour == 12) hour = 0;
int totalMinutes = hour * 60 + minute;
// Call setCalender()
await setCalender(
context,
eventId: widget.med.itemId.toString(),
@ -768,14 +988,11 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
route: widget.med.route ?? "",
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Reminder added to calendar ✅".needTranslation)),
SnackBar(content: Text("Reminder added to calendar ✅".needTranslation)),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("Error while setting calendar: $e".needTranslation)),
SnackBar(content: Text("Error while setting calendar: $e".needTranslation)),
);
}
Navigator.pop(context);
@ -797,7 +1014,6 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
);
}
TimeOfDay _parseTime(String t) {
try {
int hour = int.parse(t.split(":")[0]);
@ -806,7 +1022,7 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
if (pm && hour != 12) hour += 12;
if (!pm && hour == 12) hour = 0;
return TimeOfDay(hour: hour, minute: minute);
} catch (e) {
} catch (_) {
return TimeOfDay.now();
}
}
@ -815,3 +1031,5 @@ class _ReminderTimerDialogState extends State<ReminderTimerDialog> {

Loading…
Cancel
Save