|
|
|
|
@ -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> {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|