Accessibility & Image Widgets Update #328

Merged
Haroon6138 merged 1 commits from dev_aamir into master 6 days ago

@ -683,11 +683,20 @@
"emrgNo": "رقم جهة الاتصال في حالات الطوارئ",
"modes": "الأوضاع",
"vibration": "اهتزاز عند اللمس",
"blindModes": "أوضاع للمكفوفين جزئيًا",
"blindModes": "وضع للمكفوفين جزئياً",
"invertTheme": "عكس",
"offTheme": "إيقاف",
"dimTheme": "خافت",
"bwTheme": "أسود وأبيض",
"highContrastTheme": "تباين عالي",
"fontSize": "حجم الخط",
"fontSizeSmall": "صغير",
"fontSizeMedium": "متوسط",
"fontSizeLarge": "كبير",
"saveChanges": "حفظ التغييرات",
"settingsSavedSuccessfully": "تم حفظ الإعدادات بنجاح",
"cardHeading": "عنوان البطاقة",
"buttonText": "نص الزر",
"permissions": "إذن",
"cameraPermission": "الكاميرا",
"locationPermission": "الموقع",
@ -695,7 +704,7 @@
"outOfStockMsg": "لقد أضفت منتجًا غير متوفر حاليًا، يرجى إزالته!",
"noArabicLetters": "لا يُسمح باستخدام الحروف العربية",
"noOffersAvailable": "لا توجد عروض متاحة!",
"accessibility": "وضع الوصول",
"accessibility": "إمكانية الوصول",
"orderStatus": "حالة الطلب",
"findUs": "فروعنا",
"liveChat": "محادثة مباشرة",

@ -673,11 +673,20 @@
"emrgNo": "Emergency Contact Number",
"modes": "Modes",
"vibration": "Vibration Touch Feedback",
"blindModes": "Modes for Partially Blind",
"blindModes": "Mode for partially blind",
"invertTheme": "Invert",
"offTheme": "Off",
"dimTheme": "Dim",
"bwTheme": "Black and White",
"highContrastTheme": "High Contrast",
"fontSize": "Font Size",
"fontSizeSmall": "Small",
"fontSizeMedium": "Medium",
"fontSizeLarge": "Large",
"saveChanges": "Save Changes",
"settingsSavedSuccessfully": "Settings saved successfully",
"cardHeading": "Card Heading",
"buttonText": "Button Text",
"permissions": "Permission",
"cameraPermission": "Camera",
"locationPermission": "Location",
@ -685,7 +694,7 @@
"outOfStockMsg": "You have added product which is out of stock now, Please remove that!",
"noArabicLetters": "It Is Not Allow to Use Arabic Letters",
"noOffersAvailable": "No Offers Available!",
"accessibility": "Accessibility Mode",
"accessibility": "Accessibility",
"orderStatus": "Order Status",
"findUs": "Find Us",
"liveChat": "Live Chat",

@ -26,6 +26,8 @@ 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/dialogs/confirm_dialog.dart';
import 'package:hmg_patient_app_new/widgets/loading_dialog.dart';
import 'package:hmg_patient_app_new/widgets/accessibility/preserve_image_colors.dart';
import 'package:hmg_patient_app_new/widgets/accessibility/preserve_svg_colors.dart';
import 'package:lottie/lottie.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -120,10 +122,8 @@ class Utils {
// ),
// ));
return !isAddHours
? DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US")
.format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal())
: DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US")
.format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add(
? DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal())
: DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add(
Duration(
hours: isAddHours ? 3 : 0,
),
@ -356,12 +356,9 @@ class Utils {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: isSmallWidget ? 0.h : 48.h),
Lottie.asset(AppAnimations.noData,
repeat: false, reverse: false, frameRate: FrameRate(60), width: width.w, height: height.h, fit: BoxFit.fill),
Lottie.asset(AppAnimations.noData, repeat: false, reverse: false, frameRate: FrameRate(60), width: width.w, height: height.h, fit: BoxFit.fill),
SizedBox(height: 16.h),
(noDataText ?? LocaleKeys.noDataAvailable.tr())
.toText14(isBold: true, color: AppColors.greyTextColor, isCenter: true)
.paddingSymmetrical(64.w, 0.h),
(noDataText ?? LocaleKeys.noDataAvailable.tr()).toText14(isBold: true, color: AppColors.greyTextColor, isCenter: true).paddingSymmetrical(64.w, 0.h),
SizedBox(height: 16.h),
callToActionButton
],
@ -373,8 +370,7 @@ class Utils {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Lottie.asset(AppAnimations.loadingAnimation,
repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill),
Lottie.asset(AppAnimations.loadingAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill),
SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor, isCenter: true, isBold: true),
SizedBox(height: 8.h),
@ -400,8 +396,7 @@ class Utils {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Lottie.asset(AppAnimations.errorAnimation,
repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
Lottie.asset(AppAnimations.errorAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText16(color: AppColors.blackColor).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 8.h),
@ -502,8 +497,7 @@ class Utils {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Lottie.asset(AppAnimations.warningAnimation,
repeat: false, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
Lottie.asset(AppAnimations.warningAnimation, repeat: false, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
SizedBox(height: 8.h),
(loadingText ?? LocaleKeys.loadingText.tr()).toText15(color: AppColors.blackColor, letterSpacing: 0),
SizedBox(height: 16.h),
@ -623,10 +617,8 @@ class Utils {
}
// Replace HTML line breaks with newlines
var withLineBreaks = htmlString
.replaceAll(RegExp(r'<br\s*\/?>', multiLine: true), '\n')
.replaceAll(RegExp(r'<\/p>', multiLine: true), '\n')
.replaceAll(RegExp(r'<divider>', multiLine: true), '\n');
var withLineBreaks =
htmlString.replaceAll(RegExp(r'<br\s*\/?>', multiLine: true), '\n').replaceAll(RegExp(r'<\/p>', multiLine: true), '\n').replaceAll(RegExp(r'<divider>', multiLine: true), '\n');
// Remove all other HTML tags
var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), '');
@ -704,20 +696,7 @@ class Utils {
final year = parts[0];
// Map month number to short month name (Hijri months)
const hijriMonthNames = [
'Muharram',
'Safar',
'Rabi I',
'Rabi II',
'Jumada I',
'Jumada II',
'Rajab',
'Sha\'ban',
'Ramadan',
'Shawwal',
'Dhu al-Qi\'dah',
'Dhu al-Hijjah'
];
const hijriMonthNames = ['Muharram', 'Safar', 'Rabi I', 'Rabi II', 'Jumada I', 'Jumada II', 'Rajab', 'Sha\'ban', 'Ramadan', 'Shawwal', 'Dhu al-Qi\'dah', 'Dhu al-Hijjah'];
final monthIndex = int.tryParse(parts[1]) ?? 1;
final month = hijriMonthNames[monthIndex - 1];
@ -774,21 +753,23 @@ class Utils {
String? errorAsset,
}) {
final Color? resolvedColor = iconColor ?? (applyThemeColor && AppColors.isDarkMode ? AppColors.textColor : null);
return SvgPicture.asset(
icon,
colorFilter: resolvedColor != null ? ColorFilter.mode(isDisabled ? resolvedColor.withOpacity(0.5) : resolvedColor, BlendMode.srcIn) : null,
width: width,
height: height,
fit: fit,
errorBuilder: errorAsset != null
? (context, error, stackTrace) => SvgPicture.asset(
errorAsset,
colorFilter: resolvedColor != null ? ColorFilter.mode(isDisabled ? resolvedColor.withOpacity(0.5) : resolvedColor, BlendMode.srcIn) : null,
width: width,
height: height,
fit: fit,
)
: null,
return PreserveSvgColors(
child: SvgPicture.asset(
icon,
colorFilter: resolvedColor != null ? ColorFilter.mode(isDisabled ? resolvedColor.withValues(alpha: 0.5) : resolvedColor, BlendMode.srcIn) : null,
width: width,
height: height,
fit: fit,
errorBuilder: errorAsset != null
? (context, error, stackTrace) => SvgPicture.asset(
errorAsset,
colorFilter: resolvedColor != null ? ColorFilter.mode(isDisabled ? resolvedColor.withValues(alpha: 0.5) : resolvedColor, BlendMode.srcIn) : null,
width: width,
height: height,
fit: fit,
)
: null,
),
);
}
@ -802,14 +783,16 @@ class Utils {
}) {
final iconH = height ?? 24.h;
final iconW = width ?? 24.w;
return SvgPicture.network(
url,
colorFilter: ColorFilter.mode(
isDisabled ? iconColor.withOpacity(0.5) : iconColor,
BlendMode.srcIn,
return PreserveSvgColors(
child: SvgPicture.network(
url,
colorFilter: ColorFilter.mode(
isDisabled ? iconColor.withValues(alpha: 0.5) : iconColor,
BlendMode.srcIn,
),
width: iconW,
height: iconH,
),
width: iconW,
height: iconH,
);
}
@ -825,14 +808,15 @@ class Utils {
}) {
final iconH = height ?? 24.h;
final iconW = width ?? 24.w;
return Container(
decoration: BoxDecoration(
border: border != null ? Border.all(color: AppColors.whiteColor, width: border) : null,
borderRadius: border != null ? BorderRadius.circular(borderRadius ?? 12.r) : null,
return PreserveImageColors(
child: Container(
decoration: BoxDecoration(
border: border != null ? Border.all(color: AppColors.whiteColor, width: border) : null,
borderRadius: border != null ? BorderRadius.circular(borderRadius ?? 12.r) : null,
),
child: Image.asset(icon, width: iconW, height: iconH, fit: fit),
),
child: Image.asset(icon, width: iconW, height: iconH, fit: fit),
);
// return Image.asset(icon, width: width, height: height, fit: fit, );
}
static Widget buildImgWithAssetsWithBorderRadius({
@ -847,21 +831,23 @@ class Utils {
}) {
final iconH = height ?? 24.h;
final iconW = width ?? 24.w;
return Container(
width: iconW,
height: iconH,
decoration: BoxDecoration(
border: border != null ? Border.all(color: AppColors.whiteColor, width: border) : null,
borderRadius: borderRadius != null ? BorderRadius.circular(borderRadius ?? 12.r) : null,
image: DecorationImage(
image: AssetImage(
icon,
),
fit: fit)),
return PreserveImageColors(
child: Container(
width: iconW,
height: iconH,
decoration: BoxDecoration(
border: border != null ? Border.all(color: AppColors.whiteColor, width: border) : null,
borderRadius: BorderRadius.circular(borderRadius ?? 12.r),
image: DecorationImage(
image: AssetImage(
icon,
),
fit: fit)),
),
);
}
/// Widget to build an SVG from network
/// Widget to build an image from network - automatically preserves colors in visual modes
static Widget buildImgWithNetwork({
required String url,
required Color iconColor,
@ -873,16 +859,18 @@ class Utils {
}) {
final iconH = height ?? 24.h;
final iconW = width ?? 24.w;
return Image.network(
url,
width: iconW,
height: iconH,
fit: fit,
errorBuilder: errorBuilder ??
(_, __, ___) {
//todo_section change the error builder icon that it is returning
return Utils.buildSvgWithAssets(width: iconW, height: iconH, icon: AppAssets.no_visit_icon);
},
return PreserveImageColors(
child: Image.network(
url,
width: iconW,
height: iconH,
fit: fit,
errorBuilder: errorBuilder ??
(_, __, ___) {
//todo_section change the error builder icon that it is returning
return Utils.buildSvgWithAssets(width: iconW, height: iconH, icon: AppAssets.no_visit_icon);
},
),
);
}
@ -891,26 +879,37 @@ class Utils {
spacing: spacing.w,
mainAxisSize: MainAxisSize.max,
children: [
Image.asset(AppAssets.mada, width: width.h, height: height.h),
Image.asset(
AppAssets.tamaraEng,
width: width.h,
height: height.h,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
debugPrint('Failed to load Tamara PNG in payment methods: $error');
return Utils.buildSvgWithAssets(icon: AppAssets.tamara, width: 35.h, height: 35.h, fit: BoxFit.contain);
},
PreserveImageColors(
child: Image.asset(AppAssets.mada, width: width.h, height: height.h),
),
PreserveImageColors(
child: Image.asset(
AppAssets.tamaraEng,
width: width.h,
height: height.h,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
debugPrint('Failed to load Tamara PNG in payment methods: $error');
return Utils.buildSvgWithAssets(icon: AppAssets.tamara, width: 35.h, height: 35.h, fit: BoxFit.contain);
},
),
),
PreserveImageColors(
child: Image.asset(AppAssets.visa, width: width.h, height: height.h),
),
Image.asset(AppAssets.visa, width: width.h, height: height.h),
Image.asset(AppAssets.mastercard, width: width.h, height: height.h),
Platform.isIOS ? Image.asset(AppAssets.applePay, width: width.h, height: height.h) : SizedBox.shrink(),
PreserveImageColors(
child: Image.asset(AppAssets.mastercard, width: width.h, height: height.h),
),
Platform.isIOS
? PreserveImageColors(
child: Image.asset(AppAssets.applePay, width: width.h, height: height.h),
)
: SizedBox.shrink(),
],
);
}
static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize,
{bool isSaudiCurrency = true, bool isExpanded = true}) {
static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize, {bool isSaudiCurrency = true, bool isExpanded = true}) {
return Row(
mainAxisAlignment: isExpanded ? MainAxisAlignment.spaceBetween : MainAxisAlignment.start,
children: [
@ -965,13 +964,7 @@ class Utils {
// text: NumberFormat.currency(locale: 'en_US', symbol: " ", decimalDigits: 0).format(habibWalletAmount),
// text: " ${(NumberFormat.decimalPattern().format(habibWalletAmount)).toStringAsFixed(2)}",
text: " ${(NumberFormat.decimalPattern().format(habibWalletAmount))}",
style: TextStyle(
color: resolvedTextColor,
fontSize: fontSize ?? 32.f,
letterSpacing: letterSpacing ?? -4,
fontFamily: "Poppins",
fontWeight: fontWeight ?? FontWeight.w600,
height: 1),
style: TextStyle(color: resolvedTextColor, fontSize: fontSize ?? 32.f, letterSpacing: letterSpacing ?? -4, fontFamily: "Poppins", fontWeight: fontWeight ?? FontWeight.w600, height: 1),
),
],
),
@ -1035,12 +1028,7 @@ class Utils {
static PatientDoctorAppointmentList? convertToPatientDoctorAppointmentList(HospitalsModel? hospital) {
if (hospital == null) return null;
return PatientDoctorAppointmentList(
filterName: hospital.name,
distanceInKMs: hospital.distanceInKilometers?.toString(),
projectTopName: hospital.name,
projectBottomName: hospital.name,
model: hospital,
isHMC: hospital.isHMC);
filterName: hospital.name, distanceInKMs: hospital.distanceInKilometers?.toString(), projectTopName: hospital.name, projectBottomName: hospital.name, model: hospital, isHMC: hospital.isHMC);
}
static HospitalsModel? convertToHospitalsModel(PatientDoctorAppointmentList? item) {

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
class LaserBodyParts {
static final LaserBodyParts _instance = LaserBodyParts._internal();
@ -9,11 +9,11 @@ class LaserBodyParts {
factory LaserBodyParts() => _instance;
static Widget image(String assetUri) {
return new SvgPicture.asset(assetUri, fit: BoxFit.cover, width: 88, height: 88);
return Utils.buildSvgWithAssets(icon: assetUri, fit: BoxFit.cover, width: 88, height: 88, applyThemeColor: false);
}
static Widget imagePng(String assetUri) {
return Image.asset(assetUri, fit: BoxFit.cover, width: 88, height: 88);
return Utils.buildImgWithAssets(icon: assetUri, fit: BoxFit.cover, width: 88, height: 88);
}
Map<String, Widget> maleBodyMap = {

@ -16,6 +16,8 @@ import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
class ProfileSettingsViewModel extends ChangeNotifier {
static const String _darkModeKey = 'is_dark_mode';
static const String _fontSizeStepKey = 'accessibility_font_size_step';
static const String _visualModeKey = 'accessibility_visual_mode';
final CacheService _cacheService;
final ProfileSettingsRepo profileSettingsRepo;
@ -25,6 +27,13 @@ class ProfileSettingsViewModel extends ChangeNotifier {
bool _isDarkMode = false;
bool get isDarkMode => _isDarkMode;
// Accessibility settings
int _fontSizeStep = 2; // 0: Small, 1: Small-Medium, 2: Medium (default), 3: Medium-Large, 4: Large
int get fontSizeStep => _fontSizeStep;
String _visualMode = 'off'; // off, invert, dim, highContrast
String get visualMode => _visualMode;
// Update email state
bool isUpdateEmailLoading = false;
bool isUpdateEmailSuccess = false;
@ -163,6 +172,47 @@ class ProfileSettingsViewModel extends ChangeNotifier {
notifyListeners();
}
// Accessibility settings
/// Load accessibility settings at app startup
void loadAccessibilitySettings() {
_fontSizeStep = _cacheService.getInt(key: _fontSizeStepKey) ?? 2;
_visualMode = _cacheService.getString(key: _visualModeKey) ?? 'off';
// No notifyListeners() here we are called before build.
}
/// Update font size step and save to cache
void setFontSizeStep(int step) {
_fontSizeStep = step;
_cacheService.saveInt(key: _fontSizeStepKey, value: step);
notifyListeners();
}
/// Update visual mode and save to cache
void setVisualMode(String mode) {
_visualMode = mode;
_cacheService.saveString(key: _visualModeKey, value: mode);
notifyListeners();
}
/// Get font scale multiplier based on current font size step
double getFontScaleMultiplier() {
switch (_fontSizeStep) {
case 0:
return 0.85; // Small
case 1:
return 0.95; // Small-Medium
case 2:
return 1.0; // Medium (default)
case 3:
return 1.15; // Medium-Large
case 4:
return 1.3; // Large
default:
return 1.0;
}
}
// Update patient info
Future<void> updatePatientInfo({

@ -687,6 +687,15 @@ abstract class LocaleKeys {
static const offTheme = 'offTheme';
static const dimTheme = 'dimTheme';
static const bwTheme = 'bwTheme';
static const highContrastTheme = 'highContrastTheme';
static const fontSize = 'fontSize';
static const fontSizeSmall = 'fontSizeSmall';
static const fontSizeMedium = 'fontSizeMedium';
static const fontSizeLarge = 'fontSizeLarge';
static const saveChanges = 'saveChanges';
static const settingsSavedSuccessfully = 'settingsSavedSuccessfully';
static const cardHeading = 'cardHeading';
static const buttonText = 'buttonText';
static const permissions = 'permissions';
static const cameraPermission = 'cameraPermission';
static const locationPermission = 'locationPermission';
@ -1578,7 +1587,6 @@ abstract class LocaleKeys {
static const waterConsumption = 'waterConsumption';
static const selectNumberOfReminders = 'selectNumberOfReminders';
static const h2oSettings = 'h2oSettings';
static const settingsSavedSuccessfully = 'settingsSavedSuccessfully';
static const yourName = 'yourName';
static const ageYears = 'ageYears';
static const numberOfRemindersInADay = 'numberOfRemindersInADay';

@ -134,6 +134,9 @@ Future<void> callInitializations() async {
// Restore persisted dark-mode preference before the first frame.
getIt.get<ProfileSettingsViewModel>().loadDarkMode();
// Restore persisted accessibility settings before the first frame.
getIt.get<ProfileSettingsViewModel>().loadAccessibilitySettings();
}
void main() async {
@ -282,6 +285,55 @@ void main() async {
class MyApp extends StatelessWidget {
const MyApp({super.key});
/// Apply visual mode filter to the entire app
Widget _applyVisualMode(String visualMode, Widget child) {
switch (visualMode) {
case 'invert':
// Invert colors app-wide (red becomes cyan for colorblind users)
return ColorFiltered(
colorFilter: const ColorFilter.matrix(<double>[
-1, 0, 0, 0, 255, // Red channel inverted
0, -1, 0, 0, 255, // Green channel inverted
0, 0, -1, 0, 255, // Blue channel inverted
0, 0, 0, 1, 0, // Alpha channel unchanged
]),
child: child,
);
case 'dim':
// Apply dim effect with opacity overlay
return Stack(
children: [
child,
Positioned.fill(
child: IgnorePointer(
child: Container(
color: Colors.black.withValues(alpha: 0.3), // 30% black overlay for dimming
),
),
),
],
);
case 'highContrast':
// Apply desaturation for high contrast (removes colors, leaves black and white)
return ColorFiltered(
colorFilter: const ColorFilter.matrix(<double>[
0.2126, 0.7152, 0.0722, 0, 0, // Red channel (grayscale)
0.2126, 0.7152, 0.0722, 0, 0, // Green channel (grayscale)
0.2126, 0.7152, 0.0722, 0, 0, // Blue channel (grayscale)
0, 0, 0, 1, 0, // Alpha channel unchanged
]),
child: child,
);
case 'off':
default:
// No filter applied
return child;
}
}
@override
Widget build(BuildContext context) {
return SafeArea(
@ -300,13 +352,16 @@ class MyApp extends StatelessWidget {
// title: 'Dr. AlHabib',
title: 'Dr. AlHabib Beta',
builder: (context, mchild) {
return MediaQuery(
Widget child = MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: TextScaler.noScaling,
textScaler: TextScaler.linear(profileVm.getFontScaleMultiplier()),
alwaysUse24HourFormat: true,
),
child: mchild!,
);
// Apply visual mode filters app-wide
return _applyVisualMode(profileVm.visualMode, child);
},
showSemanticsDebugger: false,
debugShowCheckedModeBanner: false,

@ -570,8 +570,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(24.r),
// Todo: what is this???? Api Key??? 😲
child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=${(MediaQuery.of(context).size.width * 1.5).toInt()}x${(MediaQuery.of(context).size.height * 0.35).toInt()}&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}",
child: Utils.buildImgWithNetwork(
url: "https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=${(MediaQuery.of(context).size.width * 1.5).toInt()}x${(MediaQuery.of(context).size.height * 0.35).toInt()}&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}",
iconColor: AppColors.transparent,
fit: BoxFit.cover,
width: double.infinity,
),

@ -112,7 +112,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h)
Utils.buildImgWithAssets(icon: AppAssets.mada, width: 72.h, height: 25.h)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h),
LocaleKeys.mada.tr(context: context).toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
@ -230,9 +230,9 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
Utils.buildImgWithAssets(icon: AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.mastercard, width: 40.h, height: 40.h),
],
).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h),
@ -352,7 +352,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h)
Utils.buildImgWithAssets(icon: AppAssets.tamaraEng, width: 72.h, height: 25.h)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading),
SizedBox(height: 16.h),
LocaleKeys.tamara.tr(context: context)

@ -139,8 +139,9 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
@ -261,8 +262,9 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
(doctor?.doctorImageURL ?? doctor?.doctorImage ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png"),
Utils.buildImgWithNetwork(
url: (doctor?.doctorImageURL ?? doctor?.doctorImage ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png"),
iconColor: AppColors.transparent,
width: 24.w,
height: 24.h,
fit: BoxFit.cover,

@ -227,10 +227,11 @@ class _AppointmentCardState extends State<AppointmentCard> {
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
widget.isLoading
Utils.buildImgWithNetwork(
url: widget.isLoading
? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png'
: widget.patientAppointmentHistoryResponseModel.doctorImageURL!,
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
@ -280,8 +281,9 @@ class _AppointmentCardState extends State<AppointmentCard> {
SizedBox(width: 12.w),
(widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL != null &&
widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL!.isNotEmpty)
? Image.network(
widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png",
? Utils.buildImgWithNetwork(
url: widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png",
iconColor: AppColors.transparent,
width: 20.h,
height: 15.h,
fit: BoxFit.cover,

@ -58,8 +58,9 @@ class AppointmentDoctorCard extends StatelessWidget {
children: [
Column(
children: [
Image.network(
patientAppointmentHistoryResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: patientAppointmentHistoryResponseModel.doctorImageURL!,
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -10,6 +10,9 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
import '../../../core/utils/utils.dart';
import '../../../theme/colors.dart';
class BuildDoctorRowAppointmentRating extends StatelessWidget {
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@ -22,8 +25,9 @@ class BuildDoctorRowAppointmentRating extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
patientAppointmentHistoryResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: patientAppointmentHistoryResponseModel.doctorImageURL!,
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -86,8 +86,9 @@ class _DoctorResponsePageState extends State<DoctorResponsePage> {
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
iconColor: AppColors.blackBgColor,
width: 50.w,
height: 50.h,
fit: BoxFit.cover,

@ -87,8 +87,9 @@ class AskDoctorAppointmentCard extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
askDoctorAppointmentHistoryList.doctorImageURL!,
Utils.buildImgWithNetwork(
url: askDoctorAppointmentHistoryList.doctorImageURL!,
iconColor: AppColors.blackBgColor,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -28,8 +28,9 @@ class DoctorResponseTransactions extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
iconColor: AppColors.blackBgColor,
width: 50.w,
height: 50.h,
fit: BoxFit.cover,
@ -85,7 +86,11 @@ class DoctorResponseTransactions extends StatelessWidget {
SizedBox(height: 16.h),
Row(
children: [
Image.asset(getIt.get<AppState>().getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, width: 42.w, height: 42.h),
Utils.buildImgWithAssets(
icon: getIt.get<AppState>().getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
width: 42.w,
height: 42.h,
),
SizedBox(width: 8.w),
Container(
padding: EdgeInsets.all(8.w),
@ -116,10 +121,16 @@ class DoctorResponseTransactions extends StatelessWidget {
borderRadius: BorderRadius.circular(8.r),
),
child: doctorResponseModel.transactions![index].doctorResponse!.toText12(color: AppColors.textColor, isBold: true),
),
SizedBox(width: 8.w),
Image.network("https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png", fit: BoxFit.cover, width: 42.w, height: 42.h).circle(100.r),
],
),
SizedBox(width: 8.w),
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
iconColor: AppColors.blackBgColor,
fit: BoxFit.cover,
width: 42.w,
height: 42.h,
).circle(100.r),
],
),
],
);

@ -132,8 +132,9 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 64.h,
height: 64.h,
fit: BoxFit.cover,
@ -191,8 +192,9 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
myAppointmentsVM.patientMyDoctorsList[index].doctorImageURL!,
Utils.buildImgWithNetwork(
url: myAppointmentsVM.patientMyDoctorsList[index].doctorImageURL!,
iconColor: AppColors.transparent,
width: 64.h,
height: 64.h,
fit: BoxFit.cover,
@ -383,8 +385,9 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
myAppointmentsVM.patientFavouriteDoctorsList[index].doctorImageUrl!,
Utils.buildImgWithNetwork(
url: myAppointmentsVM.patientFavouriteDoctorsList[index].doctorImageUrl!,
iconColor: AppColors.transparent,
width: 64.h,
height: 64.h,
fit: BoxFit.cover,

@ -83,8 +83,9 @@ class DoctorProfilePage extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL!,
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
@ -109,8 +110,9 @@ class DoctorProfilePage extends StatelessWidget {
),
],
),
Image.network(
bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL!,
Utils.buildImgWithNetwork(
url: bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL!,
iconColor: AppColors.transparent,
width: 32.h,
height: 32.h,
fit: BoxFit.cover,

@ -66,8 +66,8 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
padding: EdgeInsets.all(16.h),
child: Row(
children: [
Image.asset(
appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
Utils.buildImgWithAssets(
icon: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
width: 52.h,
height: 52.h,
),

@ -106,7 +106,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
Utils.buildImgWithAssets(icon: AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
LocaleKeys.mada.tr(context: context).toText16(isBold: true),
],
@ -187,9 +187,9 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
Utils.buildImgWithAssets(icon: AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.mastercard, width: 40.h, height: 40.h),
],
),
SizedBox(height: 16.h),
@ -271,7 +271,7 @@ class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentP
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h),
Utils.buildImgWithAssets(icon: AppAssets.tamaraEng, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
LocaleKeys.tamara.tr(context: context).toText16(isBold: true),
],

@ -84,9 +84,10 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
children: [
Row(
children: [
Image.network(
bookAppointmentsViewModel.selectedDoctor.doctorImageURL ??
Utils.buildImgWithNetwork(
url: bookAppointmentsViewModel.selectedDoctor.doctorImageURL ??
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
iconColor: AppColors.transparent,
width: 50.h,
height: 50.h,
fit: BoxFit.cover,
@ -104,9 +105,10 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
SizedBox(width: 12.w),
(bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL != null &&
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL!.isNotEmpty)
? Image.network(
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL ??
? Utils.buildImgWithNetwork(
url: bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL ??
"https://hmgwebservices.com/Images/flag/SAU.png",
iconColor: AppColors.transparent,
width: 20.h,
height: 15.h,
fit: BoxFit.cover,
@ -334,12 +336,10 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
// Show default image (no image data or user has no uploaded image)
print('📷 Showing default avatar for user $currentPatientId');
return Image.asset(
defaultImage,
key: ValueKey('default_$currentPatientId'),
return Utils.buildImgWithAssets(
icon: defaultImage,
width: 52.w,
height: 52.h,
gaplessPlayback: true,
);
}

@ -116,7 +116,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
Utils.buildImgWithAssets(icon: AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
LocaleKeys.mada.tr(context: context).toText16(isBold: true),
],
@ -197,9 +197,9 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
Utils.buildImgWithAssets(icon: AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.mastercard, width: 40.h, height: 40.h),
],
),
SizedBox(height: 16.h),
@ -281,7 +281,7 @@ class _WaitingAppointmentPaymentPageState extends State<WaitingAppointmentPaymen
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h),
Utils.buildImgWithAssets(icon: AppAssets.tamaraEng, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
LocaleKeys.tamara.tr(context: context).toText16(isBold: true),
],

@ -52,10 +52,11 @@ class DoctorCard extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
isLoading
Utils.buildImgWithNetwork(
url: isLoading
? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png"
: doctorsListResponseModel.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png",
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
@ -120,15 +121,16 @@ class DoctorCard extends StatelessWidget {
.toString()
.toText12(isBold: true, color: AppColors.textColor, maxLine: 2, isEnglishOnly: true)
.toShimmer2(isShow: isLoading),
),
SizedBox(width: 6.w),
Image.network(
isLoading ? "https://hmgwebservices.com/Images/flag/SYR.png" : doctorsListResponseModel.nationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SYR.png",
width: 20.h,
height: 15.h,
fit: BoxFit.fill,
).toShimmer2(isShow: isLoading),
],
),
SizedBox(width: 6.w),
Utils.buildImgWithNetwork(
url: isLoading ? "https://hmgwebservices.com/Images/flag/SYR.png" : doctorsListResponseModel.nationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SYR.png",
iconColor: AppColors.transparent,
width: 20.h,
height: 15.h,
fit: BoxFit.fill,
).toShimmer2(isShow: isLoading),
],
),
SizedBox(height: 6.h),
Wrap(

@ -301,7 +301,7 @@ class _MyChildVaccinePageState extends State<MyChildVaccinePage> {
),
child: Row(
children: [
Image.asset(children[index]['image'], width: 24.h, height: 24.h),
Utils.buildImgWithAssets(icon: children[index]['image'], width: 24.h, height: 24.h),
SizedBox(width: 8.w),
Text(
"${children[index]['name']} (${children[index]['gender']})",

@ -282,8 +282,8 @@ class _ComprehensiveCheckupPageState extends State<ComprehensiveCheckupPage> {
final String imagePath = appStateLocal.isArabic() ? AppAssets.comprehensiveCheckupAr : AppAssets.comprehensiveCheckupEn;
return Stack(
children: [
Image.asset(
imagePath,
Utils.buildImgWithAssets(
icon: imagePath,
width: double.infinity,
fit: BoxFit.cover,
).paddingAll(16.w),

@ -259,8 +259,9 @@ class FeedbackPage extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
contactUsViewModel.patientFeedbackSelectedAppointment!.doctorImageURL!,
Utils.buildImgWithNetwork(
url: contactUsViewModel.patientFeedbackSelectedAppointment!.doctorImageURL!,
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -16,6 +16,8 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:provider/provider.dart';
import '../../core/utils/utils.dart';
class FindUsPage extends StatelessWidget {
FindUsPage({super.key});
@ -120,8 +122,9 @@ class FindUsPage extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -70,8 +70,9 @@ class LiveChatPage extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -78,8 +78,9 @@ class FindUsItemCard extends StatelessWidget {
: SizedBox.shrink(),
Row(
children: [
Image.network(
getHMGLocationsModel.projectImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: getHMGLocationsModel.projectImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 40.h,
height: 40.h,
fit: BoxFit.cover,

@ -211,7 +211,7 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
Utils.buildImgWithAssets(icon: AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
LocaleKeys.mada.tr(context: context).toText16(isBold: true),
],
@ -252,9 +252,9 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
Utils.buildImgWithAssets(icon: AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.mastercard, width: 40.h, height: 40.h),
],
),
SizedBox(height: 16.h),
@ -296,21 +296,11 @@ class _CovidPaymentScreenState extends State<CovidPaymentScreen> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
AppAssets.tamaraEng,
Utils.buildImgWithAssets(
icon: AppAssets.tamaraEng,
width: 72.h,
height: 25.h,
fit: BoxFit.contain,
// If PNG fails to load for any reason, log and fallback to SVG asset
errorBuilder: (context, error, stackTrace) {
debugPrint('Failed to load Tamara PNG asset: $error');
return Utils.buildSvgWithAssets(
icon: AppAssets.tamara,
width: 72.h,
height: 25.h,
fit: BoxFit.contain,
);
},
),
SizedBox(height: 16.h),
LocaleKeys.tamara.tr(context: context).toText16(isBold: true),

@ -102,7 +102,7 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
Utils.buildImgWithAssets(icon: AppAssets.mada, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
LocaleKeys.mada.tr(context: context).toText16(isBold: true),
],
@ -188,9 +188,9 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
Utils.buildImgWithAssets(icon: AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.mastercard, width: 40.h, height: 40.h),
],
),
SizedBox(height: 16.h),
@ -277,7 +277,7 @@ class _ErOnlineCheckinPaymentPageState extends State<ErOnlineCheckinPaymentPage>
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.tamaraEng, width: 72.h, height: 25.h),
Utils.buildImgWithAssets(icon: AppAssets.tamaraEng, width: 72.h, height: 25.h),
SizedBox(height: 16.h),
LocaleKeys.tamara.tr(context: context).toText16(isBold: true),
],

@ -85,7 +85,7 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 72.h, height: 25.h).toShimmer2(isShow: false),
Utils.buildImgWithAssets(icon: AppAssets.mada, width: 72.h, height: 25.h).toShimmer2(isShow: false),
SizedBox(height: 16.h),
LocaleKeys.mada.tr(context: context).toText16(isBold: true).toShimmer2(isShow: false),
],
@ -183,9 +183,9 @@ class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> {
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.visa, width: 40.h, height: 40.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.mastercard, width: 40.h, height: 40.h),
],
).toShimmer2(isShow: false),
SizedBox(height: 16.h),

@ -13,6 +13,8 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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';
import '../../core/utils/utils.dart';
class ServiceInfoPage extends StatelessWidget {
final String serviceName;
final String serviceHeader;
@ -37,8 +39,8 @@ class ServiceInfoPage extends StatelessWidget {
borderRadius: BorderRadius.circular(24.r),
child: Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Image.asset(
serviceImage,
child: Utils.buildImgWithAssets(
icon: serviceImage,
fit: BoxFit.fitHeight,
// height: 480.h,
// width: 520.w,

@ -56,8 +56,8 @@ class LargeServiceCard extends StatelessWidget {
topLeft: Radius.circular(24.r),
topRight: Radius.circular(24.r),
),
child: Image.asset(
serviceCardData.largeCardIcon,
child: Utils.buildImgWithAssets(
icon: serviceCardData.largeCardIcon,
fit: BoxFit.cover,
width: double.infinity,
height: isFoldable ? 190.h : (isTablet ? 200.h : 180.h),
@ -72,7 +72,7 @@ class LargeServiceCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
isPNG
? Image.asset(serviceCardData.icon, width: 35.h, height: 35.h)
? Utils.buildImgWithAssets(icon: serviceCardData.icon, width: 35.h, height: 35.h)
: Container(
height: 48.h,
width: 48.h,
@ -204,7 +204,7 @@ class FadedLargeServiceCard extends StatelessWidget {
borderRadius: BorderRadius.circular(24.r),
child: Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Image.asset(serviceCardData.largeCardIcon, fit: BoxFit.cover, width: 520.w, height: 250.h)),
child: Utils.buildImgWithAssets(icon: serviceCardData.largeCardIcon, fit: BoxFit.cover, width: 520.w, height: 250.h)),
),
Positioned(
top: 0,
@ -234,7 +234,7 @@ class FadedLargeServiceCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
isPNG
? Image.asset(serviceCardData.icon, width: 32.h, height: 32.h).circle(100.h)
? Utils.buildImgWithAssets(icon: serviceCardData.icon, width: 32.h, height: 32.h).circle(100.h)
: Container(
height: 32.h,
width: 32.h,

@ -63,7 +63,7 @@ class WelcomeWidget extends StatelessWidget {
),
imageWidget ??
(imageUrl != null
? Image.asset(imageUrl!, width: 40, height: 40)
? Utils.buildImgWithAssets(icon: imageUrl!, width: 40, height: 40)
: SizedBox(width: 40, height: 40)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -6,6 +6,7 @@ import 'package:hmg_patient_app_new/core/app_export.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/date_util.dart';
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/insurance/insurance_view_model.dart';
@ -82,8 +83,9 @@ class InsuranceApprovalDetailsPage extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
insuranceApprovalResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: insuranceApprovalResponseModel.doctorImageURL!,
iconColor: AppColors.blackBgColor,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -106,8 +106,9 @@ class InsuranceApprovalCard extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
isLoading ? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png" : insuranceApprovalResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: isLoading ? "https://hmgwebservices.com/Images/MobileImages/OALAY/1439.png" : insuranceApprovalResponseModel.doctorImageURL!,
iconColor: AppColors.blackBgColor,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -55,8 +55,9 @@ class LabResultItemView extends StatelessWidget {
SizedBox(height: 8.h),
Row(
children: [
Image.network(
isLoading ? "" : labOrder!.doctorImageURL!,
Utils.buildImgWithNetwork(
url: isLoading ? "" : labOrder!.doctorImageURL!,
iconColor: AppColors.transparent,
width: 24.h,
height: 24.h,
fit: BoxFit.cover,

@ -1,9 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
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/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_order_response_by_ai_model.dart';
@ -37,7 +37,13 @@ class AiAnalysisWidget extends StatelessWidget {
Container(
padding: EdgeInsets.all(8.r),
decoration: BoxDecoration(gradient: AppColors.aiLinearGradient, borderRadius: BorderRadius.circular(8.r)),
child: SvgPicture.asset(AppAssets.aiOverView, colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), height: 18.r, width: 18.r),
child: Utils.buildSvgWithAssets(
icon: AppAssets.aiOverView,
iconColor: Colors.white,
height: 18.r,
width: 18.r,
applyThemeColor: false,
),
),
],
),

@ -908,8 +908,9 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: FadeInAnimation(
child: Row(
children: [
Image.network(
prescriptionVM.patientPrescriptionOrders[index].doctorImageURL!,
Utils.buildImgWithNetwork(
url: prescriptionVM.patientPrescriptionOrders[index].doctorImageURL!,
iconColor: AppColors.transparent,
width: 40.h,
height: 40.h,
fit: BoxFit.cover,
@ -1059,8 +1060,9 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
? Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 64.h,
height: 64.h,
fit: BoxFit.cover,
@ -1106,8 +1108,9 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
myAppointmentsVM.patientMyDoctorsList[index].doctorImageURL!,
Utils.buildImgWithNetwork(
url: myAppointmentsVM.patientMyDoctorsList[index].doctorImageURL!,
iconColor: AppColors.transparent,
width: 64.h,
height: 64.h,
fit: BoxFit.cover,

@ -139,8 +139,9 @@ class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
model.patientSickLeaveList[index].doctorImageURL!,
Utils.buildImgWithNetwork(
url: model.patientSickLeaveList[index].doctorImageURL!,
iconColor: AppColors.transparent,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,

@ -83,8 +83,9 @@ class _VaccineListPageState extends State<VaccineListPage> {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -163,9 +163,10 @@ class _MedicalFileAppointmentCardState extends State<MedicalFileAppointmentCard>
children: [
Row(
children: [
Image.network(
widget.patientAppointmentHistoryResponseModel.doctorImageURL ??
Utils.buildImgWithNetwork(
url: widget.patientAppointmentHistoryResponseModel.doctorImageURL ??
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 30.h,
height: 30.h,
fit: BoxFit.fill,

@ -56,8 +56,9 @@ class PatientSickLeaveCard extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : patientSickLeavesResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : patientSickLeavesResponseModel.doctorImageURL!,
iconColor: AppColors.transparent,
width: 30.h,
height: 30.h,
fit: BoxFit.cover,

@ -241,8 +241,9 @@ class _MedicalReportsPageState extends State<MedicalReportsPage> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
report.doctorImageURL!,
Utils.buildImgWithNetwork(
url: report.doctorImageURL!,
iconColor: AppColors.transparent,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,

@ -42,8 +42,9 @@ class PatientMedicalReportCard extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : patientMedicalReportResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : patientMedicalReportResponseModel.doctorImageURL!,
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.fill,

@ -149,8 +149,9 @@ class _MyInvoicesDetailsPageState extends State<MyInvoicesDetailsPage> {
children: [
Column(
children: [
Image.network(
widget.getInvoiceDetailsResponseModel.doctorImageURL ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
Utils.buildImgWithNetwork(
url: widget.getInvoiceDetailsResponseModel.doctorImageURL ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -102,8 +102,9 @@ class InvoiceListCard extends StatelessWidget {
children: [
Column(
children: [
Image.network(
getInvoicesListResponseModel.doctorImageUrl ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
Utils.buildImgWithNetwork(
url: getInvoicesListResponseModel.doctorImageUrl ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -71,8 +71,9 @@ class PharmacyInvoiceCard extends StatelessWidget {
children: [
Column(
children: [
Image.network(
pharmacyInvoice.doctorImageURL ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
Utils.buildImgWithNetwork(
url: pharmacyInvoice.doctorImageURL ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -84,24 +84,9 @@ class _OfferAndDiscountsFullScreenSwiperPageState extends State<OfferAndDiscount
flipX: getIt.get<AppState>().isArabic(),
child: ClipRRect(
borderRadius: BorderRadius.circular(16.r),
child: Image.asset(
_promoImages[index],
child: Utils.buildImgWithAssets(
icon: _promoImages[index],
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return Container(
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(16.r),
),
child: Center(
child: Icon(
Icons.image_outlined,
size: 100.h,
color: Colors.white.withValues(alpha: 0.5),
),
),
);
},
),
),
),

@ -2,6 +2,7 @@ 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/utils/size_utils.dart';
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/offers_and_discounts/models/offers_and_discounts_response_model.dart';
@ -92,8 +93,9 @@ class OffersAndDiscountsDetailedPage extends StatelessWidget {
children: [
ClipRRect(
borderRadius: BorderRadius.circular(24.h),
child: Image.network(
offer.imageUrl!,
child: Utils.buildImgWithNetwork(
url: offer.imageUrl!,
iconColor: AppColors.blackBgColor,
width: double.infinity,
height: 250.h,
fit: BoxFit.cover,

@ -158,8 +158,9 @@ class _OffersAndDiscountsPageState extends State<OffersAndDiscountsPage> {
ClipRRect(
borderRadius: BorderRadius.vertical(top: Radius.circular(24.h)),
child: SizedBox.expand(
child: Image.network(
offersAndDiscountVM.filteredOffers[index].imageUrl!,
child: Utils.buildImgWithNetwork(
url: offersAndDiscountVM.filteredOffers[index].imageUrl!,
iconColor: AppColors.blackBgColor,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(

@ -5,6 +5,8 @@ import 'package:hmg_patient_app_new/presentation/offers_and_discounts/offer_and_
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:smooth_corner/smooth_corner.dart';
import '../../../core/utils/utils.dart';
class OffersAndDiscountsCarousel extends StatefulWidget {
const OffersAndDiscountsCarousel({super.key});
@ -112,19 +114,9 @@ class _OffersAndDiscountsCarouselState extends State<OffersAndDiscountsCarousel>
padding: const EdgeInsets.all(2.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(11.r),
child: Image.asset(
imagePath,
child: Utils.buildImgWithAssets(
icon: imagePath,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
color: AppColors.greyColor,
child: Icon(
Icons.image,
color: AppColors.textColorLight,
size: 32.h,
),
);
},
),
),
),

@ -5,6 +5,7 @@ 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/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/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@ -110,8 +111,8 @@ class _ParkingPageState extends State<ParkingPage> {
borderRadius: BorderRadius.circular(24.r),
child: Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Image.asset(
AppAssets.carParkingService,
child: Utils.buildImgWithAssets(
icon: AppAssets.carParkingService,
fit: BoxFit.fitHeight,
height: 480.h,
width: 520.w,

@ -61,8 +61,9 @@ class PrescriptionDeliveryOrderSummaryPage extends StatelessWidget {
borderRadius: BorderRadius.all(
Radius.circular(5.r),
),
child: Image.network(
prescriptionsViewModel.prescriptionDetailsList[index].imageSRCUrl!,
child: Utils.buildImgWithNetwork(
url: prescriptionsViewModel.prescriptionDetailsList[index].imageSRCUrl!,
iconColor: AppColors.blackBgColor,
fit: BoxFit.cover,
width: 60.w,
height: 70.h,
@ -99,8 +100,9 @@ class PrescriptionDeliveryOrderSummaryPage extends StatelessWidget {
ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(20.r),
child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lat},${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lng}&zoom=15&size=350x165&maptype=roadmap&markers=color:red%7C${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lat},${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lng}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng",
child: Utils.buildImgWithNetwork(
url: "https://maps.googleapis.com/maps/api/staticmap?center=${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lat},${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lng}&zoom=15&size=350x165&maptype=roadmap&markers=color:red%7C${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lat},${prescriptionsViewModel.locationGeocodeResponse.results.first.geometry.location.lng}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng",
iconColor: AppColors.blackBgColor,
fit: BoxFit.contain,
),
),

@ -125,8 +125,9 @@ class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
widget.prescriptionsResponseModel.doctorImageURL!,
Utils.buildImgWithNetwork(
url: widget.prescriptionsResponseModel.doctorImageURL!,
iconColor: AppColors.blackBgColor,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,

@ -42,8 +42,9 @@ class PrescriptionItemView extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
spacing: 8.h,
children: [
Image.network(
isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].imageThumbUrl!,
Utils.buildImgWithNetwork(
url: isLoading ? "" : prescriptionVM.prescriptionDetailsList[index].imageThumbUrl!,
iconColor: AppColors.blackBgColor,
width: 60.h,
height: 60.h,
errorBuilder: (cxt, child, tr) {

@ -150,8 +150,9 @@ class _PrescriptionsListPageState extends State<PrescriptionsListPage> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
model.patientPrescriptionOrders[index].doctorImageURL!,
Utils.buildImgWithNetwork(
url: model.patientPrescriptionOrders[index].doctorImageURL!,
iconColor: AppColors.blackBgColor,
width: 24.h,
height: 24.h,
fit: BoxFit.fill,

@ -0,0 +1,476 @@
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/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/profile_settings/profile_settings_view_model.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/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:provider/provider.dart';
enum VisualMode { off, invert, dim, highContrast }
class AccessibilityPage extends StatefulWidget {
const AccessibilityPage({super.key});
@override
State<AccessibilityPage> createState() => _AccessibilityPageState();
}
class _AccessibilityPageState extends State<AccessibilityPage> {
late ProfileSettingsViewModel profileSettingsViewModel;
int _currentFontSizeStep = 2; // 0: Small, 1: Small-Medium, 2: Medium (default), 3: Medium-Large, 4: Large
VisualMode _selectedMode = VisualMode.off;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
profileSettingsViewModel = Provider.of<ProfileSettingsViewModel>(context, listen: false);
// Load saved settings from ViewModel
_loadSavedSettings();
}
});
}
void _loadSavedSettings() {
setState(() {
_currentFontSizeStep = profileSettingsViewModel.fontSizeStep;
_selectedMode = _visualModeFromString(profileSettingsViewModel.visualMode);
});
}
VisualMode _visualModeFromString(String mode) {
switch (mode) {
case 'off':
return VisualMode.off;
case 'invert':
return VisualMode.invert;
case 'dim':
return VisualMode.dim;
case 'highContrast':
return VisualMode.highContrast;
default:
return VisualMode.off;
}
}
String _visualModeToString(VisualMode mode) {
switch (mode) {
case VisualMode.off:
return 'off';
case VisualMode.invert:
return 'invert';
case VisualMode.dim:
return 'dim';
case VisualMode.highContrast:
return 'highContrast';
}
}
@override
void dispose() {
super.dispose();
}
double _getFontSizeForStep(int step) {
const double mediumSize = 40.0; // Medium is baseline
switch (step) {
case 0:
return mediumSize * 0.5; // Small: 20.0
case 1:
return mediumSize * 0.75; // Small-Medium: 30.0
case 2:
return mediumSize; // Medium (default): 40.0
case 3:
return mediumSize * 1.5; // Medium-Large: 60.0
case 4:
return mediumSize * 1.75; // Large: 70.0
default:
return mediumSize;
}
}
@override
Widget build(BuildContext context) {
profileSettingsViewModel = Provider.of<ProfileSettingsViewModel>(context, listen: false);
return CollapsingListView(
title: LocaleKeys.accessibility.tr(context: context),
isClose: true,
bottomChild: Container(
padding: EdgeInsets.all(24.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
child: CustomButton(
height: 56.h,
icon: AppAssets.checkmark_icon,
iconColor: AppColors.whiteColor,
text: LocaleKeys.saveChanges.tr(context: context),
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
fontSize: 16.f,
isBold: true,
onPressed: () {
// Save accessibility settings to ViewModel
profileSettingsViewModel.setFontSizeStep(_currentFontSizeStep);
profileSettingsViewModel.setVisualMode(_visualModeToString(_selectedMode));
// Show success message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: LocaleKeys.settingsSavedSuccessfully.tr(context: context).toText14(
color: AppColors.whiteColor,
),
backgroundColor: AppColors.successColor,
duration: const Duration(seconds: 2),
),
);
// Pop the page
Navigator.pop(context);
},
),
),
child: SingleChildScrollView(
padding: EdgeInsets.only(top: 16.h, bottom: 24.h, left: 24.w, right: 24.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Font Size Card
_buildFontSizeCard(),
SizedBox(height: 24.h),
// Mode for Partially Blind Card
_buildVisualModeCard(),
],
),
),
);
}
Widget _buildFontSizeCard() {
return Container(
padding: EdgeInsets.all(24.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Card Label
LocaleKeys.fontSize.tr(context: context).toText18(isBold: true),
SizedBox(height: 24.h),
// Center Aa heading that changes size
Container(
height: 70.h,
child: Center(
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 300),
style: TextStyle(
fontSize: _getFontSizeForStep(_currentFontSizeStep),
fontWeight: FontWeight.bold,
color: AppColors.blackBgColor,
),
child: const Text("Aa"),
),
),
),
SizedBox(height: 32.h),
// Stepped slider
Column(
children: [
// Stack to position circles on top of the bar
Stack(
alignment: Alignment.center,
children: [
// Grey bar
Container(
height: 4.h,
decoration: BoxDecoration(
color: AppColors.greyTextColor.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(2.r),
),
),
// Step indicator with dots positioned on top of the bar
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate(5, (index) {
bool isSelected = index == _currentFontSizeStep;
return GestureDetector(
onTap: () {
setState(() {
_currentFontSizeStep = index;
});
},
behavior: HitTestBehavior.opaque,
child: Padding(
padding: EdgeInsets.all(8.w), // Increased tap zone
child: Container(
width: isSelected ? 20.w : 12.w,
height: isSelected ? 20.w : 12.w,
decoration: BoxDecoration(
color: isSelected ? AppColors.primaryRedColor : Colors.transparent,
shape: BoxShape.circle,
border: Border.all(
color: isSelected ? AppColors.primaryRedColor : AppColors.greyTextColor.withValues(alpha: 0.3),
width: 2.w,
),
),
),
),
);
}),
),
],
),
SizedBox(height: 12.h),
// Labels
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.fontSizeSmall.tr(context: context).toText12(color: AppColors.greyTextColor),
LocaleKeys.fontSizeMedium.tr(context: context).toText12(color: AppColors.greyTextColor),
LocaleKeys.fontSizeLarge.tr(context: context).toText12(color: AppColors.greyTextColor),
],
),
],
),
],
),
);
}
Widget _buildVisualModeCard() {
return Container(
padding: EdgeInsets.all(24.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Card Label
LocaleKeys.blindModes.tr(context: context).toText18(isBold: true),
SizedBox(height: 24.h),
// Two columns layout
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Left Column - Radio buttons
Expanded(
flex: 2,
child: Column(
children: [
_buildRadioOption(VisualMode.off, LocaleKeys.offTheme.tr(context: context)),
SizedBox(height: 12.h),
_buildRadioOption(VisualMode.invert, LocaleKeys.invertTheme.tr(context: context)),
SizedBox(height: 12.h),
_buildRadioOption(VisualMode.dim, LocaleKeys.dimTheme.tr(context: context)),
SizedBox(height: 12.h),
_buildRadioOption(VisualMode.highContrast, LocaleKeys.highContrastTheme.tr(context: context)),
],
),
),
SizedBox(width: 16.w),
// Right Column - Preview Card
Expanded(
flex: 3,
child: _buildPreviewCard(),
),
],
),
],
),
);
}
Widget _buildRadioOption(VisualMode mode, String label) {
bool isSelected = _selectedMode == mode;
return GestureDetector(
onTap: () {
setState(() {
_selectedMode = mode;
});
},
child: Row(
children: [
Container(
width: 20.w,
height: 20.w,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: isSelected ? AppColors.primaryRedColor : AppColors.greyTextColor,
width: 2.w,
),
color: Colors.transparent,
),
child: isSelected
? Center(
child: Container(
width: 10.w,
height: 10.w,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.primaryRedColor,
),
),
)
: null,
),
SizedBox(width: 8.w),
label.toText14(
isBold: isSelected,
color: isSelected ? AppColors.blackBgColor : AppColors.greyTextColor,
),
],
),
);
}
Widget _buildPreviewCard() {
// Always build preview content with base "Off" mode colors
Widget previewContent = Container(
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
isCustomShadow: [
BoxShadow(
color: const Color(0xff000000).withValues(alpha: 0.1),
blurRadius: 16,
spreadRadius: 16 * 0.1, // 10% of blur radius
offset: const Offset(0, 0), // Uniform shadow on all sides
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top row with heading and arrow
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
LocaleKeys.cardHeading.tr(context: context).toText14(
isBold: true,
color: AppColors.blackBgColor, // Always use base color
),
Transform.scale(
scaleX: Utils.appState.isArabic() ? -1 : 1,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_forward,
iconColor: AppColors.blackBgColor, // Always use base color
),
),
],
),
SizedBox(height: 16.h),
// Price with SAR symbol
Row(
children: [
"1234".toText24(
isBold: true,
color: AppColors.blackBgColor, // Always use base color
),
SizedBox(width: 4.w),
LocaleKeys.riyal.tr(context: context).toText14(
color: AppColors.blackBgColor, // Always use base color
),
SizedBox(width: 4.w),
Utils.buildSvgWithAssets(
icon: AppAssets.saudi_riyal_icon,
iconColor: AppColors.blackBgColor, // Always use base color
width: 16.w,
height: 16.w,
),
],
),
SizedBox(height: 16.h),
// Button - always show with base "Off" colors
CustomButton(
height: 44.h,
icon: AppAssets.add_icon,
iconColor: AppColors.whiteColor,
// Always use base color
text: LocaleKeys.buttonText.tr(context: context),
backgroundColor: AppColors.primaryRedColor,
// Always use base color
borderColor: AppColors.primaryRedColor,
// Always use base color
textColor: AppColors.whiteColor,
// Always use base color
fontSize: 14.f,
onPressed: () {},
),
],
),
);
// Apply visual mode filters to preview
switch (_selectedMode) {
case VisualMode.invert:
return ColorFiltered(
colorFilter: const ColorFilter.matrix(<double>[
-1, 0, 0, 0, 255, // Red channel inverted
0, -1, 0, 0, 255, // Green channel inverted
0, 0, -1, 0, 255, // Blue channel inverted
0, 0, 0, 1, 0, // Alpha channel unchanged
]),
child: previewContent,
);
case VisualMode.dim:
return Stack(
children: [
previewContent,
Positioned.fill(
child: IgnorePointer(
child: Container(
decoration: BoxDecoration(
color: AppColors.blackBgColor.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(20.r),
),
),
),
),
],
);
case VisualMode.highContrast:
return ColorFiltered(
colorFilter: const ColorFilter.matrix(<double>[
0.2126, 0.7152, 0.0722, 0, 0, // Red channel (grayscale)
0.2126, 0.7152, 0.0722, 0, 0, // Green channel (grayscale)
0.2126, 0.7152, 0.0722, 0, 0, // Blue channel (grayscale)
0, 0, 0, 1, 0, // Alpha channel unchanged
]),
child: previewContent,
);
case VisualMode.off:
return previewContent;
}
}
}

@ -23,6 +23,7 @@ import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_v
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/insurance_update_details_card.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/accessibility_page.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/profile_picture_widget.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/update_email_widget.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/widgets/update_emergency_contact_widget.dart';
@ -254,6 +255,10 @@ class ProfileSettingsState extends State<ProfileSettings> {
);
},
),
1.divider,
actionItem(AppAssets.bell, LocaleKeys.accessibility.tr(context: context), () {
Navigator.of(context).push(CustomPageRoute(page: const AccessibilityPage()));
}),
],
),
),
@ -600,7 +605,13 @@ class _FamilyCardWidgetState extends State<FamilyCardWidget> {
],
).expanded,
// Icon(Icons.qr_code, size: 56.h)
Image.network("https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${widget.profile.responseId.toString()}", fit: BoxFit.contain, height: 56.h, width: 56.w)
Utils.buildImgWithNetwork(
url: "https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=${widget.profile.responseId.toString()}",
iconColor: AppColors.transparent,
fit: BoxFit.contain,
height: 56.h,
width: 56.w,
)
],
),
SizedBox(height: 4.h),

@ -128,12 +128,10 @@ class _ProfilePictureWidgetState extends State<ProfilePictureWidget> {
// Show default image (no image data or user has no uploaded image)
print('📷 Showing default avatar for user $currentPatientId');
return Image.asset(
defaultImage,
key: ValueKey('default_$currentPatientId'),
return Utils.buildImgWithAssets(
icon: defaultImage,
width: 136.w,
height: 136.h,
gaplessPlayback: true,
);
}

@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.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/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/accessibility/preserve_svg_colors.dart';
class RadiologyAiAnalysisWidget extends StatelessWidget {
final RadiologyAiAnalysisResponse data;
@ -47,7 +48,7 @@ class RadiologyAiAnalysisWidget extends StatelessWidget {
Container(
padding: EdgeInsets.all(8.r),
decoration: BoxDecoration(gradient: AppColors.aiLinearGradient, borderRadius: BorderRadius.circular(8.r)),
child: SvgPicture.asset(AppAssets.aiOverView, colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), height: 18.r, width: 18.r),
child: PreserveSvgColors(child: SvgPicture.asset(AppAssets.aiOverView, colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), height: 18.r, width: 18.r)),
),
],
),

@ -401,8 +401,9 @@ class _RadiologyOrdersPageState extends State<RadiologyOrdersPage> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
Utils.buildImgWithNetwork(
url: group.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
iconColor: AppColors.transparent,
width: 24.w,
height: 24.h,
fit: BoxFit.cover,

@ -1,7 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
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/my_appointments/appointment_rating_view_model.dart';
@ -96,7 +96,13 @@ class _RateAppointmentClinicState extends State<RateAppointmentClinic> {
});
},
iconSize: 35,
icon: SvgPicture.asset('assets/images/svg/rate_${index + 1}.svg', colorFilter: getColors(rating)),
icon: Utils.buildSvgWithAssets(
icon: 'assets/images/svg/rate_${index + 1}.svg',
iconColor: getRatingColor(rating),
width: 35,
height: 35,
applyThemeColor: false,
),
),
)
: IconButton(
@ -106,7 +112,12 @@ class _RateAppointmentClinicState extends State<RateAppointmentClinic> {
});
},
iconSize: 35,
icon: SvgPicture.asset('assets/images/svg/rate_${index + 1}.svg'),
icon: Utils.buildSvgWithAssets(
icon: 'assets/images/svg/rate_${index + 1}.svg',
width: 35,
height: 35,
applyThemeColor: false,
),
),
),
],
@ -181,6 +192,23 @@ class _RateAppointmentClinicState extends State<RateAppointmentClinic> {
);
}
Color getRatingColor(int rating) {
switch (rating) {
case 5:
return AppColors.bgGreenColor;
case 4:
return Colors.greenAccent;
case 3:
return AppColors.warningLightColor;
case 2:
return Colors.orange;
case 1:
return AppColors.primaryRedColor;
default:
return AppColors.greyColor;
}
}
ColorFilter getColors(int rating){
switch(rating){

@ -9,6 +9,9 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
import '../../../core/utils/utils.dart';
import '../../../theme/colors.dart';
class BuildDoctorRow extends StatelessWidget {
bool isForClinic = false;
AppointmentDetails? appointmentDetails;
@ -21,8 +24,9 @@ class BuildDoctorRow extends StatelessWidget {
return Padding(padding: EdgeInsets.all(16),child:Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
isForClinic ? 'https://hmgwebservices.com/Images/Hospitals/${appointmentDetails!.projectID}.jpg' : appointmentDetails!.doctorImageURL ,
Utils.buildImgWithNetwork(
url: isForClinic ? 'https://hmgwebservices.com/Images/Hospitals/${appointmentDetails!.projectID}.jpg' : appointmentDetails!.doctorImageURL ,
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -81,7 +81,7 @@ class SmartwatchHomePage extends StatelessWidget {
),
child: Column(
children: [
Image.asset("assets/images/png/smartwatches/apple-watch-5.jpg", width: 136.h, height: 136.h).paddingSymmetrical(24.w, 8.h),
Utils.buildImgWithAssets(icon: "assets/images/png/smartwatches/apple-watch-5.jpg", width: 136.h, height: 136.h).paddingSymmetrical(24.w, 8.h),
"Apple Watch".needTranslation.toText16(isBold: true),
CustomButton(
text: LocaleKeys.selectSmartWatch.tr(context: context),
@ -115,7 +115,7 @@ class SmartwatchHomePage extends StatelessWidget {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r),
child: Column(
children: [
Image.asset("assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg", fit: BoxFit.contain, width: 136.w, height: 136.h)
Utils.buildImgWithAssets(icon: "assets/images/png/smartwatches/galaxy_watch_8_classic.jpeg", fit: BoxFit.contain, width: 136.w, height: 136.h)
.paddingSymmetrical(24.w, 8.h),
"Samsung Watch".needTranslation.toText16(isBold: true),
CustomButton(
@ -153,7 +153,7 @@ class SmartwatchHomePage extends StatelessWidget {
),
child: Column(
children: [
Image.asset("assets/images/png/smartwatches/Huawei_Watch.png", width: 136.w, height: 136.h).paddingSymmetrical(24.w, 8.h),
Utils.buildImgWithAssets(icon: "assets/images/png/smartwatches/Huawei_Watch.png", width: 136.w, height: 136.h).paddingSymmetrical(24.w, 8.h),
"Huawei Watch".needTranslation.toText16(isBold: true),
CustomButton(
text: LocaleKeys.selectSmartWatch.tr(context: context),
@ -187,7 +187,7 @@ class SmartwatchHomePage extends StatelessWidget {
),
child: Column(
children: [
Image.asset("assets/images/png/smartwatches/Whoop_Watch.png", width: 136.w, height: 136.h).paddingSymmetrical(24.w, 8.h),
Utils.buildImgWithAssets(icon: "assets/images/png/smartwatches/Whoop_Watch.png", width: 136.w, height: 136.h).paddingSymmetrical(24.w, 8.h),
"Whoop Watch".needTranslation.toText16(isBold: true),
CustomButton(
text: LocaleKeys.selectSmartWatch.tr(context: context),

@ -48,8 +48,8 @@ class SmartwatchInstructionsPage extends StatelessWidget {
mainAxisSize: MainAxisSize.max,
spacing: 18.h,
children: [
Image.asset(
smartwatchDetails.watchIcon,
Utils.buildImgWithAssets(
icon: smartwatchDetails.watchIcon,
fit: BoxFit.contain,
height: 280.h,
width: 280.w,

@ -1,11 +1,11 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:health/health.dart';
import 'package:fl_chart/fl_chart.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/size_utils.dart';
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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/smartwatches/widgets/health_metric.dart';
@ -53,12 +53,12 @@ class HealthMetricCard extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
metric.svgIcon,
Utils.buildSvgWithAssets(
icon: metric.svgIcon,
height: 30.h,
width: 30.h,
fit: BoxFit.contain,
// color: color,
applyThemeColor: false,
),
// Icon(
// metric.icon,

@ -2,6 +2,8 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/organ_model.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/organ_dot_widget.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/organ_tooltip_widget.dart';
@ -113,11 +115,21 @@ class _InteractiveBodyWidgetState extends State<InteractiveBodyWidget> {
children: [
// Body image
Positioned.fill(
child: Image.asset(
widget.bodyImageAsset,
fit: BoxFit.fill,
color: widget.isBodyHidden ? Colors.black.withValues(alpha: 0.5) : null,
),
child: widget.isBodyHidden
? ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.black.withValues(alpha: 0.5),
BlendMode.darken,
),
child: Utils.buildImgWithAssets(
icon: widget.bodyImageAsset,
fit: BoxFit.fill,
),
)
: Utils.buildImgWithAssets(
icon: widget.bodyImageAsset,
fit: BoxFit.fill,
),
),
// Organ dots

@ -1779,7 +1779,7 @@ class _CallScreenState extends State<CallScreen> {
children: [
IconButton(
onPressed: onPressAudio,
icon: isMuted.value ? Image.asset("assets/images/png/zoom/unmute@2x.png") : Image.asset("assets/images/png/zoom/mute@2x.png"),
icon: isMuted.value ? Utils.buildImgWithAssets(icon: "assets/images/png/zoom/unmute@2x.png") : Utils.buildImgWithAssets(icon: "assets/images/png/zoom/mute@2x.png"),
iconSize: circleButtonSize,
tooltip: isMuted.value == true ? "Unmute" : "Mute",
),
@ -1791,7 +1791,7 @@ class _CallScreenState extends State<CallScreen> {
IconButton(
onPressed: onPressVideo,
iconSize: circleButtonSize,
icon: isVideoOn.value ? Image.asset("assets/images/png/zoom/video-off@2x.png") : Image.asset("assets/images/png/zoom/video-on@2x.png"),
icon: isVideoOn.value ? Utils.buildImgWithAssets(icon: "assets/images/png/zoom/video-off@2x.png") : Utils.buildImgWithAssets(icon: "assets/images/png/zoom/video-on@2x.png"),
),
Column(
children: [

@ -107,7 +107,7 @@ class _AncillaryOrderPaymentPageState extends State<AncillaryOrderPaymentPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(AppAssets.mada, width: 50.h, height: 50.h),
Utils.buildImgWithAssets(icon: AppAssets.mada, width: 50.h, height: 50.h),
SizedBox(height: 16.h),
LocaleKeys.mada.tr(context: context).toText16(isBold: true).toShimmer2(isShow: todoVM.isProcessingPayment),
],
@ -177,9 +177,9 @@ class _AncillaryOrderPaymentPageState extends State<AncillaryOrderPaymentPage> {
children: [
Row(
children: [
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
Utils.buildImgWithAssets(icon: AppAssets.visa, width: 50.h, height: 50.h),
SizedBox(width: 8.h),
Image.asset(AppAssets.mastercard, width: 40.h, height: 40.h),
Utils.buildImgWithAssets(icon: AppAssets.mastercard, width: 40.h, height: 40.h),
],
).toShimmer2(isShow: todoVM.isProcessingPayment),
SizedBox(height: 16.h),

@ -224,8 +224,8 @@ class _AncillaryOrderDetailsListState extends State<AncillaryOrderDetailsList> {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
Utils.buildImgWithAssets(
icon: gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
width: 56.w,
height: 56.h,
),

@ -138,8 +138,9 @@ class AncillaryOrderCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (!isLoading) ...[
Image.network(
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
Utils.buildImgWithNetwork(
url: "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown.png",
iconColor: AppColors.transparent,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,

@ -235,12 +235,11 @@ class _VitalSignPageState extends State<VitalSignPage> {
child: Stack(
fit: StackFit.expand,
children: [
Image.asset(
getIt.get<AppState>().getAuthenticatedUser()?.gender == 1
Utils.buildImgWithAssets(
icon: getIt.get<AppState>().getAuthenticatedUser()?.gender == 1
? AppAssets.bmiFullBody
: AppAssets.bmiFullBodyFemale,
fit: BoxFit.cover,
alignment: Alignment.topCenter,
),
Align(
alignment: Alignment.bottomCenter,

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
extension WithContainer on Widget {
@ -63,7 +63,7 @@ class DefaultButton extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (iconData != null) Icon(iconData, color: textColor),
if (svgIcon != null) SvgPicture.asset(svgIcon ?? ""),
if (svgIcon != null) Utils.buildSvgWithAssets(icon: svgIcon ?? "", applyThemeColor: false),
if (!isTextExpanded)
Padding(
padding: EdgeInsets.only(

@ -78,7 +78,7 @@ class AppCustomChipWidget extends StatelessWidget {
? Chip(
avatar: icon.isNotEmpty
? isIconPNG
? Image.asset(icon, width: iconS, height: iconS)
? Utils.buildImgWithAssets(icon: icon, width: iconS, height: iconS)
: Utils.buildSvgWithAssets(
icon: icon,
width: iconS,

@ -79,7 +79,7 @@ class ImageOptions {
}
},
onFilesTap: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
FilePickerResult? result = await FilePicker.pickFiles(
type: FileType.custom,
allowedExtensions: [
'jpg',

@ -12,6 +12,8 @@ import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:map_launcher/map_launcher.dart';
import '../../core/utils/utils.dart';
/// A reusable location map widget that displays a static map with address and directions button
/// Can be used in any review screen (HHC, CMC, etc.)
class LocationMapWidget extends StatelessWidget {
@ -127,24 +129,10 @@ class LocationMapWidget extends StatelessWidget {
ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(24.r),
child: Image.network(
staticMapUrl,
child: Utils.buildImgWithNetwork(
url: staticMapUrl,
iconColor: AppColors.transparent,
fit: BoxFit.contain,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
height: 165.h,
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(24.r),
),
child: Center(
child: CircularProgressIndicator(
color: AppColors.primaryRedColor,
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return Container(
height: 165.h,

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class FullScreenImageViewer extends StatelessWidget {
@ -22,8 +22,8 @@ class FullScreenImageViewer extends StatelessWidget {
body: Center(
child: InteractiveViewer(
child: isSvg
? SvgPicture.asset(path, width: double.infinity, fit: BoxFit.contain)
: Image.asset(width: double.infinity, path, fit: BoxFit.contain),
? Utils.buildSvgWithAssets(icon: path, width: double.infinity, fit: BoxFit.contain, applyThemeColor: false)
: Utils.buildImgWithAssets(icon: path, width: double.infinity, fit: BoxFit.contain),
),
),
);

@ -3,9 +3,9 @@ import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.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/buttons/custom_button.dart';
@ -93,9 +93,10 @@ class _NfcLayoutState extends State<NfcLayout> {
SizedBox(
height: 30,
),
SvgPicture.asset(
"assets/images/nfc/contactless.svg",
Utils.buildSvgWithAssets(
icon: "assets/images/nfc/contactless.svg",
height: MediaQuery.of(context).size.width / 3,
applyThemeColor: false,
),
SizedBox(
height: 30,
@ -161,8 +162,8 @@ class _NfcLayoutState extends State<NfcLayout> {
SizedBox(
height: 30,
),
Image.asset(
"assets/images/nfc/ic_done.png",
Utils.buildImgWithAssets(
icon: "assets/images/nfc/ic_done.png",
height: MediaQuery.of(context).size.width / 3,
),
SizedBox(

@ -4,6 +4,7 @@ import 'package:hmg_patient_app_new/core/app_assets.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/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
class UserAvatarWidget extends StatelessWidget {
final double width;
@ -84,11 +85,11 @@ class UserAvatarWidget extends StatelessWidget {
// If decoding fails, show default image
return ClipRRect(
borderRadius: BorderRadius.circular(effectiveBorderRadius),
child: Image.asset(
defaultImage,
child: Utils.buildImgWithAssets(
icon: defaultImage,
width: width,
height: height,
fit: fit,
fit: fit ?? BoxFit.cover,
),
);
}
@ -97,11 +98,11 @@ class UserAvatarWidget extends StatelessWidget {
// Show default image with rounded corners
return ClipRRect(
borderRadius: BorderRadius.circular(effectiveBorderRadius),
child: Image.asset(
defaultImage,
child: Utils.buildImgWithAssets(
icon: defaultImage,
width: width,
height: height,
fit: fit,
fit: fit ?? BoxFit.cover,
),
);
}

Loading…
Cancel
Save