pull/208/head
haroon amjad 1 day ago
parent f7446d0d41
commit 4959392f74

@ -92,7 +92,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" tools:node="remove"/>
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />

@ -566,6 +566,8 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
final appointmentsList = (list as List).map((item) => GetFavoriteDoctorsListModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetFavoriteDoctorsListModel>();
appointmentsList.removeWhere((element) => element.isActive == false);
apiResponse = GenericApiModel<List<GetFavoriteDoctorsListModel>>(
messageStatus: messageStatus,
statusCode: statusCode,

@ -15,7 +15,7 @@ class NotificationsViewModel extends ChangeNotifier {
List<NotificationResponseModel> notificationsList = [];
int currentPage = 0;
int pagingSize = 15;
int pagingSize = 50;
int notificationStatusID = 2; // Default to status 2 (e.g., unread)
NotificationsViewModel({

@ -258,7 +258,8 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
CustomPageRoute(
page: InsuranceHomePage(),
),
);
)
.then((val) {});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.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';
@ -8,7 +9,9 @@ import 'package:hmg_patient_app_new/features/book_appointments/models/laser_body
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/laser_body_parts.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:provider/provider.dart';
import 'package:smooth_corner/smooth_corner.dart';
class BodyPartsListing extends StatelessWidget {
final List<LaserBodyPart> parts;
@ -49,11 +52,7 @@ class BodyPartsListing extends StatelessWidget {
Visibility(
visible: !isLoading,
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 85 / 107,
crossAxisSpacing: 4.h,
mainAxisSpacing: 21.h),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 75 / 107, crossAxisSpacing: 4.h, mainAxisSpacing: 21.h),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: parts.length,
@ -73,7 +72,7 @@ class BodyPartsListing extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 130 / 120,
aspectRatio: 150 / 140,
child: FittedBox(
fit: BoxFit.fitWidth,
child: Stack(
@ -112,14 +111,41 @@ class BodyPartsListing extends StatelessWidget {
child: Center(
child: Column(
children: [
context.read<BookAppointmentsViewModel>().getLaserProcedureNameWRTLanguage(parts[index]).toText12(isBold: true, color: AppColors.textColor, isCenter: true, maxLine: 2),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"${LocaleKeys.mins.tr()}: ".toText12(isBold: true, color: AppColors.textColor, isCenter: true, maxLine: 2),
parts[index].timeDuration!.toText12(isBold: true, color: AppColors.textColor, isCenter: true, maxLine: 2),
],
),
context.read<BookAppointmentsViewModel>().getLaserProcedureNameWRTLanguage(parts[index]).toText12(isBold: true, color: AppColors.textColor, isCenter: true, maxLine: 1),
SizedBox(height: 4.h),
AppCustomChipWidget(
backgroundColor: _isSelected ? AppColors.chipSecondaryLightRedColor : AppColors.whiteColor,
textColor: _isSelected ? AppColors.chipPrimaryRedBorderColor : AppColors.blackColor,
// labelText: "${parts[index].timeDuration!} ${LocaleKeys.mins.tr()}",
richText: "${parts[index].timeDuration!} ${LocaleKeys.mins.tr()}".toText12(
fontWeight: FontWeight.w500,
color: _isSelected ? AppColors.chipPrimaryRedBorderColor : AppColors.blackColor,
),
icon: AppAssets.waiting_time_clock,
iconHasColor: true,
iconColor: _isSelected ? AppColors.chipPrimaryRedBorderColor : AppColors.blackColor,
iconSize: 16,
labelPadding: EdgeInsetsDirectional.only(start: 8.w, end: 8.w),
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.w),
deleteIconSize: Size(18.w, 18.h),
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.circular(10.r),
smoothness: 10,
side: BorderSide(color: _isSelected ? AppColors.chipPrimaryRedBorderColor : AppColors.borderGrayColor, width: 1),
)),
// AppCustomChipWidget(
// labelText: "${parts[index].timeDuration!} ${LocaleKeys.mins.tr()}",
// backgroundColor: AppColors.whiteColor,
// // textColor: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus),
// ),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// "${LocaleKeys.mins.tr()}: ".toText12(isBold: true, color: AppColors.textColor, isCenter: true, maxLine: 2),
// parts[index].timeDuration!.toText12(isBold: true, color: AppColors.textColor, isCenter: true, maxLine: 2),
// ],
// ),
],
),
),

@ -171,7 +171,22 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
CustomPageRoute(
page: InsuranceHomePage(),
),
);
)
.then((val) async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingFeesPleaseWait.tr());
await immediateLiveCareVM.getLiveCareImmediateAppointmentFees(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
}, onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
@ -343,15 +358,17 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
bool cameraGranted = statuses[Permission.camera]?.isGranted ?? false;
bool micGranted = statuses[Permission.microphone]?.isGranted ?? false;
bool notifGranted = statuses[Permission.notification]?.isGranted ?? false;
bool alertWindowGranted = Platform.isAndroid ? (statuses[Permission.systemAlertWindow]?.isGranted ?? false) : true;
// If all required permissions are already granted
if (cameraGranted && micGranted && notifGranted) return true;
if (cameraGranted && micGranted && notifGranted && alertWindowGranted) return true;
// Collect only the missing permissions
final missing = <Permission>[];
if (!cameraGranted) missing.add(Permission.camera);
if (!micGranted) missing.add(Permission.microphone);
if (!notifGranted) missing.add(Permission.notification);
if (Platform.isAndroid && !alertWindowGranted) missing.add(Permission.systemAlertWindow);
// If any of the missing permissions are permanently denied/restricted -> open settings (single dialog)
final permanent = missing.where((p) => (statuses[p]?.isPermanentlyDenied ?? false) || (statuses[p]?.isRestricted ?? false)).toList();
@ -392,6 +409,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
cameraGranted = newStatuses[Permission.camera]?.isGranted ?? cameraGranted;
micGranted = newStatuses[Permission.microphone]?.isGranted ?? micGranted;
notifGranted = newStatuses[Permission.notification]?.isGranted ?? notifGranted;
alertWindowGranted = newStatuses[Permission.systemAlertWindow]?.isGranted ?? alertWindowGranted;
// If any requested permission is now permanently denied -> open settings
final newlyPermanent = missing.where((p) => (newStatuses[p]?.isPermanentlyDenied ?? false) || (newStatuses[p]?.isRestricted ?? false)).toList();
@ -407,7 +425,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
return false;
}
return cameraGranted && micGranted && notifGranted;
return cameraGranted && micGranted && notifGranted && alertWindowGranted;
}
// Future<bool> askVideoCallPermission() async {

@ -199,6 +199,7 @@ class _LandingPageState extends State<LandingPage> {
Navigator.of(context).push(
CustomPageRoute(
direction: AxisDirection.down,
page: FamilyMedicalScreen(),
),
);

@ -45,6 +45,7 @@ class WelcomeWidget extends StatelessWidget {
getIt.get<ProfileSettingsViewModel>().getProfileSettings();
Navigator.of(context).push(
CustomPageRoute(
direction: getIt.get<AppState>().isArabic() ? AxisDirection.right : AxisDirection.left,
page: ProfileSettings(),
),
);

@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
@ -121,17 +122,27 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget {
insuranceCardImage: "",
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.success.tr(context: context),
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.insuranceRequestSubmittedSuccessfully.tr(context: context)),
callBackFunc: () {
Navigator.pop(context);
},
isFullScreen: false,
isCloseButtonVisible: false,
isAutoDismiss: true
);
getIt.get<DialogService>().showCommonBottomSheetWithoutH(
message: LocaleKeys.insuranceRequestSubmittedSuccessfully.tr(context: context),
label: LocaleKeys.notice.tr(),
onOkPressed: () {
Navigator.pop(context);
},
okLabel: "confirm",
cancelLabel: LocaleKeys.acknowledged.tr(context: context),
isConfirmButton: true,
);
// showCommonBottomSheetWithoutHeight(
// title: LocaleKeys.success.tr(context: context),
// context,
// child: Utils.getSuccessWidget(loadingText: LocaleKeys.insuranceRequestSubmittedSuccessfully.tr(context: context)),
// callBackFunc: () {
// Navigator.pop(context);
// },
// isFullScreen: false,
// isCloseButtonVisible: false,
// isAutoDismiss: true
// );
// Future.delayed(Duration(milliseconds: 2000)).then((value) async {
// Navigator.pop(context);
// });

@ -43,6 +43,7 @@ class _FamilyMedicalScreenState extends State<FamilyMedicalScreen> {
AppState appState = getIt.get<AppState>();
return CollapsingListView(
isClose: true,
title: LocaleKeys.familyTitle.tr(context: context),
bottomChild: appState.getAuthenticatedUser()!.isParentUser!
? Container(

@ -216,18 +216,18 @@ class _NotificationsListPageState extends State<NotificationsListPage> {
}).paddingSymmetrical(16.w, 0.h),
).paddingSymmetrical(24.w, 0.h),
SizedBox(height: 16.h),
SizedBox(
key: _bottomKey,
child: "Show more notifications".toText16(
color: AppColors.primaryRedColor,
isBold: true,
isUnderLine: true
),
).onPress(() async {
await notificationsVM.loadMoreNotifications();
_scrollToBottom();
}),
SizedBox(height: 24.h),
// SizedBox(
// key: _bottomKey,
// child: "Show more notifications".toText16(
// color: AppColors.primaryRedColor,
// isBold: true,
// isUnderLine: true
// ),
// ).onPress(() async {
// await notificationsVM.loadMoreNotifications();
// _scrollToBottom();
// }),
SizedBox(height: 24.h),
],
);
}),

@ -11,7 +11,6 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/radiology/radiology_result_page.dart';

@ -158,28 +158,64 @@ class _RadiologyResultPageState extends State<RadiologyResultPage> {
borderRadius: 24.h,
hasShadow: true,
),
child: widget.patientRadiologyResponseModel.dIAPACSURL != "" ? CustomButton(
text: LocaleKeys.openRad.tr(context: context),
onPressed: () async {
if (radiologyViewModel.radiologyImageURL.isNotEmpty) {
Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL);
launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: "");
} else {
Utils.showToast("Radiology image not available");
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 45.h,
icon: AppAssets.imageIcon,
iconColor: Colors.white,
iconSize: 20.h,
).paddingSymmetrical(24.h, 24.h) : SizedBox.shrink(),
child: Column(
children: [
SizedBox(height: 24.h),
widget.patientRadiologyResponseModel.dIAPACSURL != ""
? CustomButton(
text: LocaleKeys.openRad.tr(context: context),
onPressed: () async {
if (radiologyViewModel.radiologyImageURL.isNotEmpty) {
Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL);
launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: "");
} else {
Utils.showToast("Radiology image not available");
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 56.h,
icon: AppAssets.imageIcon,
iconColor: Colors.white,
iconSize: 20.h,
).paddingSymmetrical(24.h, 0.h)
: SizedBox.shrink(),
Container(
height: 56.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.r),
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
stops: [0.236, 1.0], // 53.6% and 100%
colors: [
Color(0xFF8A38F5), // Transparent
Color(0xFFE20BBB), // Solid #F8F8F8
],
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(right: 4.w, left: 4.w),
child: Utils.buildSvgWithAssets(icon: AppAssets.aiOverView, width: 16.h, height: 16.h, iconColor: Colors.white),
),
LocaleKeys.generateAiAnalysisResult.tr(context: context).toText16(isBold: true, color: Colors.white)
],
),
).paddingSymmetrical(24.h, 12.h).onPress(() {
// Need to implement the Radiology AI analysis result generation functionality here
Utils.showToast("Radiology AI analysis result generation functionality is not implemented yet");
}),
],
),
),
],
),

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
@ -29,6 +30,7 @@ class LiveCarePermissionService {
Permission.camera,
Permission.microphone,
Permission.notification,
if (Platform.isAndroid) Permission.systemAlertWindow,
];
try {
@ -87,6 +89,7 @@ class LiveCarePermissionService {
if (permission == Permission.camera) return 'Camera';
if (permission == Permission.microphone) return 'Microphone';
if (permission == Permission.notification) return 'Notifications';
if (permission == Permission.systemAlertWindow) return 'Display over other apps';
return permission.toString();
}
}

Loading…
Cancel
Save