diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 1e66d45..ff26054 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -14,11 +14,12 @@ typedef FactoryConstructor = U Function(dynamic); class APIError { int? errorCode; + int? errorType; String? errorMessage; - APIError(this.errorCode, this.errorMessage); + APIError(this.errorCode, this.errorMessage, this.errorType); - Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage}; + Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType,}; @override String toString() { @@ -33,14 +34,14 @@ APIException _throwAPIException(Response response) { if (response.body != null && response.body.isNotEmpty) { var jsonError = jsonDecode(response.body); print(jsonError); - apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']); + apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType']); } return APIException(APIException.BAD_REQUEST, error: apiError); case 400: APIError? apiError; if (response.body != null && response.body.isNotEmpty) { var jsonError = jsonDecode(response.body); - apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']); + apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType']); } return APIException(APIException.BAD_REQUEST, error: apiError); case 401: @@ -90,7 +91,7 @@ class ApiClient { return factoryConstructor(jsonData); } else { APIError? apiError; - apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage']); + apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType']); throw APIException(APIException.BAD_REQUEST, error: apiError); } // } catch (ex) { diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 5060195..7d175b5 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -64,7 +64,7 @@ class AppState { String? get getMarathonProjectId => _projectID; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.0, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 3.8, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 572c09e..bac8616 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -98,33 +98,37 @@ class Utils { static void handleException(dynamic exception, cxt, Function(String)? onErrorMessage) { String errorMessage; - if (exception is APIException) { - if (exception.message == APIException.UNAUTHORIZED) { - return; + if (exception.error.errorType != null && exception.error.errorType == 4) { + Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.appUpdateScreen, (_) => false, arguments: exception.error?.errorMessage); + } else { + if (exception is APIException) { + if (exception.message == APIException.UNAUTHORIZED) { + return; + } else { + errorMessage = exception.error?.errorMessage ?? exception.message; + } } else { - errorMessage = exception.error?.errorMessage ?? exception.message; + errorMessage = APIException.UNKNOWN; } - } else { - errorMessage = APIException.UNKNOWN; - } - if (onErrorMessage != null) { - onErrorMessage(errorMessage); - } else { - if (!AppState().isAuthenticated) { - showDialog( - context: cxt, - builder: (cxt) => ConfirmDialog( - message: errorMessage, - onTap: () { - Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); - }, - ), - ); + if (onErrorMessage != null) { + onErrorMessage(errorMessage); } else { - if (cxt != null) { - confirmDialog(cxt, errorMessage); + if (!AppState().isAuthenticated) { + showDialog( + context: cxt, + builder: (cxt) => ConfirmDialog( + message: errorMessage, + onTap: () { + Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); + }, + ), + ); } else { - showToast(errorMessage); + if (cxt != null) { + confirmDialog(cxt, errorMessage); + } else { + showToast(errorMessage); + } } } } @@ -310,17 +314,23 @@ class Utils { } static String formatDateDefault(String date) { - if (date.toLowerCase().contains("t")) { - date = date.toLowerCase().split("t")[0]; - // return DateFormat('yyyy-MM-dd').format(DateFormat('dd-MM-yyyy').parseLoose(date)); - return DateFormat('dd-MM-yyyy').format(DateFormat('yyyy-MM-dd').parseLoose(date)); - } else { - if(date.toLowerCase().split("-")[1].length == 3) { - return DateFormat('dd-MM-yyyy').format(DateFormat('dd-MMM-yyyy').parseLoose(date)); + if (date.isNotEmpty) { + if (date.toLowerCase().contains("t")) { + date = date.toLowerCase().split("t")[0]; + if (!date.contains("00:00:00")) { + date = date + ' 00:00:00'; + } + return date; } else { - return DateFormat('dd-MM-yyyy').format(DateFormat('yyyy-MM-dd').parseLoose(date)); + if (date.toLowerCase().split("-")[1].length == 3) { + return DateFormat('dd-MM-yyyy').format(DateFormat('dd-MMM-yyyy').parseLoose(date)); + } else { + return DateFormat('dd-MM-yyyy').format(DateFormat('yyyy-MM-dd').parseLoose(date)); + } + // return DateFormat('yyyy-MM-dd').format(DateFormat('dd-MM-yyyy').parseLoose(date)); } - // return DateFormat('yyyy-MM-dd').format(DateFormat('dd-MM-yyyy').parseLoose(date)); + } else { + return date; } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index dc6b553..905f4de 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/ui/app_update_screen.dart'; import 'package:mohem_flutter_app/ui/attendance/add_vacation_rule_screen.dart'; import 'package:mohem_flutter_app/ui/attendance/monthly_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/attendance/vacation_rule_screen.dart'; @@ -191,6 +192,7 @@ class AppRoutes { static const String marathonWaitingScreen = "/marathonWaitingScreen"; static const String unsafeDeviceScreen = "/unsafeDeviceScreen"; + static const String appUpdateScreen = "/appUpdateScreen"; static final Map routes = { login: (BuildContext context) => LoginScreen(), @@ -302,5 +304,6 @@ class AppRoutes { marathonWaitingScreen: (BuildContext context) => const MarathonWaitingScreen(), unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(), + appUpdateScreen: (BuildContext context) => const AppUpdateScreen(), }; } diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 7cb7b96..4dc55f6 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -992,7 +992,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void deleteData() { List exists = [], unique = []; - exists.addAll(searchedChats!); + if(searchedChats != null) exists.addAll(searchedChats!); exists.addAll(favUsersList!); Map profileMap = {}; for (ChatUser item in exists) { diff --git a/lib/ui/app_update_screen.dart b/lib/ui/app_update_screen.dart new file mode 100644 index 0000000..4a769c3 --- /dev/null +++ b/lib/ui/app_update_screen.dart @@ -0,0 +1,56 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.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'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AppUpdateScreen extends StatefulWidget { + const AppUpdateScreen({Key? key}) : super(key: key); + + @override + State createState() => _UnsafeDeviceScreenState(); +} + +class _UnsafeDeviceScreenState extends State { + String? dynamicParams; + + @override + Widget build(BuildContext context) { + dynamicParams ??= ModalRoute.of(context)!.settings.arguments as String; + return Scaffold( + body: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + 21.height, + Center(child: Image.asset("assets/images/logos/main_mohemm_logo.png", width: 200, height: 50)), + 50.height, + "Please Update Your App".toText24(isBold: true), + 48.height, + dynamicParams.toString().toText14(isCenter: true).paddingOnly(left: 20.0, right: 20.0), + 21.height, + DefaultButton(LocaleKeys.ok.tr(), () async { + if (Platform.isAndroid || Platform.isIOS) { + var appId = Platform.isAndroid ? 'hmg.cloudSolutions.mohem' : '1468856602'; + var url = Uri.parse( + Platform.isAndroid ? "market://details?id=$appId" : "https://apps.apple.com/app/id$appId", + ); + launchUrl( + url, + mode: LaunchMode.externalApplication, + ); + } + }).paddingAll(24) + ], + ), + ), + ); + } +} diff --git a/lib/ui/login/new_password_screen.dart b/lib/ui/login/new_password_screen.dart index 8bb1443..217e049 100644 --- a/lib/ui/login/new_password_screen.dart +++ b/lib/ui/login/new_password_screen.dart @@ -102,8 +102,8 @@ class _NewPasswordScreenState extends State { passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8), 8.height, passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)), - 8.height, - passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')), + // 8.height, + // passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')), 8.height, passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), ], @@ -146,11 +146,11 @@ class _NewPasswordScreenState extends State { bool hasUppercase = password.contains(RegExp(r'[A-Z]')); bool hasDigits = password.contains(RegExp(r'[0-9]')); bool hasLowercase = password.contains(RegExp(r'[a-z]')); - bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]')); + // bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]')); bool hasMinLength = password.length >= minLength; bool isMatched = password == confirmPassword.text; - return hasDigits && hasUppercase && hasLowercase && hasSpecialCharacters && hasMinLength && isMatched && checkRepeatedChars(password); + return hasDigits && hasUppercase && hasLowercase && hasMinLength && isMatched && checkRepeatedChars(password); } bool checkRepeatedChars(String password) {