Dynamic theming has been implemented

pull/380/head
FaizHashmi 4 weeks ago
parent c88bda6e3d
commit 803d74cceb

@ -138,8 +138,7 @@ class ApiClientImp implements ApiClient {
} else {}
if (body.containsKey('isDentalAllowedBackend')) {
body['isDentalAllowedBackend'] =
body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND;
body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND;
}
if (!body.containsKey('IsPublicRequest')) {
@ -271,11 +270,11 @@ class ApiClientImp implements ApiClient {
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'POST');
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_socket_exception');
return;
@ -283,19 +282,19 @@ class ApiClientImp implements ApiClient {
final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
onFailure(message, -1, failureType: ConnectivityFailure(message));
_analytics.errorTracking.log(endPoint, error: "ClientException: $e");
// Enhanced Clarity logging
Clarity.setCustomTag('api_err_type', 'client_exception');
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'POST');
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_client_exception');
return;
} on TimeoutException catch (_) {
final message = LocaleKeys.networkTimeout.tr();
@ -307,36 +306,36 @@ class ApiClientImp implements ApiClient {
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'POST');
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_timeout');
return;
} catch (e) {
final message = LocaleKeys.networkUnknownError.tr();
onFailure(message, -1, failureType: ConnectivityFailure(message));
_analytics.errorTracking.log(endPoint, error: "UnknownException: $e");
// Enhanced Clarity logging for unknown errors
Clarity.setCustomTag('api_err_type', 'unknown_exception');
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'POST');
// Truncate exception message for Clarity
final exceptionMsg = e.toString();
final truncatedMsg = exceptionMsg.length > 252 ? '...${exceptionMsg.substring(exceptionMsg.length - 252)}' : exceptionMsg;
Clarity.setCustomTag('api_err_exception', truncatedMsg);
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_unknown_exception');
return;
}
@ -384,24 +383,19 @@ class ApiClientImp implements ApiClient {
onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
statusCode,
failureType:
UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
failureType: UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
);
// logApiEndpointError(endPoint, "session logged out", statusCode);
}
if (isAllowAny) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['IsAuthenticated'] == null) {
if (parsed['isSMSSent'] == true) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['MessageStatus'] == 1) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else if (parsed['Result'] == 'OK') {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
onFailure(
parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
@ -411,8 +405,7 @@ class ApiClientImp implements ApiClient {
logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
}
} else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
}
// else if (parsed['IsAuthenticated'] == false) {
// onFailure(
@ -424,8 +417,7 @@ class ApiClientImp implements ApiClient {
// }
else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) {
if (parsed['ErrorSearchMsg'] == null) {
@ -459,8 +451,7 @@ class ApiClientImp implements ApiClient {
}
} else {
if (parsed['SameClinicApptList'] != null) {
onSuccess(parsed, statusCode,
messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
} else {
if (parsed['message'] != null) {
onFailure(
@ -537,74 +528,74 @@ class ApiClientImp implements ApiClient {
final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
onFailure(message, -1);
_analytics.errorTracking.log(endPoint, error: "SocketException: $e");
// Clarity logging for GET requests
Clarity.setCustomTag('api_err_type', 'socket_exception');
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'GET');
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_get_socket_exception');
return;
} on http.ClientException catch (e) {
final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
onFailure(message, -1);
_analytics.errorTracking.log(endPoint, error: "ClientException: $e");
Clarity.setCustomTag('api_err_type', 'client_exception');
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'GET');
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_get_client_exception');
return;
} on TimeoutException catch (_) {
final message = LocaleKeys.networkTimeout.tr();
onFailure(message, -1);
_analytics.errorTracking.log(endPoint, error: "TimeoutException");
Clarity.setCustomTag('api_err_type', 'timeout');
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'GET');
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_get_timeout');
return;
} catch (e) {
final message = LocaleKeys.networkUnknownError.tr();
onFailure(message, -1);
_analytics.errorTracking.log(endPoint, error: "UnknownException: $e");
Clarity.setCustomTag('api_err_type', 'unknown_exception');
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'GET');
final exceptionMsg = e.toString();
final truncatedMsg = exceptionMsg.length > 252 ? '...${exceptionMsg.substring(exceptionMsg.length - 252)}' : exceptionMsg;
Clarity.setCustomTag('api_err_exception', truncatedMsg);
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_get_unknown_exception');
return;
}
@ -614,18 +605,18 @@ class ApiClientImp implements ApiClient {
if (statusCode < 200 || statusCode >= 400) {
onFailure(LocaleKeys.networkErrorWhileFetching.tr(), statusCode);
logApiEndpointError(endPoint, LocaleKeys.networkErrorWhileFetching.tr(), statusCode);
// Clarity logging for GET status code errors
Clarity.setCustomTag('api_err_type', 'status_code_error');
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
Clarity.setCustomTag('api_err_method', 'GET');
Clarity.setCustomTag('api_err_status', statusCode.toString());
if (_appState.isAuthenticated) {
Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
}
Clarity.sendCustomEvent('api_get_status_error');
} else {
var parsed = json.decode(utf8.decode(response.bodyBytes));
@ -813,7 +804,7 @@ class ApiClientImp implements ApiClient {
// Extract the last part of the endpoint path for cleaner tracking
const int clarityLimit = 100;
final cleanEndpoint = endpoint.split('/').last;
if (cleanEndpoint.length <= clarityLimit) return cleanEndpoint;
return '...${cleanEndpoint.substring(cleanEndpoint.length - (clarityLimit - 3))}';
}

@ -864,8 +864,7 @@ var GET_CUSTOMER_INFO = "VerifyCustomer";
//Pharmacy
var GET_PHARMACY_CATEGORISE =
'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0';
var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0';
var GET_OFFERS_CATEGORISE = 'discountcategories';
var GET_OFFERS_PRODUCTS = 'offerproducts/';
var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=';

@ -989,7 +989,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
openDoctorScheduleCalendar();
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
borderColor: Colors.transparent,
textColor: Colors.white,
fontSize: 16.f,
fontWeight: FontWeight.w600,
@ -1097,7 +1097,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
openDoctorScheduleCalendar();
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
borderColor: Colors.transparent,
textColor: Colors.white,
fontSize: 16.f,
fontWeight: FontWeight.w600,

@ -67,8 +67,8 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
SizedBox(height: 16.h),
CustomTabBar(
initialIndex: myAppointmentsVM.selectedTabIndex,
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.secondaryLightRedColor,
tabs: [
// CustomTabBarModel(null, LocaleKeys.allAppt.tr(context: context)),
CustomTabBarModel(null, LocaleKeys.upcoming.tr(context: context)),
@ -269,9 +269,9 @@ class _MyAppointmentsPageState extends State<MyAppointmentsPage> {
),
);
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
isBold: true,
borderRadius: 12.r,

@ -84,8 +84,7 @@ class AppointmentDoctorCard extends StatelessWidget {
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.h, height: 15.h, iconColor: AppColors.ratingColorYellow),
SizedBox(height: 2.h),
"${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? 0.0}"
.toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true),
"${patientAppointmentHistoryResponseModel.decimalDoctorRate ?? 0.0}".toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true),
],
),
).circle(100),
@ -102,11 +101,7 @@ class AppointmentDoctorCard extends StatelessWidget {
children: [
Expanded(
child: (patientAppointmentHistoryResponseModel.doctorNameObj ?? "").toText16(
isBold: true,
isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? ""),
textOverflow: TextOverflow.ellipsis,
maxlines: 2
),
isBold: true, isEnglishOnly: !Utils.isArabicText(patientAppointmentHistoryResponseModel.doctorNameObj ?? ""), textOverflow: TextOverflow.ellipsis, maxlines: 2),
),
SizedBox(width: 12.w),
// (patientAppointmentHistoryResponseModel.doctorNationalityFlagURL != null &&
@ -142,18 +137,17 @@ class AppointmentDoctorCard extends StatelessWidget {
child: AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
icon: AppAssets.doctor_calendar_icon,
richText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${(patientAppointmentHistoryResponseModel.startTime != null && patientAppointmentHistoryResponseModel.startTime!.isNotEmpty) ? patientAppointmentHistoryResponseModel.startTime!.substring(0, 5) : DateUtil.formatDateToTimeLang(DateUtil.convertStringToDateSaudiTimezone(patientAppointmentHistoryResponseModel.appointmentDate!, patientAppointmentHistoryResponseModel.projectID), false)}"
.toText10(isBold: true),
richText:
"${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${(patientAppointmentHistoryResponseModel.startTime != null && patientAppointmentHistoryResponseModel.startTime!.isNotEmpty) ? patientAppointmentHistoryResponseModel.startTime!.substring(0, 5) : DateUtil.formatDateToTimeLang(DateUtil.convertStringToDateSaudiTimezone(patientAppointmentHistoryResponseModel.appointmentDate!, patientAppointmentHistoryResponseModel.projectID), false)}"
.toText10(isBold: true),
),
),
),
AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
icon: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppAssets.walkin_appointment_icon
: AppAssets.small_livecare_icon,
icon: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon,
iconColor: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppColors.textColor : Colors.white,
labelText: (patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? LocaleKeys.livecare.tr(context: context)
: LocaleKeys.walkin.tr(context: context),
labelText: (patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? LocaleKeys.livecare.tr(context: context) : LocaleKeys.walkin.tr(context: context),
backgroundColor: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppColors.greyColor : AppColors.successColor,
textColor: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ? AppColors.textColor : Colors.white,
),
@ -163,13 +157,12 @@ class AppointmentDoctorCard extends StatelessWidget {
),
),
(patientAppointmentHistoryResponseModel.isLiveCareAppointment! ||
patientAppointmentHistoryResponseModel.isExecludeDoctor! ||
patientAppointmentHistoryResponseModel.isExecludeDoctor! ||
patientAppointmentHistoryResponseModel.isClinicReBookingAllowed! == false ||
patientAppointmentHistoryResponseModel.isActiveDoctor! == false ||
!Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID))
!Utils.isClinicAllowedForRebook(patientAppointmentHistoryResponseModel.clinicID))
? SizedBox.shrink()
: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown)
.onPress(() async {
: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).onPress(() async {
// DoctorsListResponseModel selectedDoctor = DoctorsListResponseModel();
// selectedDoctor.doctorID = patientAppointmentHistoryResponseModel.doctorID;
// selectedDoctor.doctorImageURL = patientAppointmentHistoryResponseModel.doctorImageURL;
@ -270,7 +263,7 @@ class AppointmentDoctorCard extends StatelessWidget {
onAskDoctorTap();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
borderColor: Colors.transparent,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
isBold: true,
@ -310,7 +303,7 @@ class AppointmentDoctorCard extends StatelessWidget {
onCancelTap();
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
borderColor: Colors.transparent,
textColor: AppColors.whiteColor,
fontSize: 14.f,
isBold: true,
@ -329,7 +322,7 @@ class AppointmentDoctorCard extends StatelessWidget {
onRescheduleTap();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
borderColor: Colors.transparent,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
isBold: true,

@ -142,9 +142,9 @@ class _AppointmentRatingWidgetState extends State<AppointmentRatingWidget> {
Expanded(
child: CustomButton(
text: LocaleKeys.later.tr(context: context),
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
onPressed: () {
Navigator.pop(context);
},

@ -114,7 +114,7 @@ class QuickLoginState extends State<QuickLogin> {
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
Expanded(
child: CustomButton(
text: LocaleKeys.notNow.tr(context: context),
onPressed: () {
@ -122,7 +122,7 @@ class QuickLoginState extends State<QuickLogin> {
Navigator.pop(context, "true");
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
borderColor: Colors.transparent,
textColor: AppColors.primaryRedColor,
height: 56.h,
// icon: "assets/images/svg/apple-finder.svg",

@ -106,8 +106,8 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
children: [
SizedBox(height: 16.h),
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.secondaryLightRedColor,
initialIndex: bookAppointmentsVM.selectedTabIndex,
tabs: [
CustomTabBarModel(null, LocaleKeys.general.tr(context: context)),
@ -326,9 +326,9 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: SearchDoctorByName()));
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
isBold: true,
padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0),

@ -60,9 +60,7 @@ class DoctorProfilePage extends StatelessWidget {
doctorID: viewModel.doctorsProfileResponseModel.doctorID ?? 0,
isActive: viewModel.isFavouriteDoctor,
onSuccess: (response) {
Utils.showToast(viewModel.isFavouriteDoctor
? LocaleKeys.doctorAddedToFavourite.tr(context: context)
: LocaleKeys.doctorRemovedFromFavourite.tr(context: context));
Utils.showToast(viewModel.isFavouriteDoctor ? LocaleKeys.doctorAddedToFavourite.tr(context: context) : LocaleKeys.doctorRemovedFromFavourite.tr(context: context));
// Successfully added/removed favorite - refresh the favorites list
getIt.get<MyAppointmentsViewModel>().refreshFavouriteDoctors();
},
@ -101,14 +99,11 @@ class DoctorProfilePage extends StatelessWidget {
children: [
SizedBox(
width: isFoldable ? 250.w : 220.w,
child:
("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}")
.toString()
.toText24(isBold: true),
child: ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}")
.toString()
.toText24(isBold: true),
),
(bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty
? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first
: "")
(bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first : "")
.toString()
.toText18(isBold: true, color: AppColors.primaryRedColor),
],
@ -148,16 +143,12 @@ class DoctorProfilePage extends StatelessWidget {
children: [
Column(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(height: 16.h),
LocaleKeys.ratings.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate.toString().toText16(
isBold: true,
color: AppColors.textColor,
isUnderLine: true,
decorationColor: AppColors.textColor,
fontFamily: "Poppins"),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate
.toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"),
],
).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
@ -173,18 +164,12 @@ class DoctorProfilePage extends StatelessWidget {
SizedBox(width: 36.w),
Column(
children: [
Utils.buildSvgWithAssets(
icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(height: 16.h),
LocaleKeys.reviews.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor),
NumberFormat.decimalPattern("en_US")
.format(bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate ?? 0)
.toText16(
isBold: true,
color: AppColors.textColor,
isUnderLine: true,
decorationColor: AppColors.textColor,
fontFamily: "Poppins"),
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"),
],
).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
@ -215,9 +200,7 @@ class DoctorProfilePage extends StatelessWidget {
SizedBox(height: 16.h),
LocaleKeys.information.tr(context: context).toText14(isBold: true, color: AppColors.textColor),
SizedBox(height: 6.h),
(bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "")
.trim()
.toText12(isBold: true, color: AppColors.greyTextColor),
(bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "").trim().toText12(isBold: true, color: AppColors.greyTextColor),
SizedBox(height: 24.h),
],
).paddingSymmetrical(24.h, 0.h),
@ -238,8 +221,7 @@ class DoctorProfilePage extends StatelessWidget {
bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty;
bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName;
bookAppointmentsViewModel.selectedDoctor.doctorImageURL = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL;
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL =
bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL;
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL = bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL;
bookAppointmentsViewModel.selectedDoctor.clinicName = bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription;
bookAppointmentsViewModel.selectedDoctor.projectName = bookAppointmentsViewModel.doctorsProfileResponseModel.projectName;

@ -80,8 +80,8 @@ class LaserAppointment extends StatelessWidget {
child: Column(
children: [
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.secondaryLightRedColor,
tabs: [
CustomTabBarModel(null, LocaleKeys.malE.tr()),
CustomTabBarModel(null, LocaleKeys.femaleGender.tr()),

@ -308,9 +308,9 @@ class DoctorCard extends StatelessWidget {
});
}
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
isBold: true,
borderRadius: 10.r,

@ -291,7 +291,6 @@ class _LandingPageState extends State<LandingPage> {
child: Column(
children: [
const OccasionBannerWidget(),
Row(
spacing: 8.h,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -358,11 +357,11 @@ class _LandingPageState extends State<LandingPage> {
// ...existing commented code...
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
borderColor: Colors.transparent,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w700,
borderRadius: 12.r,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(12.h, 0, 12.h, 0),
height: 40.h,
),
@ -685,9 +684,9 @@ class _LandingPageState extends State<LandingPage> {
getIt.get<BookAppointmentsViewModel>().onTabChanged(0);
Navigator.of(context).push(CustomPageRoute(page: BookAppointmentPage()));
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0),
@ -1009,13 +1008,13 @@ class _LandingPageState extends State<LandingPage> {
),
),
),
(appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
(appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
? Container(
height: MediaQuery.paddingOf(context).top + 50.h,
decoration: ShapeDecoration(
color: AppColors.secondaryLightRedBorderColor,
color: AppColors.secondaryLightRedColorBase,
shape: SmoothRectangleBorder(
side: BorderSide(width: 1, color: AppColors.primaryRedColor.withAlpha(20)),
side: BorderSide(width: 1, color: AppColors.primaryRedColorBase.withAlpha(20)),
// borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
smoothness: 1,
),
@ -1026,7 +1025,7 @@ class _LandingPageState extends State<LandingPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColor, isBold: true).paddingSymmetrical(0.h, 0.h),
LocaleKeys.insuranceExpiredOrInactive.tr(context: context).toText14(color: AppColors.primaryRedColorBase, isBold: true).paddingSymmetrical(0.h, 0.h),
Row(
children: [
CustomButton(
@ -1038,8 +1037,8 @@ class _LandingPageState extends State<LandingPage> {
showCommonBottomSheetWithoutHeight(context,
child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false);
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.secondaryLightRedBorderColor,
backgroundColor: AppColors.primaryRedColorBase,
borderColor: AppColors.primaryRedColorBase,
textColor: Colors.white,
fontSize: 12.f,
fontWeight: FontWeight.bold,
@ -1047,7 +1046,7 @@ class _LandingPageState extends State<LandingPage> {
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
height: 36.h,
).paddingSymmetrical(12.h, 0.h),
Icon(Icons.close, color: AppColors.primaryRedColor).onPress(() {
Icon(Icons.close, color: AppColors.primaryRedColorBase).onPress(() {
insuranceVM.setIsInsuranceExpiryBannerShown(false);
}),
],

@ -14,8 +14,8 @@ import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'lab_order_by_test.dart';
class AlphabeticScroll extends StatefulWidget{
final List<String> alpahbetsAvailable;
class AlphabeticScroll extends StatefulWidget {
final List<String> alpahbetsAvailable;
final List<TestDetails> details;
final AppState appState;
final LabViewModel labViewModel;
@ -38,13 +38,13 @@ class _AlphabetScrollPageState extends State<AlphabeticScroll> {
Map<String, num> density = {};
Map<String, double> _offsetMap = {};
Map<String, GlobalKey> _offsetKeys = {};
Map<String, GlobalKey> _offsetKeys = {};
int _activeIndex = 0; // <-- Highlighted letter
@override
void initState() {
super.initState();
scheduleMicrotask((){
scheduleMicrotask(() {
_rebuildData();
});
itemPositionsListener.itemPositions.addListener(_onPositionChanged);
@ -61,9 +61,7 @@ class _AlphabetScrollPageState extends State<AlphabeticScroll> {
void _rebuildData() {
data.clear();
for (var char in widget.alpahbetsAvailable) {
data[char] = widget.details
.where((element) => element.description?.toLowerCase().startsWith(char.toLowerCase()) == true)
.toList();
data[char] = widget.details.where((element) => element.description?.toLowerCase().startsWith(char.toLowerCase()) == true).toList();
}
if (_activeIndex >= widget.alpahbetsAvailable.length) {
_activeIndex = 0;
@ -79,15 +77,12 @@ class _AlphabetScrollPageState extends State<AlphabeticScroll> {
// Get FIRST visible item (top-most)
final firstVisible = positions
.where((p) => p.itemTrailingEdge > 0) // visible
.reduce((min, p) =>
p.itemLeadingEdge < min.itemLeadingEdge ? p : min);
.reduce((min, p) => p.itemLeadingEdge < min.itemLeadingEdge ? p : min);
if(_activeIndex == firstVisible.index) return ;
if (_activeIndex == firstVisible.index) return;
setState(() {
_activeIndex = firstVisible.index;
});
print("Active index = $_activeIndex");
}
@override
@ -97,12 +92,8 @@ class _AlphabetScrollPageState extends State<AlphabeticScroll> {
}
void _scrollToLetter(String letter) async {
// itemScrollController.jumpTo(index:density[letter]?.toInt()??0, );
itemScrollController.scrollTo(
index: data.keys.toList().indexOf(letter).toInt()??0,
duration: Duration(seconds: 2),
curve: Curves.easeInOutCubic);
itemScrollController.scrollTo(index: data.keys.toList().indexOf(letter).toInt() ?? 0, duration: Duration(seconds: 2), curve: Curves.easeInOutCubic);
// final key = _offsetKeys[letter];
// if (key == null) return;
//
@ -134,58 +125,52 @@ class _AlphabetScrollPageState extends State<AlphabeticScroll> {
@override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.sizeOf(context).width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start, // Add this
children: [
Expanded(
child: Column(
children: [
SizedBox(
height: (MediaQuery.sizeOf(context).height),
child: _buildList(widget.alpahbetsAvailable)
),
],
),
width: MediaQuery.sizeOf(context).width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start, // Add this
children: [
Expanded(
child: Column(
children: [
SizedBox(height: (MediaQuery.sizeOf(context).height), child: _buildList(widget.alpahbetsAvailable)),
],
),
SizedBox(
width: 24.w,
height: MediaQuery.sizeOf(context).height-(70.h+ kToolbarHeight+100.h),
child: Column(
mainAxisSize: MainAxisSize.max, // Add this
mainAxisAlignment: MainAxisAlignment.center, // Changed from center to start
crossAxisAlignment: CrossAxisAlignment.center,
children:List.generate(widget.alpahbetsAvailable.length, (i) {
final isActive = (i == _activeIndex);
return GestureDetector(
onTap: () {
setState(() => _activeIndex = i);
_scrollToLetter(widget.alpahbetsAvailable[i]);
},
child: TweenAnimationBuilder<double>(
tween: Tween(begin: 1.0, end: isActive ? 1.8 : 1.0),
duration: Duration(milliseconds: 120),
curve: Curves.easeOut,
builder: (_, scale, child) {
return Transform.scale(
scale: scale,
child: Opacity(
opacity: isActive ? 1.0 : 0.5,
child: widget.alpahbetsAvailable[i].toUpperCase().toText14(
color: !isActive ? AppColors.greyTextColor : AppColors.primaryRedColor, isEnglishOnly: true
),
),
);
},
),
);
}
),
SizedBox(
width: 24.w,
height: MediaQuery.sizeOf(context).height - (70.h + kToolbarHeight + 100.h),
child: Column(
mainAxisSize: MainAxisSize.max, // Add this
mainAxisAlignment: MainAxisAlignment.center, // Changed from center to start
crossAxisAlignment: CrossAxisAlignment.center,
children: List.generate(widget.alpahbetsAvailable.length, (i) {
final isActive = (i == _activeIndex);
return GestureDetector(
onTap: () {
setState(() => _activeIndex = i);
_scrollToLetter(widget.alpahbetsAvailable[i]);
},
child: TweenAnimationBuilder<double>(
tween: Tween(begin: 1.0, end: isActive ? 1.8 : 1.0),
duration: Duration(milliseconds: 120),
curve: Curves.easeOut,
builder: (_, scale, child) {
return Transform.scale(
scale: scale,
child: Opacity(
opacity: isActive ? 1.0 : 0.5,
child: widget.alpahbetsAvailable[i].toUpperCase().toText14(color: !isActive ? AppColors.greyTextColor : AppColors.primaryRedColor, isEnglishOnly: true),
),
);
},
),
),
),
],
),
);
);
}),
),
),
],
),
);
// );
}
@ -205,35 +190,35 @@ class _AlphabetScrollPageState extends State<AlphabeticScroll> {
key: _offsetKeys[letter],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
List.generate(items.length,(itemIndex)=>
AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabOrderByTest(
appState: getIt<AppState>(),
onTap: () {
if (items[itemIndex].model != null) {
widget.rangeViewModel.flush();
widget.labViewModel.getPatientLabResult(items[itemIndex].model!, items[itemIndex].description!,
(widget.appState.isArabic() ? items[itemIndex].testDescriptionAr! : items[itemIndex].testDescriptionEn!),"");
}
},
tests: items[itemIndex],
index: itemIndex,
isExpanded: true)),
),
))
children: List.generate(
items.length,
(itemIndex) => AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabOrderByTest(
appState: getIt<AppState>(),
onTap: () {
if (items[itemIndex].model != null) {
widget.rangeViewModel.flush();
widget.labViewModel.getPatientLabResult(items[itemIndex].model!, items[itemIndex].description!,
(widget.appState.isArabic() ? items[itemIndex].testDescriptionAr! : items[itemIndex].testDescriptionEn!), "");
}
},
tests: items[itemIndex],
index: itemIndex,
isExpanded: true)),
),
))
// ...items.indexed((item) =>
//
//
//
// )
),
),
);
},
);

@ -26,64 +26,65 @@ class LabOrderByTest extends StatelessWidget {
@override
build(BuildContext context) {
return AnimatedContainer(
key:key,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: Container(
key: ValueKey<int>(index),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'${tests!.description}'.toText16(isBold: true, isEnglishOnly: true),
SizedBox(height: 4.h),
(appState.isArabic() ? tests!.testDescriptionAr : tests!.testDescriptionEn)!.toText12(isBold: true),
SizedBox(height: 8.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppCustomChipWidget(
richText: Row(
children: [
"${LocaleKeys.lastTested.tr(context: context)}: ".toText12(isBold: true),
Directionality(
textDirection: ui.TextDirection.ltr,child: DateUtil.formatDateToDate(DateUtil.convertStringToDate(tests!.createdOn), false).toText12(isBold: true, isEnglishOnly: true))
],
),
backgroundColor: AppColors.greyLightColor,
textColor: AppColors.textColor,
key: key,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: Container(
key: ValueKey<int>(index),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'${tests!.description}'.toText16(isBold: true, isEnglishOnly: true),
SizedBox(height: 4.h),
(appState.isArabic() ? tests!.testDescriptionAr : tests!.testDescriptionEn)!.toText12(isBold: true),
SizedBox(height: 8.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppCustomChipWidget(
richText: Row(
children: [
"${LocaleKeys.lastTested.tr(context: context)}: ".toText12(isBold: true),
Directionality(
textDirection: ui.TextDirection.ltr, child: DateUtil.formatDateToDate(DateUtil.convertStringToDate(tests!.createdOn), false).toText12(isBold: true, isEnglishOnly: true))
],
),
],
),
SizedBox(height: 16.h),
Row(
children: [
Expanded(child: Container()),
Expanded(
child: CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewResults.tr(context: context),
onPressed: () {
onTap();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
backgroundColor: AppColors.greyLightColor,
textColor: AppColors.textColor,
),
],
),
SizedBox(height: 16.h),
Row(
children: [
Expanded(child: Container()),
Expanded(
child: CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewResults.tr(context: context),
onPressed: () {
onTap();
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: Colors.transparent,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
));
),
],
),
],
),
),
);
}
}

File diff suppressed because one or more lines are too long

@ -122,8 +122,8 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
children: [
SizedBox(height: 16.h),
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.secondaryLightRedColor,
initialIndex: 0,
tabs: [
CustomTabBarModel(null, LocaleKeys.visitsOrders.tr(context: context)),
@ -149,13 +149,11 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
myInvoicesViewModel.filterInvoices(InvoiceFilterType.all);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all
? AppColors.primaryRedColor
: AppColors.textColor.withValues(alpha: 0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontSize: 12.f,
fontWeight: FontWeight.w600,
borderRadius: 10,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
@ -166,15 +164,12 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
if (myInvoicesVM.getOriginalInvoicesList().isEmpty) return;
_showHospitalFilterBottomSheet(context);
},
backgroundColor:
myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital
? AppColors.primaryRedColor
: AppColors.textColor.withValues(alpha: 0.2),
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontSize: 12.f,
fontWeight: FontWeight.w600,
borderRadius: 10,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
@ -185,15 +180,12 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
if (myInvoicesVM.getOriginalInvoicesList().isEmpty) return;
_showClinicFilterBottomSheet(context);
},
backgroundColor:
myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic
? AppColors.primaryRedColor
: AppColors.textColor.withValues(alpha: 0.2),
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontSize: 12.f,
fontWeight: FontWeight.w600,
borderRadius: 10,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
@ -204,15 +196,12 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
if (myInvoicesVM.getOriginalInvoicesList().isEmpty) return;
_showDoctorFilterBottomSheet(context);
},
backgroundColor:
myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor
? AppColors.primaryRedColor
: AppColors.textColor.withValues(alpha: 0.2),
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontSize: 12.f,
fontWeight: FontWeight.w600,
borderRadius: 10,
borderRadius: 10.r,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
@ -245,16 +234,14 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
onTap: () async {
if (Utils.isVidaPlusProject(myInvoicesVM.allInvoicesList[index].projectId ?? 0)) {
LoaderBottomSheet.showLoader(
loadingText: LocaleKeys.sendingEmailPleaseWait.tr(context: context));
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.sendingEmailPleaseWait.tr(context: context));
await myInvoicesViewModel.sendInvoiceEmail(
appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
projectID: myInvoicesVM.allInvoicesList[index].projectId!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(context,
child: Utils.getSuccessWidget(
loadingText: LocaleKeys.emailSentSuccessfullyMessage.tr(context: context)),
child: Utils.getSuccessWidget(loadingText: LocaleKeys.emailSentSuccessfullyMessage.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
@ -289,8 +276,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
if (myInvoicesViewModel.downloadInvoicePDFBase64!.isNotEmpty) {
String path = await Utils.createFileFromString(
myInvoicesViewModel.downloadInvoicePDFBase64!, "pdf");
String path = await Utils.createFileFromString(myInvoicesViewModel.downloadInvoicePDFBase64!, "pdf");
try {
OpenFilex.open(path);
} catch (ex) {
@ -377,8 +363,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
if (myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!.isNotEmpty) {
String path = await Utils.createFileFromString(
myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!, "pdf");
String path = await Utils.createFileFromString(myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!, "pdf");
try {
OpenFilex.open(path);
} catch (ex) {

@ -111,7 +111,7 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
onPressed: () => goToHomePage(),
width: 86.w,
height: 56.h,
backgroundColor: Color(0xffFEE9EA),
backgroundColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
borderColor: Colors.transparent,
).paddingOnly(left: 24.w)

@ -164,7 +164,7 @@ class _AnimatedScreenState extends State<AnimatedScreen> with TickerProviderStat
width: 400.h,
height: 653.h,
decoration: BoxDecoration(
color: Color(0xffED1C2B),
color: AppColors.primaryRedColor,
borderRadius: BorderRadius.circular(330.h),
),
),
@ -273,7 +273,7 @@ class _MoveObjectDemoState extends State<MoveObjectDemo> with SingleTickerProvid
width: 200,
height: 375,
decoration: BoxDecoration(
color: const Color(0xffED1C2B),
color: AppColors.primaryRedColor,
borderRadius: BorderRadius.circular(330),
),
),
@ -367,7 +367,7 @@ class _MoveOnClickDemoState extends State<MoveOnClickDemo> with TickerProviderSt
width: 100,
height: 150,
decoration: BoxDecoration(
color: const Color(0xffED1C2B),
color: AppColors.primaryRedColor,
borderRadius: BorderRadius.circular(330),
),
),

@ -159,9 +159,9 @@ class _RateAppointmentClinicState extends State<RateAppointmentClinic> {
Expanded(
child: CustomButton(
text: LocaleKeys.back.tr(context: context),
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
onPressed: () {
appointmentRatingViewModel!.setTitle(LocaleKeys.rateDoctor.tr(context: context));
appointmentRatingViewModel!.setSubTitle(LocaleKeys.howWasYourLastVisitWithDoctor.tr(context: context));

@ -181,9 +181,9 @@ class _RateAppointmentDoctorState extends State<RateAppointmentDoctor> {
Expanded(
child: CustomButton(
text: LocaleKeys.later.tr(context: context),
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
onPressed: () {
Navigator.pop(context);
},

@ -66,8 +66,8 @@ class _ActivityDetailsState extends State<ActivityDetails> {
children: [
Expanded(
child: CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.secondaryLightRedColor,
tabs: [
CustomTabBarModel(null, "D"),
CustomTabBarModel(null, "W"),

@ -56,8 +56,8 @@ class _HealthDashboardState extends State<HealthDashboard> with SingleTickerProv
children: [
SizedBox(height: 96.h),
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.secondaryLightRedColor,
tabs: [
CustomTabBarModel(null, "Overview".needTranslation),
CustomTabBarModel(null, "Details".needTranslation),

@ -257,9 +257,9 @@ class AncillaryOrderCard extends StatelessWidget {
onViewDetails!();
}
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w600,
borderRadius: 10.r,

@ -252,9 +252,9 @@ class AncillaryOrderCard extends StatelessWidget {
onViewDetails!();
}
},
backgroundColor: Color(0xffFEE9EA),
borderColor: Color(0xffFEE9EA),
textColor: Color(0xffED1C2B),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
isBold: true,
borderRadius: 10.r,

@ -54,7 +54,7 @@ class AppColors {
/// The original, non-themed brand red (or its dark-mode variant). Always
/// stable regardless of any active occasion theme — intended for opacity
/// derived usages (e.g. `AppColors.primaryRedColorBase.withOpacity(0.1)`).
static Color get primaryRedColorBase => isDarkMode ? const Color(0xFFED1C2B) : const Color(0xFFED1C2B);
static Color get primaryRedColorBase => isDarkMode ? dark.primaryRedColor : const Color(0xFFED1C2B);
/// Semantic color for critical/negative actions (delete/deactivate account,
/// cancel appointment, clear/reset, emergency, etc.). Same light/dark

@ -10,8 +10,8 @@ class CustomButton extends StatefulWidget {
final String text;
final String? icon;
final VoidCallback? onPressed;
final Color backgroundColor;
final Color borderColor;
final Color? backgroundColor;
final Color? borderColor;
final Color textColor;
final double? borderRadius;
final double borderWidth;
@ -33,8 +33,8 @@ class CustomButton extends StatefulWidget {
super.key,
required this.text,
required this.onPressed,
this.backgroundColor = const Color(0xFFED1C2B),
this.borderColor = const Color(0xFFED1C2B),
this.backgroundColor,
this.borderColor,
this.textColor = Colors.white,
this.borderRadius,
this.borderWidth = 2,
@ -93,6 +93,8 @@ class _CustomButtonState extends State<CustomButton> with SingleTickerProviderSt
final iconS = widget.iconSize ?? (24.h);
final fontS = widget.fontSize ?? (16.f);
final isButtonDisabled = widget.isDisabled || widget.onPressed == null;
final resolvedBackgroundColor = widget.backgroundColor ?? AppColors.primaryRedColor;
final resolvedBorderColor = widget.borderColor ?? AppColors.primaryRedColor;
return Semantics(
button: true,
@ -134,10 +136,10 @@ class _CustomButtonState extends State<CustomButton> with SingleTickerProviderSt
width: widget.width,
padding: widget.padding,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: isButtonDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : widget.backgroundColor,
color: isButtonDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : resolvedBackgroundColor,
borderRadius: radius,
customBorder: BorderRadius.circular(radius),
side: widget.borderSide ?? BorderSide(width: widget.borderWidth.h, color: isButtonDisabled ? Colors.transparent : widget.borderColor)),
side: widget.borderSide ?? BorderSide(width: widget.borderWidth.h, color: isButtonDisabled ? Colors.transparent : resolvedBorderColor)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,

Loading…
Cancel
Save