diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 7c59175..905c02d 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -826,6 +826,7 @@ "noOfInvites": "عدد الدعوات", "noSpecialServicesAvailable": "لا توجد خدمات خاصة متاحة للمنطقة المحددة.", "customService": "الخدمة المخصصة", + "lookingToAddCustomService": "هل تريد إضافة خدمة مخصصة؟", "selectServiceDetails": "اختر تفاصيل الخدمة", "addServiceDetails": "أضف تفاصيل الخدمة", "companyNameMandatory": "اسم الشركة إلزامي", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 6cfa3b8..cf5d3ec 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -829,6 +829,7 @@ "noOfInvites": "No of invites", "noSpecialServicesAvailable": "There are no special services available for the selected region.", "customService": "Custom Service", + "lookingToAddCustomService": "Looking to add a custom service?", "selectServiceDetails": "Select service details", "addServiceDetails": "Add service details", "connectionProblem": "Connection Problem", diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 3f1c53c..87615d4 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -90,7 +90,6 @@ class AppRoutes { static const String appointment = "/appointment"; static const String appointmentDetailList = "/appointmentDetailList"; static const String updateAppointmentPage = "/updateAppointmentPage"; - static const String addServiceInAppointment = "/addServiceInAppointment"; static const String mergeAppointments = "/mergeAppointments"; //Services diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 6e31013..6744edf 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -830,6 +830,7 @@ class CodegenLoader extends AssetLoader { "noOfInvites": "عدد الدعوات", "noSpecialServicesAvailable": "لا توجد خدمات خاصة متاحة للمنطقة المحددة.", "customService": "الخدمة المخصصة", + "lookingToAddCustomService": "هل تريد إضافة خدمة مخصصة؟", "selectServiceDetails": "اختر تفاصيل الخدمة", "addServiceDetails": "أضف تفاصيل الخدمة", "companyNameMandatory": "اسم الشركة إلزامي", @@ -1768,6 +1769,7 @@ class CodegenLoader extends AssetLoader { "noOfInvites": "No of invites", "noSpecialServicesAvailable": "There are no special services available for the selected region.", "customService": "Custom Service", + "lookingToAddCustomService": "Looking to add a custom service?", "selectServiceDetails": "Select service details", "addServiceDetails": "Add service details", "connectionProblem": "Connection Problem", diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 0e92ade..e05b415 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -807,6 +807,7 @@ abstract class LocaleKeys { static const noOfInvites = 'noOfInvites'; static const noSpecialServicesAvailable = 'noSpecialServicesAvailable'; static const customService = 'customService'; + static const lookingToAddCustomService = 'lookingToAddCustomService'; static const selectServiceDetails = 'selectServiceDetails'; static const addServiceDetails = 'addServiceDetails'; static const companyNameMandatory = 'companyNameMandatory'; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index d9d5f97..ba67bf4 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -24,10 +24,10 @@ import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/widgets/loading_dialog.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_toast.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher_string.dart'; -import 'package:toastification/toastification.dart'; class Utils { static bool _isLoadingVisible = false; @@ -44,18 +44,20 @@ class Utils { return 'https://ms.hmg.com/ad/${adDetails.id}?app=$appParam'; } - static void showToast(String message) { - toastification.show( - type: ToastificationType.info, - style: ToastificationStyle.minimal, - title: Text( - message, - maxLines: 5, - overflow: TextOverflow.ellipsis, - ), - autoCloseDuration: const Duration(seconds: 3), - alignment: Alignment.topCenter, - showProgressBar: false, + // Neutral styling for now -- existing call sites across the app were never written + // with a success/error distinction in mind (confirmed: plenty of messageStatus == 1 + // success branches call this same function as the error branches), so defaulting to + // red/green here would mislabel most of them until those ~340 call sites are reviewed + // and updated individually to pass isSuccess explicitly. + static void showToast(String message, {bool isSuccess = false, VoidCallback? onComplete}) { + AppToast.show( + message, + seconds: onComplete != null ? AppToast.actionSeconds : AppToast.plainSeconds, + showIcon: onComplete != null, + showCountdownText: true, + bgColor: isSuccess ? AppToast.successBgColor : null, + textColor: isSuccess ? AppToast.successTextColor : null, + onComplete: onComplete, ); } @@ -114,7 +116,11 @@ class Utils { return ""; } - return ("${timeOfDay.hour.toString().length == 1 ? "0" : ""}${timeOfDay.hour}:${timeOfDay.minute.toString().length == 1 ? "0" : ""}${timeOfDay.minute}").toString(); + return ("${timeOfDay.hour + .toString() + .length == 1 ? "0" : ""}${timeOfDay.hour}:${timeOfDay.minute + .toString() + .length == 1 ? "0" : ""}${timeOfDay.minute}").toString(); } static dynamic getNotNullValue(List list, int index) { @@ -689,7 +695,7 @@ class Utils { border: Border.all( width: w, // color: color // <--- border width here - ), + ), borderRadius: BorderRadius.circular(radius), ); } @@ -712,7 +718,7 @@ class Utils { border: Border.all( width: 1, // color: color // <--- border width here - ), + ), borderRadius: BorderRadius.circular(radius), ); } @@ -730,7 +736,8 @@ class Utils { } static String getAdsPaymentBrowserForm({required int paymentId, required int adId}) { - return '
'; + return '
'; } // BOTTOM SHEETS @@ -791,18 +798,18 @@ class Utils { switch (inviteTypeEnum) { case InviteTypeEnum.whatsapp: - // WhatsApp requires a phone number and message, format like this: + // WhatsApp requires a phone number and message, format like this: url = 'https://wa.me/?text=${Uri.encodeComponent(message)}'; break; case InviteTypeEnum.sms: - // SMS: 'sms:?body=' - // You can add a phone number, or keep it empty to allow the user to input one. + // SMS: 'sms:?body=' + // You can add a phone number, or keep it empty to allow the user to input one. url = 'sms:?body=${Uri.encodeComponent(message)}'; break; case InviteTypeEnum.email: - // Email: 'mailto:?subject=&body=' + // Email: 'mailto:?subject=&body=' url = 'mailto:?subject=MowaterInvitation&body=${Uri.encodeComponent(message)}'; break; } diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart index ba36db2..08be755 100644 --- a/lib/view_models/service_view_model.dart +++ b/lib/view_models/service_view_model.dart @@ -365,9 +365,11 @@ class ServiceVM extends BaseVM { } resetCustomServiceForm() { + customServiceEnabledStatus = false; customServiceTitle = ""; customServicePrice = ""; customerServiceTax = "15"; + notifyListeners(); } String customServiceTitleError = ""; diff --git a/lib/view_models/user_view_model.dart b/lib/view_models/user_view_model.dart index 874ed5e..46c88c0 100644 --- a/lib/view_models/user_view_model.dart +++ b/lib/view_models/user_view_model.dart @@ -615,14 +615,28 @@ class UserVM extends BaseVM { } } + // getAllCountries() previously let a failed call (e.g. SocketException/ClientException + // from api_client.dart) propagate as an unhandled exception all the way to the UI -- + // confirmed on a real device: no try/catch anywhere in this chain, so the user just saw + // a crash with no toast. Catch and surface it here instead, and fall back to an empty + // Country() so existing callers (which already null-check/iterate ".data") keep working. Future getAllCountries() async { - return await userRepo.getAllCountries(); + try { + return await userRepo.getAllCountries(); + } catch (e) { + Utils.handleException(e, null); + return Country(); + } } Future getAllCountriesForUser() async { userCountries = null; userCities = null; - userCountries = await userRepo.getAllCountries(); + try { + userCountries = await userRepo.getAllCountries(); + } catch (e) { + Utils.handleException(e, null); + } notifyListeners(); }