diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index ed2bba1..6dab797 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -729,7 +729,7 @@ var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatb class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT @@ -848,6 +848,7 @@ class ApiConsts { static final String getAllSharedRecordsByStatus = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus'; static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile'; static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus'; + static final String getActivePrescriptionsDetails = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID'; // static values for Api static final double appVersionID = 18.7; diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index a82a9ad..67464b3 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -3,6 +3,8 @@ import 'package:get_it/get_it.dart'; import 'package:hmg_patient_app_new/core/api/api_client.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/location_util.dart'; +import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_view_model.dart'; +import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; @@ -45,6 +47,8 @@ import 'package:local_auth/local_auth.dart'; import 'package:logger/web.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../features/active_prescriptions/active_prescriptions_repo.dart'; + GetIt getIt = GetIt.instance; class AppDependencies { @@ -103,6 +107,7 @@ class AppDependencies { getIt.registerLazySingleton(() => MedicalFileRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => ImmediateLiveCareRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerLazySingleton(() => EmergencyServicesRepoImp(loggerService: getIt(), apiClient: getIt())); + getIt.registerLazySingleton(() => ActivePrescriptionsRepoImp(loggerService: getIt(), apiClient: getIt())); // ViewModels // Global/shared VMs → LazySingleton @@ -202,6 +207,13 @@ class AppDependencies { ), ); + getIt.registerLazySingleton( + () => ActivePrescriptionsViewModel( + errorHandlerService: getIt(), + activePrescriptionsRepo: getIt() + ), + ); + // Screen-specific VMs → Factory // getIt.registerFactory( // () => BookAppointmentsViewModel( diff --git a/lib/core/utils/calendar_utils.dart b/lib/core/utils/calendar_utils.dart index 2068db9..8c0db18 100644 --- a/lib/core/utils/calendar_utils.dart +++ b/lib/core/utils/calendar_utils.dart @@ -266,7 +266,7 @@ setCalender(BuildContext context, eventId: eventId + (i.toString() + j.toString()), location: '', //event id with varitions ); - + print("Creating event #$j for day $i → $actualDate"); actualDate = DateTime(actualDate.year, actualDate.month, actualDate.day, 8, 0); } actualDate = Jiffy.parseFromDateTime(actualDate).add(days: 1).dateTime; diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index a88d9c2..1fc3806 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -670,7 +670,7 @@ class Utils { } /// Widget to build an SVG from network - static Widget buildImgWithNetwork({required String url, required Color iconColor, bool isDisabled = false, double width = 24, double height = 24, BoxFit fit = BoxFit.cover, ImageErrorWidgetBuilder? errorBuilder}) { + static Widget buildImgWithNetwork({required String url, bool isDisabled = false, double width = 24, double height = 24, BoxFit fit = BoxFit.cover, ImageErrorWidgetBuilder? errorBuilder}) { return Image.network( url, width: width, diff --git a/lib/features/active_prescriptions/active_prescriptions_repo.dart b/lib/features/active_prescriptions/active_prescriptions_repo.dart index 847d6e8..437f364 100644 --- a/lib/features/active_prescriptions/active_prescriptions_repo.dart +++ b/lib/features/active_prescriptions/active_prescriptions_repo.dart @@ -2,7 +2,6 @@ import 'package:dartz/dartz.dart'; import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart'; - import '../../core/api/api_client.dart'; import '../../core/api_consts.dart'; import '../../core/common_models/generic_api_model.dart'; @@ -11,7 +10,7 @@ import '../../services/logger_service.dart'; abstract class ActivePrescriptionsRepo { - Future>> getActivePrescriptionsDetails(); + Future>>> getActivePrescriptionsDetails(); } @@ -23,10 +22,10 @@ class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo { @override - Future>> getActivePrescriptionsDetails() async + Future>>> getActivePrescriptionsDetails() async { try { - GenericApiModel? apiResponse; + GenericApiModel>? apiResponse; Failure? failure; await apiClient.post( ApiConsts.getActivePrescriptionsDetails, @@ -36,18 +35,20 @@ class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo { }, onSuccess: (response, statusCode, {messageStatus, errorMessage}) { try { - // final list = response['GetActivePrescriptionReportByPatientIDList']; - - // final prescriptionLists = list.map((item) => ActivePrescriptionsResponseModel.fromJson(item as Map)).toList().cast(); + var list = response['List_ActiveGetPrescriptionReportByPatientID']; + var res = list + .map( + (item) => ActivePrescriptionsResponseModel.fromJson(item)) + .toList(); - apiResponse = GenericApiModel( + apiResponse = GenericApiModel>( messageStatus: messageStatus, statusCode: statusCode, errorMessage: null, - data: response, + // data: response, + data: res ); - return ['List_ActiveGetPrescriptionReportByPatientID']; - //apiResponse; + return apiResponse; } catch (e) { failure = DataParsingFailure(e.toString()); } @@ -61,39 +62,4 @@ class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo { } } - - - - // - // Future> getActiveMedications() { - // try { - // GenericApiModel? apiResponse; - // Failure? failure; - // return apiClient.post( - // ApiConsts.getActivePrescriptionsDetails, - // body: patientDeviceDataRequest, - // onFailure: (error, statusCode, {messageStatus, failureType}) { - // failure = failureType; - // }, - // onSuccess: (response, statusCode, {messageStatus, errorMessage}) { - // try { - // apiResponse = GenericApiModel( - // messageStatus: messageStatus, - // statusCode: statusCode, - // errorMessage: errorMessage, - // data: response, - // ); - // } catch (e) { - // failure = DataParsingFailure(e.toString()); - // } - // }, - // ).then((_) { - // if (failure != null) return Left(failure!); - // if (apiResponse == null) return Left(ServerFailure("Unknown error")); - // return Right(apiResponse!); - // }); - // } catch (e) { - // return Future.value(Left(UnknownFailure(e.toString()))); - // } - // } } \ No newline at end of file diff --git a/lib/features/active_prescriptions/active_prescriptions_view_model.dart b/lib/features/active_prescriptions/active_prescriptions_view_model.dart index d995f96..03f84ea 100644 --- a/lib/features/active_prescriptions/active_prescriptions_view_model.dart +++ b/lib/features/active_prescriptions/active_prescriptions_view_model.dart @@ -4,13 +4,17 @@ import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_ import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; -class ActivePrescriptionsViewModel extends ChangeNotifier { +class ActivePrescriptionsViewModel extends ChangeNotifier { bool isActivePrescriptionsDetailsLoading = false; - late ActivePrescriptionsRepo activePrescriptionsRepo; + late ActivePrescriptionsRepo activePrescriptionsRepo; late ErrorHandlerService errorHandlerService; - // Prescription Orders Lists + ActivePrescriptionsViewModel({ + required this.activePrescriptionsRepo, + required this.errorHandlerService, + }); + List activePrescriptionsDetailsList = []; initActivePrescriptionsViewModel() { @@ -20,38 +24,172 @@ class ActivePrescriptionsViewModel extends ChangeNotifier { setPrescriptionsDetailsLoading() { isActivePrescriptionsDetailsLoading = true; - // activePrescriptionsDetailsList.clear(); notifyListeners(); } - Future getActiveMedications( {Function(dynamic)? onSuccess, Function(String)? onError}) - async { + // Get medications list + Future getActiveMedications({ + Function(dynamic)? onSuccess, + Function(String)? onError, + }) async { final result = await activePrescriptionsRepo.getActivePrescriptionsDetails(); result.fold( (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { - if (apiResponse.messageStatus == 2) { - // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); - } else if (apiResponse.messageStatus == 1) { - activePrescriptionsDetailsList = apiResponse.data!; - isActivePrescriptionsDetailsLoading = false; + if (apiResponse.messageStatus == 1) { + activePrescriptionsDetailsList = apiResponse.data ?? []; notifyListeners(); - if (onSuccess != null) { - onSuccess(apiResponse); - print(activePrescriptionsDetailsList.length); - } + if (onSuccess != null) onSuccess(apiResponse.data); } }, ); } + DateTime parseDate(String? date) { + if (date == null) return DateTime.now(); + final regex = RegExp(r"\/Date\((\d+)([+-]\d+)?\)\/"); + final match = regex.firstMatch(date); + if (match != null) { + final millis = int.parse(match.group(1)!); + return DateTime.fromMillisecondsSinceEpoch(millis); + } + 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 generateMedicationDays(ActivePrescriptionsResponseModel med) { + final start = parseDate(med.startDate); + final duration = med.days ?? 0; + final frequency = (med.frequency ?? "").toLowerCase().trim(); + + List 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; + } + } + + // 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))); + } + } + + // 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 = {}; + for (final d in result) { + unique["${d.year}-${d.month}-${d.day}"] = d; + } + return unique.values.toList()..sort((a, b) => a.compareTo(b)); + } + bool sameYMD(DateTime a, DateTime b) => + a.year == b.year && a.month == b.month && a.day == b.day; + // Filter medications for selected day + List getMedsForSelectedDay(DateTime selectedDate) { + final target = DateTime(selectedDate.year, selectedDate.month, selectedDate.day); + return activePrescriptionsDetailsList.where((med) { + final days = generateMedicationDays(med); + return days.any((d) => sameYMD(d, target)); + }).toList(); + } } + + + diff --git a/lib/features/active_prescriptions/models/active_prescriptions_response_model.dart b/lib/features/active_prescriptions/models/active_prescriptions_response_model.dart index 878e191..eb216a6 100644 --- a/lib/features/active_prescriptions/models/active_prescriptions_response_model.dart +++ b/lib/features/active_prescriptions/models/active_prescriptions_response_model.dart @@ -7,7 +7,7 @@ class ActivePrescriptionsResponseModel { dynamic companyName; int? days; dynamic doctorName; - int? doseDailyQuantity; + int? doseDailyQuantity; // doses per day String? frequency; int? frequencyNumber; dynamic image; @@ -23,7 +23,7 @@ class ActivePrescriptionsResponseModel { dynamic patientName; dynamic phoneOffice1; dynamic prescriptionQr; - int? prescriptionTimes; + dynamic prescriptionTimes; dynamic productImage; String? productImageBase64; String? productImageString; @@ -35,6 +35,10 @@ class ActivePrescriptionsResponseModel { int? scaleOffset; String? startDate; + // ✅ Added for reminder feature + List selectedDoseTimes = []; + bool isReminderOn = false; // toggle status + ActivePrescriptionsResponseModel({ this.address, this.appointmentNo, @@ -69,47 +73,57 @@ class ActivePrescriptionsResponseModel { this.sku, this.scaleOffset, this.startDate, - }); - factory ActivePrescriptionsResponseModel.fromRawJson(String str) => ActivePrescriptionsResponseModel.fromJson(json.decode(str)); + // ✅ Default values for new fields (won’t break API) + List? selectedDoseTimes, + this.isReminderOn = false, + }) : selectedDoseTimes = selectedDoseTimes ?? []; + + factory ActivePrescriptionsResponseModel.fromRawJson(String str) => + ActivePrescriptionsResponseModel.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); - factory ActivePrescriptionsResponseModel.fromJson(Map json) => ActivePrescriptionsResponseModel( - address: json["Address"], - appointmentNo: json["AppointmentNo"], - clinic: json["Clinic"], - companyName: json["CompanyName"], - days: json["Days"], - doctorName: json["DoctorName"], - doseDailyQuantity: json["DoseDailyQuantity"], - frequency: json["Frequency"], - frequencyNumber: json["FrequencyNumber"], - image: json["Image"], - imageExtension: json["ImageExtension"], - imageSrcUrl: json["ImageSRCUrl"], - imageString: json["ImageString"], - imageThumbUrl: json["ImageThumbUrl"], - isCovered: json["IsCovered"], - itemDescription: json["ItemDescription"], - itemId: json["ItemID"], - orderDate: json["OrderDate"], - patientId: json["PatientID"], - patientName: json["PatientName"], - phoneOffice1: json["PhoneOffice1"], - prescriptionQr: json["PrescriptionQR"], - prescriptionTimes: json["PrescriptionTimes"], - productImage: json["ProductImage"], - productImageBase64: json["ProductImageBase64"], - productImageString: json["ProductImageString"], - projectId: json["ProjectID"], - projectName: json["ProjectName"], - remarks: json["Remarks"], - route: json["Route"], - sku: json["SKU"], - scaleOffset: json["ScaleOffset"], - startDate: json["StartDate"], - ); + factory ActivePrescriptionsResponseModel.fromJson(Map json) => + ActivePrescriptionsResponseModel( + address: json["Address"], + appointmentNo: json["AppointmentNo"], + clinic: json["Clinic"], + companyName: json["CompanyName"], + days: json["Days"], + doctorName: json["DoctorName"], + doseDailyQuantity: json["DoseDailyQuantity"], + frequency: json["Frequency"], + frequencyNumber: json["FrequencyNumber"], + image: json["Image"], + imageExtension: json["ImageExtension"], + imageSrcUrl: json["ImageSRCUrl"], + imageString: json["ImageString"], + imageThumbUrl: json["ImageThumbUrl"], + isCovered: json["IsCovered"], + itemDescription: json["ItemDescription"], + itemId: json["ItemID"], + orderDate: json["OrderDate"], + patientId: json["PatientID"], + patientName: json["PatientName"], + phoneOffice1: json["PhoneOffice1"], + prescriptionQr: json["PrescriptionQR"], + prescriptionTimes: json["PrescriptionTimes"], + productImage: json["ProductImage"], + productImageBase64: json["ProductImageBase64"], + productImageString: json["ProductImageString"], + projectId: json["ProjectID"], + projectName: json["ProjectName"], + remarks: json["Remarks"], + route: json["Route"], + sku: json["SKU"], + scaleOffset: json["ScaleOffset"], + startDate: json["StartDate"], + + // ✅ Ensure local reminder values are not overwritten by API + selectedDoseTimes: [], + isReminderOn: false, + ); Map toJson() => { "Address": address, @@ -145,5 +159,7 @@ class ActivePrescriptionsResponseModel { "SKU": sku, "ScaleOffset": scaleOffset, "StartDate": startDate, + + }; } diff --git a/lib/main.dart b/lib/main.dart index 259ce3b..5a33d02 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,7 @@ import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; @@ -129,6 +130,9 @@ void main() async { ), ChangeNotifierProvider( create: (_) => getIt.get(), + ), + ChangeNotifierProvider( + create: (_) => getIt.get(), ) ], child: MyApp()), ), diff --git a/lib/presentation/active_medication/active_medication_page.dart b/lib/presentation/active_medication/active_medication_page.dart index 6394002..aa2abe5 100644 --- a/lib/presentation/active_medication/active_medication_page.dart +++ b/lib/presentation/active_medication/active_medication_page.dart @@ -1,355 +1,538 @@ -import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; -// import 'package:sizer/sizer.dart'; -import '../../core/dependencies.dart'; +import 'package:flutter/cupertino.dart'; +import '../../core/app_assets.dart'; +import '../../core/utils/calendar_utils.dart'; import '../../features/active_prescriptions/active_prescriptions_view_model.dart'; import '../../features/active_prescriptions/models/active_prescriptions_response_model.dart'; import '../../generated/locale_keys.g.dart'; -import '../../services/dialog_service.dart'; import '../../theme/colors.dart'; import '../../widgets/appbar/app_bar_widget.dart'; import 'package:intl/intl.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; -// import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; - 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'; class ActiveMedicationPage extends StatefulWidget { - //inal List activePrescriptionsResponseModel; - - ActiveMedicationPage({super.key, }); - - - + const ActiveMedicationPage({super.key}); @override State createState() => _ActiveMedicationPageState(); } class _ActiveMedicationPageState extends State { - late DateTime currentDate; - late DateTime selectedDate; - - + late DateTime currentDate; + late DateTime selectedDate; + List selectedDayMeds = []; ActivePrescriptionsViewModel? activePreVM; + Map medReminderStatus = {}; @override - void initState() { - activePreVM = Provider.of(context, listen: false); - activePreVM?.getActiveMedications(); - print(activePreVM?.activePrescriptionsDetailsList); + void initState() { super.initState(); currentDate = DateTime.now(); selectedDate = currentDate; + WidgetsBinding.instance.addPostFrameCallback((_) async { + activePreVM = Provider.of(context, listen: false); + LoaderBottomSheet.showLoader(); + await activePreVM!.getActiveMedications( + onSuccess: (_) { + LoaderBottomSheet.hideLoader(); + final todayMeds = activePreVM!.getMedsForSelectedDay(selectedDate); + setState(() { + selectedDayMeds = todayMeds; + }); + }, + onError: (_) { + LoaderBottomSheet.hideLoader(); + }, + ); + activePreVM!.addListener(() { + if (!mounted) return; + final medsForDay = activePreVM!.getMedsForSelectedDay(selectedDate); + setState(() => selectedDayMeds = medsForDay); + }); + }); } -// Generate today + next 6 days - List getUpcomingDays() { - return List.generate(7, (index) => currentDate.add(Duration(days: index))); - } - // on/off toggle - bool isOn = true; - - get index => null; + List getUpcomingDays() => List.generate(7, (index) => currentDate.add(Duration(days: index))); @override Widget build(BuildContext context) { - // activePreVM = Provider.of(context, listen: false); - List days = getUpcomingDays(); - int dayIndex = selectedDate.difference(currentDate).inDays; - String dateText = "${selectedDate.day}${getSuffix(selectedDate.day)} ${DateFormat.MMMM().format(selectedDate)} "; - return Scaffold( + final days = getUpcomingDays(); + final dateText = "${selectedDate.day}${getSuffix(selectedDate.day)} ${DateFormat.MMMM().format(selectedDate)}"; + return Scaffold( backgroundColor: AppColors.scaffoldBgColor, appBar: CustomAppBar( - onBackPressed: () { - Navigator.of(context).pop(); - }, - onLanguageChanged: (lang) {}, - hideLogoAndLang: true, + onBackPressed: () => Navigator.of(context).pop(), + onLanguageChanged: (_) {}, + hideLogoAndLang: true, ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 65.h, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: days.length, - // itemCount: widget.details.length, - itemBuilder: (context, index) { - DateTime day = days[index]; - String label = DateFormat('E').format(day); // Mon, Tue - return Padding( - padding: const EdgeInsets.only(right: 12), - child: buildDayCard(label, day), - ); - }, - ), - ), - SizedBox(height: 20.h), - -// Show full date text - Text( - dateText, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Active Medications".needTranslation, style: TextStyle( color: AppColors.textColor, - fontSize: 16.fSize, - fontWeight: FontWeight.w500), + fontSize: 27.f, + fontWeight: FontWeight.w600)), + SizedBox(height: 16.h), + SizedBox( + height: 65.h, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: days.length, + itemBuilder: (context, index) { + final day = days[index]; + final label = DateFormat('E').format(day); + return Padding( + padding: const EdgeInsets.only(right: 12), + child: buildDayCard(label, day), + ); + }, ), - Text( - "Medications".needTranslation, - style: TextStyle( - color: AppColors.primaryRedBorderColor,fontSize: 12.fSize, fontWeight: FontWeight.w500), - ), - SizedBox(height: 16.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24, - hasShadow: true,), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + ), + SizedBox(height: 20.h), + RichText( + text: TextSpan( children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(1), - child: Container( - width: 59.h, - height: 59.h, - decoration: BoxDecoration( - border: Border.all( - color: AppColors.spacerLineColor,// Border color - width: 1.0.h, ), - borderRadius: BorderRadius.circular(30),// Border width - ), - child: - Utils.buildImgWithNetwork(url: activePreVM!.activePrescriptionsDetailsList[index].productImageString.toString(),width: 26.h,) - ), - ), - SizedBox(width: 12.h), - Text( - activePreVM!.activePrescriptionsDetailsList[index].itemDescription.toString(), - style: TextStyle( - fontSize: 16.fSize, - height: 1.2.h, - fontWeight: FontWeight.w700, - color: Colors.black87), - ), - ], - ), - SizedBox(height: 12.h), - activePreVM!.activePrescriptionsDetailsList.length > 0 ? - Wrap( - direction: Axis.horizontal, - spacing: 4.h, - runSpacing: 4.h, - children: [ - AppCustomChipWidget( - labelText: "Route: ${activePreVM?.activePrescriptionsDetailsList[index].route}", - ), - AppCustomChipWidget( - labelText: "Frequency: ${activePreVM?.activePrescriptionsDetailsList[index].frequency}".needTranslation, - ), - AppCustomChipWidget( - labelText: "Daily Does ${activePreVM?.activePrescriptionsDetailsList[index].doseDailyQuantity}".needTranslation, - ), - AppCustomChipWidget( - labelText: "Duration: ${activePreVM?.activePrescriptionsDetailsList[index].days} ".needTranslation, - ), - ], - ): - Container( - child: Text("no data"), - ), - SizedBox(height: 12.h), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(Icons.info_outline, color: Colors.grey,), - SizedBox(width: 8.h), - Expanded( - child: Text( - "Remark: some remarks about the prescription will be here".needTranslation, - style: TextStyle( - fontSize: 10.fSize, - color: AppColors.greyTextColor, - fontWeight: FontWeight.w500, - ), - overflow: TextOverflow.visible, - ), - ) - ], - ), - ], - ).paddingAll(16), - const Divider( - indent: 0, - endIndent: 0, - thickness: 1, - color: AppColors.greyColor, + TextSpan( + text: "${selectedDate.day}", + style: TextStyle( + color: AppColors.textColor, + fontSize: 16, + fontWeight: FontWeight.w500, + ), ), - // Reminder Row - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 40.h, - height: 40.h, - decoration: BoxDecoration( - color: AppColors.greyColor, - borderRadius: BorderRadius.circular(10),// Border width - ), - child: Icon(Icons.notifications_sharp, color: AppColors.greyTextColor) - // MedicalFileCard( - // label: "Vaccine Info".needTranslation, - // textColor: AppColors.blackColor, - // backgroundColor: AppColors.whiteColor, - // svgIcon: AppAssets..bell, - // isLargeText: true, - // iconSize: 36.h, - // ) + WidgetSpan( + child: Transform.translate( + offset: const Offset(0, -4), + child: Text( + getSuffix(selectedDate.day), + style: const TextStyle( + fontSize: 12, + color: AppColors.textColor, + fontWeight: FontWeight.w500, + ), ), - SizedBox(width: 8.h), - Expanded( + ), + ), + TextSpan( + text: " ${DateFormat.MMMM().format(selectedDate)}", + style: const TextStyle( + color: AppColors.textColor, + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + Text("Medications".needTranslation, + style: TextStyle( + color: AppColors.primaryRedBorderColor, + fontSize: 12.f, + fontWeight: FontWeight.w500)), + SizedBox(height: 16.h), + Expanded( + child: SingleChildScrollView( + child: selectedDayMeds.isNotEmpty + ? ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: selectedDayMeds.length, + itemBuilder: (context, index) { + final med = selectedDayMeds[index]; + final doses = med.doseDailyQuantity ?? 1; + med.selectedDoseTimes ??= List.filled(doses, null); + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.r, + hasShadow: true, + ), + margin: EdgeInsets.all(10), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "Set Reminder", - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14.fSize, - color: AppColors.textColor), - ), - Text( - "Notify me before the consumption time", - style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12.fSize, - color: AppColors.textColorLight), + _buildMedHeader(med), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.info_outline, + color: AppColors.lightGreyTextColor, + size: 20, + ), + SizedBox(width: 6.h), + Expanded( + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "Remarks: ".needTranslation, + style: TextStyle( + color: AppColors.textColor, + fontWeight: FontWeight.w600, + fontSize: 10, + ), + ), + TextSpan( + text: "some remarks about the prescription will be here".needTranslation, + style: TextStyle( + color: AppColors.lightGreyTextColor, + fontWeight: FontWeight.normal, + fontSize: 10, + ), + ), + ], + ), + ), + ), + ], + ).paddingOnly(left: 16, right: 16), + const Divider(color: AppColors.greyColor), + // Reminder Section + GestureDetector( + onTap: () => showDoseDialog(med, index), + child: Row( + children: [ + Container( + width: 40.h, + height: 40.h, + alignment: Alignment.center, + decoration: BoxDecoration( + color: AppColors.greyColor, + borderRadius: BorderRadius.circular(10), + ), + child: Utils.buildSvgWithAssets( + icon: AppAssets.bell, + height: 24.h, + width: 24.h, + iconColor: AppColors.greyTextColor, + ), + ), + SizedBox(width: 12.h), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text("Set Reminder".needTranslation, + style: TextStyle( + fontSize: 14.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor)), + Text("Notify me before the consumption time".needTranslation, + style: TextStyle( + fontSize: 12.f, + color: AppColors.textColorLight, + )), + ], + ), + ), + _buildToggle(index) + ], + ).paddingAll(16), ), + const Divider(color: AppColors.greyColor), + _buildButtons(), ], - ).onPress(() { - DialogService dialogService = getIt.get(); - dialogService.showReminderBottomSheetWithoutHWithChild( - label: "Set the timer for reminder".needTranslation, - message: "", - child: ReminderTimerDialog(), - onOkPressed: () {}, - ); - }), + ), + ); + }, + ) + : Utils.getNoDataWidget(context, + noDataText: "No medications today".needTranslation), + ), + ), + ], + ).paddingAll(16), + ); + } + + //medicine card + Widget _buildMedHeader(ActivePrescriptionsResponseModel med) => Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(children: [ + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Container( + width: 59.h, + height: 59.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.spacerLineColor, + borderRadius: 30.r, + hasShadow: false, + ), + child: Utils.buildImgWithNetwork( + url: med.productImageString ?? "" ).circle(52.h) + ), + ), + SizedBox(width: 12.h), + Expanded( + child: Text( + med.itemDescription ?? "", + style: TextStyle( + fontSize: 16.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor), + ), + ), + ]), + SizedBox(height: 12.h), + Wrap( + 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), + ], + ), + ], + ), + ); + + Widget _buildButtons() => Padding( + padding: EdgeInsets.all(16), + child: Row(children: [ + Expanded( + child: CustomButton( + text: "Check Availability".needTranslation, + fontSize: 13.f, + onPressed: () {}, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.errorColor, + ), + ), + SizedBox(width: 12.h), + Expanded( + child: CustomButton( + text: "Read Instructions".needTranslation, fontSize: 13.f, onPressed: () {})), + ]), + ); + + Widget _buildToggle(int index) { + final value = medReminderStatus[index] ?? false; + + return GestureDetector( + onTap: () async { + await showDoseDialog(selectedDayMeds[index], index); + setState(() { + if ((selectedDayMeds[index].selectedDoseTimes ?? []).any((t) => t != null)) { + medReminderStatus[index] = true; + } + }); + }, + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + width: 50.h, + height: 28.h, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: value ? AppColors.lightGreenColor : AppColors.greyColor.withOpacity(0.3), + ), + child: AnimatedAlign( + duration: const Duration(milliseconds: 200), + alignment: value ? Alignment.centerRight : Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(3), + child: Container( + width: 22.h, + height: 22.h, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: value ? AppColors.textGreenColor : AppColors.greyTextColor, + ), + ), + ), + ), + ), + ); + } + + Future showDoseDialog(ActivePrescriptionsResponseModel med, int medIndex) { + final doses = med.frequencyNumber ?? 1; + if (med.selectedDoseTimes.length != doses) { + med.selectedDoseTimes = List.generate(doses, (_) => null); + } + + return showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (_) => Container( + width: double.infinity, + height: 520.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.bottomSheetBgColor, + customBorder: 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, + children: [ + Text( + "Reminders".needTranslation, + style: TextStyle( + fontSize: 20.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor, ), - GestureDetector( - onTap: () { - setState(() { - isOn = !isOn; - }); - }, - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - width: 50.h, - height: 28.h, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: isOn ? AppColors.lightGreenColor: AppColors.greyColor, ), - child: AnimatedAlign( - duration: const Duration(milliseconds: 200), - alignment: isOn ? Alignment.centerRight : Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.all(3), + GestureDetector( + onTap: () => Navigator.pop(context), + child: Icon(Icons.close, color:AppColors.blackBgColor), + ), + ], + ), + SizedBox(height: 20.h), + Expanded( + child: ListView.builder( + itemCount: doses, + itemBuilder: (context, doseIndex) { + final badgeColor = [ + AppColors.textGreenColor, + AppColors.infoColor, + AppColors.labelColorYellow, + AppColors.purpleBg + ][doseIndex % 4]; + + 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); + }, child: Container( - width: 22.h, - height: 22.h, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: isOn ? AppColors.textGreenColor : AppColors.greyTextColor, + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(16), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 16.r, + hasShadow: false, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.symmetric( + vertical: 6, horizontal: 14), + decoration: BoxDecoration( + color: badgeColor, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + doseLabel, + style: TextStyle( + color: AppColors.whiteColor, + fontWeight: FontWeight.bold, + fontSize: 16.f, + ), + ), + ), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + "Set reminder for $doseLabel dose", + style: TextStyle( + color: AppColors.textColor, + fontWeight: FontWeight.bold, + fontSize: 16.f, + ), + ), + ), + Icon(Icons.arrow_forward_outlined, + size: 24.w, color: AppColors.textColor), + ], + ), + SizedBox(height: 4.h), + Text( + time, + style: TextStyle( + fontSize: 12.f, + color: AppColors.greyTextColor, + fontWeight: FontWeight.w500, + ), + ), + ], ), ), - ), - ), + ); + }, ), ), - SizedBox(width: 2.h), - // Switch( - // value: isOn, - // onChanged: (value){ - // setState(() { - // isOn = value; - // }); - // }, - // activeColor: AppColors.lightGreenColor, - // activeTrackColor: AppColors.lightGreenColor, - // activeThumbColor: AppColors.textGreenColor, - // inactiveThumbColor: AppColors.greyTextColor, - // inactiveTrackColor: AppColors.greyColor, - // ), - ], - ).paddingAll(16), - const Divider( - indent: 0, - endIndent: 0, - thickness: 1, - color: AppColors.greyColor, - ), - -// Buttons - Row( - children: [ - Expanded( - child: CustomButton( - text: LocaleKeys.checkAvailability.tr(), - fontSize: 14.fSize, - onPressed: () async { - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.errorColor, - ), - ), - SizedBox(width: 12.h), - Expanded( - child: CustomButton( - text: LocaleKeys.readInstructions.tr(), - fontSize: 14.fSize, - onPressed: () async { - }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: AppColors.whiteColor, - ), - ), - ], - ).paddingAll(16), - ], - ), - ) - ] - ), + ], + ), + ), + ), + ); + } + void showTimePickerSheet( + ActivePrescriptionsResponseModel med, int medIndex, int doseIndex) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (_) => Container( + width: double.infinity, + height: 460.h, + decoration: BoxDecoration( + color: AppColors.bottomSheetBgColor, + borderRadius: + BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)), + ), + child: ReminderTimerDialog( + med: med, + frequencyNumber: med.doseDailyQuantity ?? 1, + doseIndex: doseIndex, + onTimeSelected: (String time) { + setState(() { + med.selectedDoseTimes[doseIndex] = time; + medReminderStatus[medIndex] = true; + }); + }, + ), ), ); } - Widget buildDayCard(String label, DateTime date,) { - bool isSelected = selectedDate.day == date.day && + Widget buildDayCard(String label, DateTime date) { + final isSelected = selectedDate.day == date.day && selectedDate.month == date.month && selectedDate.year == date.year; - return GestureDetector( onTap: () { + final vm = + Provider.of(context, listen: false); setState(() { selectedDate = date; + selectedDayMeds = vm.getMedsForSelectedDay(date); }); }, child: Container( @@ -357,36 +540,38 @@ class _ActiveMedicationPageState extends State { height: 65.h, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), - color: isSelected ? AppColors.secondaryLightRedBorderColor: AppColors.transparent, + color: isSelected + ? AppColors.secondaryLightRedBorderColor + : Colors.transparent, border: Border.all( - color: isSelected ? AppColors.primaryRedBorderColor : AppColors.spacerLineColor, - width: 1.0.h, - ), + color: isSelected + ? AppColors.primaryRedBorderColor + : AppColors.spacerLineColor, + width: 1), ), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - date.day == currentDate.day ? "Today".needTranslation : label, - style: TextStyle( - color: isSelected ? AppColors.primaryRedBorderColor : AppColors.greyTextColor, - fontSize: 12.fSize, - fontWeight: FontWeight.w500, - ), - ), - SizedBox(height: 5.h), - Text( - date.day.toString(), - style: TextStyle( - fontSize: 16.fSize, - fontWeight: FontWeight.bold, - color: isSelected ? AppColors.primaryRedBorderColor : AppColors.textColor, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + date.day == currentDate.day ? "Today" : label, + style: TextStyle( + color: isSelected + ? AppColors.primaryRedBorderColor + : AppColors.greyTextColor, + fontSize: 11.f, + fontWeight: FontWeight.w500), ), - ), - ], - ), + SizedBox(height: 5.h), + Text("${date.day}", + style: TextStyle( + fontSize: 16.f, + fontWeight: FontWeight.bold, + color: isSelected + ? AppColors.primaryRedBorderColor + : AppColors.textColor)) + ]), ), ), ); @@ -398,167 +583,235 @@ class _ActiveMedicationPageState extends State { if (day == 3 || day == 23) return "rd"; return "th"; } - - // Widget manageReminder(){ - // NavigationService navigationService = getIt(); - // return Container( - // width: 59, - // height: 59, - // decoration: BoxDecoration( - // border: Border.all( - // color: AppColors.spacerLineColor,// Border color - // width: 1.0, ), - // borderRadius: BorderRadius.circular(30),// Border width - // ), - // child: - // Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon,width: 30.h, height: 30.h) - // ); - // } } + + class ReminderTimerDialog extends StatefulWidget { - // final Function()? onSetReminderPress; - // final String message; - // - // const ReminderTimerDialog(this.onSetReminderPress, this.message, {super.key}); - const ReminderTimerDialog({super.key}); + final int frequencyNumber; + final int doseIndex; + final Function(String) onTimeSelected; + final ActivePrescriptionsResponseModel med; + + const ReminderTimerDialog({ + super.key, + required this.frequencyNumber, + required this.doseIndex, + required this.onTimeSelected, + required this.med, + }); @override State createState() => _ReminderTimerDialogState(); } class _ReminderTimerDialogState extends State { - final List options = ["Morning", "Afternoon", "Evening", "Midnight"]; - final List selectedTimes = ["Morning"]; // Default selection + TimeOfDay selectedTime = TimeOfDay.now(); + String? _selectedTime; + String bigTimeText = "00:00"; + bool showPicker = false; + final List> presetTimes = [ + ["06:00 AM", "07:00 AM", "08:00 AM", "09:00 AM"], // Morning + ["12:00 PM", "01:00 PM", "02:00 PM", "03:00 PM"], // Noon + ["06:00 PM", "07:00 PM", "08:00 PM", "09:00 PM"], // Evening + ]; @override Widget build(BuildContext context) { - return // - Column( - children: [ - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24, - hasShadow: true,), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - // Checkboxes list - children: options.map((time) => buildCircleCheckbox(time)).toList(), - ).paddingAll(16), - ), - SizedBox(height: 25.h), - // Buttons Row - Row( - children: [ - Expanded( - child: ElevatedButton.icon( - onPressed: () => Navigator.pop(context), - icon: const Icon(Icons.close, color: AppColors.errorColor), - label: Text( - LocaleKeys.cancel.tr(), - style: TextStyle( - color: AppColors.errorColor, - fontWeight: FontWeight.w500, - fontSize: 14.fSize + final int bucket = widget.doseIndex.clamp(0, 2); + final List 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)), + 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), + ), + SizedBox(height: 12.h), + // Preset times + Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.start, + children: times.map((t) { + bool selected = _selectedTime == t; + return AppCustomChipWidget( + labelText: t, + backgroundColor: selected + ? AppColors.lightGreenButtonColor + : AppColors.transparent, + textColor: AppColors.textColor, + shape: RoundedRectangleBorder( + side: BorderSide( + color: selected + ? AppColors.successColor + : AppColors.spacerLineColor, + width: 1.2, ), + borderRadius: BorderRadius.circular(12), ), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.secondaryLightRedColor, - elevation: 0, - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 14), + onChipTap: () { + setState(() { + _selectedTime = t; + selectedTime = _parseTime(t); + bigTimeText = selectedTime.format(context).split(" ")[0]; + showPicker = false; + }); + }, + ); + }).toList(), + ), + SizedBox(height: 25.h), + GestureDetector( + onTap: () { + setState(() { + showPicker = !showPicker; + }); + }, + child: Center( + child: Column( + children: [ + Text( + bigTimeText, + style: TextStyle( + fontSize: 48.f, + fontWeight: FontWeight.bold, + color: AppColors.textColor + ), ), - ), + Text( + selectedTime.period == DayPeriod.am ? "AM" : "PM", + style: TextStyle( + fontSize: 20.f, + fontWeight: FontWeight.bold, + color: AppColors.greyTextColor, + ), + ), + ], ), ), - SizedBox(width: 12.h), - Expanded( - child: ElevatedButton.icon( - onPressed: () { - Navigator.pop(context, selectedTimes); + ), + SizedBox(height: 15.h), + // Time picker + if (showPicker) + SizedBox( + height: 100.h, + child: CupertinoDatePicker( + mode: CupertinoDatePickerMode.time, + use24hFormat: false, + initialDateTime: DateTime( + 2024, + 1, + 1, + selectedTime.hour, + selectedTime.minute, + ), + onDateTimeChanged: (DateTime newTime) { + setState(() { + _selectedTime = null; + selectedTime = TimeOfDay( + hour: newTime.hour, + minute: newTime.minute, + ); + bigTimeText = + selectedTime.format(context).split(" ")[0]; + }); }, - icon: const Icon(Icons.notifications_rounded), - label: Text( - LocaleKeys.setReminder.tr(), - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14.fSize + ), + ), + SizedBox(height: 25.h), + Row( + children: [ + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: AppColors.successColor, + foregroundColor: AppColors.whiteColor, + elevation: 0, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.successColor, - foregroundColor: AppColors.whiteColor, - elevation: 0, - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + onPressed: () async { + final selectedFormattedTime = + selectedTime.format(context); + widget.onTimeSelected(selectedFormattedTime); + try { + final parts = selectedFormattedTime.split(":"); + int hour = int.parse(parts[0]); + int minute = int.parse(parts[1].split(" ")[0]); + bool isPM = selectedFormattedTime.contains("PM"); + 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(), + selectedMinutes: totalMinutes, + frequencyNumber: widget.frequencyNumber, + days: widget.med.days ?? 1, + orderDate: widget.med.orderDate ?? "", + itemDescriptionN: widget.med.itemDescription ?? "", + route: widget.med.route ?? "", + ); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Reminder added to calendar ✅".needTranslation)), + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text("Error while setting calendar: $e".needTranslation)), + ); + } + Navigator.pop(context); + }, + child: Text( + LocaleKeys.save.tr(), + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16.f, + ), ), ), ), - ), - ], - ), - SizedBox(height: 30.h), - ], - ); - } - - Widget buildCircleCheckbox(String label) { - final bool isSelected = selectedTimes.contains(label); - return InkWell( - onTap: () { - setState(() { - if (isSelected) { - selectedTimes.remove(label); - } else { - selectedTimes.add(label); - } - }); - }, - borderRadius: BorderRadius.circular(25), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - // Custom circle checkbox - Container( - width: 15.h, - height: 15.h, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: isSelected ? AppColors.spacerLineColor: AppColors.spacerLineColor, - width: 1.h, - ), - color: isSelected ? AppColors.errorColor: AppColors.transparent, - ), - ), - SizedBox(width: 12.h), - // Label text - Text( - label, - style: TextStyle(fontSize: 16.fSize, color: Colors.black87), + ], ), ], - ), + ).paddingAll(16), ), ); } - void showCircleCheckboxDialog(BuildContext context) async { - final selected = await showDialog>( - context: context, - builder: (context) => const ReminderTimerDialog(), - ); - - if (selected != null && selected.isNotEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Reminders set for: ${selected.join(', ').needTranslation}')), - ); + TimeOfDay _parseTime(String t) { + try { + int hour = int.parse(t.split(":")[0]); + int minute = int.parse(t.split(":")[1].split(" ")[0]); + bool pm = t.contains("PM"); + if (pm && hour != 12) hour += 12; + if (!pm && hour == 12) hour = 0; + return TimeOfDay(hour: hour, minute: minute); + } catch (e) { + return TimeOfDay.now(); } } } + + + diff --git a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart index a48ca10..28a55ba 100644 --- a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart +++ b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart @@ -119,7 +119,7 @@ class TrackingScreen extends StatelessWidget { backgroundColor: AppColors.lightRedButtonColor, borderColor: Colors.transparent, text: "Share Your Live Locatin on Whatsapp".needTranslation, - fontSize: 12.fSize, + fontSize: 12.f, textColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor, onPressed: () {}, @@ -170,7 +170,7 @@ class TrackingScreen extends StatelessWidget { return Row( spacing: 16.h, children: [ - Utils.buildImgWithNetwork(url: "", iconColor: Colors.transparent) + Utils.buildImgWithNetwork(url: "",) .circle(52.h), Expanded( child: Column( @@ -244,7 +244,7 @@ class TrackingScreen extends StatelessWidget { TextSpan( text: "Please wait for the call".needTranslation, style: TextStyle( - fontSize: 21.fSize, + fontSize: 21.f, fontWeight: FontWeight.w600, color: AppColors.textColor, ), @@ -252,7 +252,7 @@ class TrackingScreen extends StatelessWidget { TextSpan( text: "...".needTranslation, style: TextStyle( - fontSize: 21.fSize, + fontSize: 21.f, fontWeight: FontWeight.w600, color: AppColors.errorColor, ), @@ -265,7 +265,7 @@ class TrackingScreen extends StatelessWidget { TextSpan( text: "15:30".needTranslation, style: TextStyle( - fontSize: 21.fSize, + fontSize: 21.f, fontWeight: FontWeight.w600, color: AppColors.textColor, ), @@ -273,7 +273,7 @@ class TrackingScreen extends StatelessWidget { TextSpan( text: " mins ".needTranslation, style: TextStyle( - fontSize: 21.fSize, + fontSize: 21.f, fontWeight: FontWeight.w600, color: AppColors.errorColor, ), @@ -281,7 +281,7 @@ class TrackingScreen extends StatelessWidget { TextSpan( text: "to hospital".needTranslation, style: TextStyle( - fontSize: 21.fSize, + fontSize: 21.f, fontWeight: FontWeight.w600, color: AppColors.textColor, ), diff --git a/lib/presentation/emergency_services/widgets/nearestERItem.dart b/lib/presentation/emergency_services/widgets/nearestERItem.dart index 3dc2aa1..6a8fdbc 100644 --- a/lib/presentation/emergency_services/widgets/nearestERItem.dart +++ b/lib/presentation/emergency_services/widgets/nearestERItem.dart @@ -49,7 +49,7 @@ class NearestERItem extends StatelessWidget { ).toShimmer2(isShow: isLoading) : Utils.buildImgWithNetwork( url: nearestERItem.projectImageURL ?? '', - iconColor: Colors.transparent, + // iconColor: Colors.transparent, ).circle(24.h).toShimmer2(isShow: isLoading), const SizedBox(width: 12), Expanded( diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 2f72227..0e9eb30 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -351,7 +351,16 @@ class _LandingPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Quick Links".needTranslation.toText16(isBold: true), + CustomButton(text: "Quick Links".needTranslation, + onPressed: () { + Navigator.of(context).push( + CustomPageRoute( + page: ActiveMedicationPage(), + ), + ); + }, + ), + // "Quick Links".needTranslation.toText16(isBold: true), Row( children: [ "View medical file".needTranslation.toText12(color: AppColors.primaryRedColor), diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index ce2f87c..3aab1de 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -77,5 +77,7 @@ static const Color calenderTextColor = Color(0xFFD0D0D0); static const Color lightGreenButtonColor = Color(0x2618C273); static const Color lightRedButtonColor = Color(0x1AED1C2B); +static const Color lightGreyTextColor = Color(0xFF959595); +static const Color labelColorYellow = Color(0xFFFBCB6E); }