Toast fixed

wala_plus_with_dialog_removal
FaizHashmi 2 weeks ago
parent a0c5ac7e6c
commit b25b398695

@ -7,7 +7,6 @@ import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/toast/app_toast.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_model.dart';
@ -105,24 +104,18 @@ class MarathonApiClient {
}
Future<QuestionModel> getNextQuestion({required String? questionId, required String marathonId}) async {
Map<String, String?> jsonObject = <String, String?>{
"previousQuestionId": questionId,
"marathonId": marathonId,
};
Map<String, String?> jsonObject = <String, String?>{"previousQuestionId": questionId, "marathonId": marathonId};
return await ApiClient().postJsonForObject(
(json) {
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
if (marathonModel.statusCode == 404 || marathonModel.statusCode == 208 || marathonModel.statusCode == 204 || marathonModel.statusCode == 500) {
AppToast.show(
Utils.showToast(
marathonModel.message!,
seconds: AppToast.actionSeconds,
onComplete: () {
AppRoutes.navigatorKey.currentContext!.read<MarathonProvider>().resetValues();
Navigator.of(
AppRoutes.navigatorKey.currentContext!,
).popUntil(ModalRoute.withName(AppRoutes.dashboard));
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.dashboard));
},
);
}
@ -215,99 +208,99 @@ class MarathonApiClient {
return null;
}
// late HubConnection hubConnection;
// Future<void> buildHubConnection(BuildContext context, String prizeId) async {
// HttpConnectionOptions httpOptions = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
// hubConnection = HubConnectionBuilder()
// .withUrl(
// ApiConsts.marathonHubConnectionUrl + "?employeeNumber=${AppState().memberInformationList!.eMPLOYEENUMBER ?? ""}&employeeName=${AppState().memberInformationList!.eMPLOYEENAME ?? ""}",
// options: httpOptions,
// )
// .withAutomaticReconnect(
// retryDelays: <int>[2000, 5000, 10000, 20000],
// )
// .configureLogging(
// Logger("Logging"),
// )
// .build();
// hubConnection.onclose(
// ({Exception? error}) {
// logger.i("onclose");
// },
// );
// hubConnection.onreconnecting(
// ({Exception? error}) {
// logger.i("onreconnecting");
// },
// );
// hubConnection.onreconnected(
// ({String? connectionId}) {
// logger.i("onreconnected");
// },
// );
// if (hubConnection.state != HubConnectionState.Connected) {
// await hubConnection.start();
// logger.i("Started HubConnection");
//
// await hubConnection.invoke(
// "AddParticipant",
// args: <Object>[
// <String, dynamic>{
// "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "",
// "employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "",
// "marathonId": AppState().getMarathonProjectId,
// "prizeId": "8577B2E8-5DD7-43F0-10DD-08DACB0AC064",
// }
// ],
// ).catchError((e) {
// logger.i("Error in AddParticipant: $e");
// });
//
// context.read<MarathonProvider>().addItemToList(ApiConsts.dummyQuestion);
//
// await hubConnection.invoke(
// "SendQuestionToParticipant",
// args: <Object>[
// <String, dynamic>{
// "marathonId": "${AppState().getMarathonProjectId}",
// }
// ],
// ).catchError((e) {
// Utils.confirmDialog(context, e.toString());
// logger.i("Error in SendQuestionToParticipant: $e");
// });
//
// try {
// hubConnection.on("OnSendQuestionToParticipant", (List<Object?>? arguments) {
// onSendQuestionToParticipant(arguments, context);
// });
// } catch (e, s) {
// logger.i("Error in OnSendQuestionToParticipant");
// }
//
// try {
// hubConnection.on("OnParticipantJoin", (List<Object?>? arguments) {
// onParticipantJoin(arguments, context);
// });
// } catch (e, s) {
// logger.i("Error in OnParticipantJoin");
// }
// }
// }
//
// Future<void> onSendQuestionToParticipant(List<Object?>? arguments, BuildContext context) async {
// logger.i("onSendQuestionToParticipant arguments: $arguments");
//
// if (arguments != null) {
// Map<dynamic, dynamic> data = arguments.first! as Map<dynamic, dynamic>;
// var json = data["data"];
// QuestionModel newQuestion = QuestionModel.fromJson(json);
// AppRoutes.navigatorKey.currentContext!.read<MarathonProvider>().onNewQuestionReceived(newQuestion);
// }
// }
//
// Future<void> onParticipantJoin(List<Object?>? arguments, BuildContext context) async {
// logger.i("OnParticipantJoin arguments: $arguments");
// context.watch<MarathonProvider>().totalMarathoners++;
// }
// late HubConnection hubConnection;
// Future<void> buildHubConnection(BuildContext context, String prizeId) async {
// HttpConnectionOptions httpOptions = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
// hubConnection = HubConnectionBuilder()
// .withUrl(
// ApiConsts.marathonHubConnectionUrl + "?employeeNumber=${AppState().memberInformationList!.eMPLOYEENUMBER ?? ""}&employeeName=${AppState().memberInformationList!.eMPLOYEENAME ?? ""}",
// options: httpOptions,
// )
// .withAutomaticReconnect(
// retryDelays: <int>[2000, 5000, 10000, 20000],
// )
// .configureLogging(
// Logger("Logging"),
// )
// .build();
// hubConnection.onclose(
// ({Exception? error}) {
// logger.i("onclose");
// },
// );
// hubConnection.onreconnecting(
// ({Exception? error}) {
// logger.i("onreconnecting");
// },
// );
// hubConnection.onreconnected(
// ({String? connectionId}) {
// logger.i("onreconnected");
// },
// );
// if (hubConnection.state != HubConnectionState.Connected) {
// await hubConnection.start();
// logger.i("Started HubConnection");
//
// await hubConnection.invoke(
// "AddParticipant",
// args: <Object>[
// <String, dynamic>{
// "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "",
// "employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "",
// "marathonId": AppState().getMarathonProjectId,
// "prizeId": "8577B2E8-5DD7-43F0-10DD-08DACB0AC064",
// }
// ],
// ).catchError((e) {
// logger.i("Error in AddParticipant: $e");
// });
//
// context.read<MarathonProvider>().addItemToList(ApiConsts.dummyQuestion);
//
// await hubConnection.invoke(
// "SendQuestionToParticipant",
// args: <Object>[
// <String, dynamic>{
// "marathonId": "${AppState().getMarathonProjectId}",
// }
// ],
// ).catchError((e) {
// Utils.confirmDialog(context, e.toString());
// logger.i("Error in SendQuestionToParticipant: $e");
// });
//
// try {
// hubConnection.on("OnSendQuestionToParticipant", (List<Object?>? arguments) {
// onSendQuestionToParticipant(arguments, context);
// });
// } catch (e, s) {
// logger.i("Error in OnSendQuestionToParticipant");
// }
//
// try {
// hubConnection.on("OnParticipantJoin", (List<Object?>? arguments) {
// onParticipantJoin(arguments, context);
// });
// } catch (e, s) {
// logger.i("Error in OnParticipantJoin");
// }
// }
// }
//
// Future<void> onSendQuestionToParticipant(List<Object?>? arguments, BuildContext context) async {
// logger.i("onSendQuestionToParticipant arguments: $arguments");
//
// if (arguments != null) {
// Map<dynamic, dynamic> data = arguments.first! as Map<dynamic, dynamic>;
// var json = data["data"];
// QuestionModel newQuestion = QuestionModel.fromJson(json);
// AppRoutes.navigatorKey.currentContext!.read<MarathonProvider>().onNewQuestionReceived(newQuestion);
// }
// }
//
// Future<void> onParticipantJoin(List<Object?>? arguments, BuildContext context) async {
// logger.i("OnParticipantJoin arguments: $arguments");
// context.watch<MarathonProvider>().totalMarathoners++;
// }
}

@ -38,14 +38,18 @@ class Utils {
// Callers showing a value straight from an API response should pass isSuccess: response's
// MessageStatus == 1; everywhere else (validation messages, caught errors) just defaults to
// red, and the handful of hardcoded success confirmations pass isSuccess: true explicitly.
static void showToast(String message, {bool longDuration = true, bool isSuccess = false}) {
// onComplete makes this an action-toast (longer actionSeconds duration + icon shown) instead
// of a plain info toast - this is the single calling point, every caller should go through
// here instead of calling AppToast.show directly, so the color/duration/icon rules in one place.
static void showToast(String message, {bool longDuration = true, bool isSuccess = false, VoidCallback? onComplete}) {
AppToast.show(
message,
seconds: AppToast.plainSeconds,
showIcon: false,
seconds: onComplete != null ? AppToast.actionSeconds : AppToast.plainSeconds,
showIcon: onComplete != null,
showCountdownText: true,
bgColor: isSuccess ? const Color(0xFFECFDF5) : const Color(0xFFF1CECE),
textColor: isSuccess ? const Color(0xFF059669) : const Color(0xFFC53030),
bgColor: isSuccess ? AppToast.successBgColor : AppToast.errorBgColor,
textColor: isSuccess ? AppToast.successTextColor : AppToast.errorTextColor,
onComplete: onComplete,
);
}
@ -167,9 +171,8 @@ class Utils {
onErrorMessage(errorMessage);
} else {
if (!AppState().isAuthenticated) {
AppToast.show(
showToast(
errorMessage,
seconds: AppToast.actionSeconds,
onComplete: () {
Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route<dynamic> route) => false);
},
@ -191,9 +194,11 @@ class Utils {
static void confirmDialog(cxt, String message, {VoidCallback? onTap}) {
// No onTap means there's nothing to confirm - it's a plain notice, so a self-dismissing
// toast replaces the old "OK just closes" dialog instead of requiring a tap.
// toast replaces the old "OK just closes" dialog instead of requiring a tap. Every current
// caller of this path passes an error/warning message (catch blocks, location/fake-location
// warnings, session errors) - never success - so red is correct here.
if (onTap == null) {
AppToast.show(message);
showToast(message);
} else {
showDialog(context: cxt, builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap));
}

@ -27,7 +27,6 @@ import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
import 'package:mohem_flutter_app/widgets/toast/app_toast.dart';
/// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool
// ignore: prefer_mixin
@ -190,9 +189,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
notifyListeners();
Utils.handleException(ex, context, (err) {
Utils.hideLoading(context);
AppToast.show(
Utils.showToast(
err,
seconds: AppToast.actionSeconds,
onComplete: () {
Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false);
},

@ -14,7 +14,6 @@ import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/image_picker.dart';
import 'package:mohem_flutter_app/widgets/toast/app_toast.dart';
import 'package:provider/provider.dart';
class EtqanOvrCreateRequest extends StatefulWidget {
@ -88,11 +87,11 @@ class _EtqanOvrCreateRequestState extends State<EtqanOvrCreateRequest> {
DefaultButton(LocaleKeys.submit.tr(), () async {
provider.setDescription(_descriptionController.text);
if (provider.selectedProject == null) {
AppToast.show(LocaleKeys.pleaseSelectProject.tr());
Utils.showToast(LocaleKeys.pleaseSelectProject.tr());
return;
}
if (!provider.isDescriptionValid()) {
AppToast.show(LocaleKeys.pleaseEnterDescription.tr());
Utils.showToast(LocaleKeys.pleaseEnterDescription.tr());
return;
}
Map<String, dynamic>? ticketInfo = await provider.submitRequest(context);
@ -101,9 +100,9 @@ class _EtqanOvrCreateRequestState extends State<EtqanOvrCreateRequest> {
String ticketId = ticketInfo['id'] ?? '';
// String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId';
String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber';
AppToast.show(
Utils.showToast(
successMessage,
seconds: AppToast.actionSeconds,
isSuccess: true,
onComplete: () {
Navigator.pop(context);
Navigator.pop(context);

@ -22,7 +22,6 @@ import 'package:mohem_flutter_app/widgets/bottom_sheets/confirm_bottom_sheet.dar
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/info_chip_widget.dart';
import 'package:mohem_flutter_app/widgets/location/Location.dart' as location;
import 'package:mohem_flutter_app/widgets/toast/app_toast.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shimmer/shimmer.dart';
@ -429,7 +428,7 @@ class _DashboardScreenForDependetState extends State<DashboardScreenForDependet>
if (!hasPermission) {
bool granted = await _requestLocationPermission();
if (!granted) {
AppToast.show(LocaleKeys.locationPermissionRequiredForNearestOffers.tr());
Utils.showToast(LocaleKeys.locationPermissionRequiredForNearestOffers.tr());
return false;
}
}

@ -20,7 +20,6 @@ import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/dialogs/otp_dialog.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/confirm_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/toast/app_toast.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
@ -429,7 +428,7 @@ class _LoginScreenState extends State<LoginScreen> {
},
);
} else {
AppToast.show(msg);
Utils.showToast(msg);
}
});
}
@ -596,16 +595,15 @@ class _LoginScreenState extends State<LoginScreen> {
}
void _navigateToMazayaAccessRevoked([String? depName, String? message]) async {
await Utils.removeStringFromPrefs("P_DEP_IS_LOGGED_IN");
await Utils.removeStringFromPrefs("P_DEP_NATIONAL_ID");
await Utils.removeStringFromPrefs("P_DEP_BIRTH_DATE");
await Utils.removeStringFromPrefs("P_DEP_TOKEN_ID");
await Utils.removeStringFromPrefs("P_DEP_LOGIN_TOKEN_ID");
await Utils.removeStringFromPrefs("P_DEP_AUTHENTICATION_TOKEN_ID");
await Utils.removeStringFromPrefs("P_DEP_MOBILE_NUMBER");
await Utils.removeStringFromPrefs("P_DEPENDENT_NAME");
await Utils.removeStringFromPrefs("P_DEP_LOGIN_TYPE");
await Utils.removeStringFromPrefs("P_DEP_IS_LOGGED_IN");
await Utils.removeStringFromPrefs("P_DEP_NATIONAL_ID");
await Utils.removeStringFromPrefs("P_DEP_BIRTH_DATE");
await Utils.removeStringFromPrefs("P_DEP_TOKEN_ID");
await Utils.removeStringFromPrefs("P_DEP_LOGIN_TOKEN_ID");
await Utils.removeStringFromPrefs("P_DEP_AUTHENTICATION_TOKEN_ID");
await Utils.removeStringFromPrefs("P_DEP_MOBILE_NUMBER");
await Utils.removeStringFromPrefs("P_DEPENDENT_NAME");
await Utils.removeStringFromPrefs("P_DEP_LOGIN_TYPE");
ApiConsts.selectedMemberType = MemberType.employee;
ApiConsts.ISDependetLogin = false;
AppState().setDependentName = null;

@ -17,7 +17,6 @@ import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart
import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart';
import 'package:mohem_flutter_app/ui/screens/mowadhafhi/view_transaction_attachment.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/toast/app_toast.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
@ -283,7 +282,7 @@ class _RequestDetailsState extends State<MowadhafhiRequestDetails> {
Utils.showToast("Cannot open file.");
}
} else {
AppToast.show("You need to give storage permission to view files.");
Utils.showToast("You need to give storage permission to view files.");
}
});
}

@ -19,7 +19,6 @@ import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/dialogs/success_dialog.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/confirm_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/dialogs/dialogs.dart';
import 'package:mohem_flutter_app/widgets/toast/app_toast.dart';
import 'package:mohem_flutter_app/widgets/location/Location.dart' as location;
import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart';
import 'package:mohem_flutter_app/widgets/qr_scanner_dialog.dart';
@ -84,7 +83,7 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
if (has) {
getHuaweiCurrentLocation(attendanceType);
} else {
AppToast.show(LocaleKeys.locationPermissionRequiredForAttendance.tr());
Utils.showToast(LocaleKeys.locationPermissionRequiredForAttendance.tr());
}
}
});
@ -396,7 +395,7 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId, isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng);
if (g?.messageStatus != 1) {
Utils.hideLoading(context);
AppToast.show(g?.errorEndUserMessage ?? "Unexpected error occurred");
Utils.showToast(g?.errorEndUserMessage ?? "Unexpected error occurred");
} else {
bool status = await model.fetchAttendanceTracking(context);
if (Platform.isIOS) await Future.delayed(const Duration(seconds: 3));
@ -420,7 +419,7 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? "", isGpsRequired: isNfcLocationEnabled, lat: lat, long: lng);
if (g?.messageStatus != 1) {
Utils.hideLoading(context);
AppToast.show(g?.errorEndUserMessage ?? "Unexpected error occurred");
Utils.showToast(g?.errorEndUserMessage ?? "Unexpected error occurred");
} else {
bool status = await model.fetchAttendanceTracking(context);
Utils.hideLoading(context);
@ -482,7 +481,7 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
Utils.hideLoading(context);
await closeWifiRequest();
if (g?.messageStatus == 2) {
AppToast.show(g?.errorEndUserMessage ?? "");
Utils.showToast(g?.errorEndUserMessage ?? "");
} else {
showMDialog(
context,
@ -526,7 +525,7 @@ class _MarkAttendanceWidgetState extends State<MarkAttendanceWidget> {
bool status = await model.fetchAttendanceTracking(context);
Utils.hideLoading(context);
if (g?.messageStatus == 2) {
AppToast.show(g?.errorEndUserMessage ?? "");
Utils.showToast(g?.errorEndUserMessage ?? "");
} else {
showMDialog(
context,

@ -18,6 +18,15 @@ class AppToast {
// change this single value to retune it everywhere that uses it.
static const int plainSeconds = 3;
// Shared success/error colors - same combo as dependent_details_screen.dart's
// "Active"/"Access Off" badges. Any direct AppToast.show(...) call (not going through
// Utils.showToast) must pass these explicitly, otherwise it silently falls back to the
// plain dark/white style below regardless of whether it's reporting success or failure.
static const Color errorBgColor = Color(0xFFF1CECE);
static const Color errorTextColor = Color(0xFFC53030);
static const Color successBgColor = Color(0xFFECFDF5);
static const Color successTextColor = Color(0xFF059669);
static void show(String message, {int seconds = 5, VoidCallback? onComplete, bool showIcon = true, bool showCountdownText = true, Color? bgColor, Color? textColor}) {
OverlayState? overlay = AppRoutes.navigatorKey.currentState?.overlay;
if (overlay == null) return;

Loading…
Cancel
Save