diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 070597d..f187ebd 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -10,9 +10,9 @@ Bool { - FirebaseApp.configure() + FirebaseApp.configure() + FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in + GeneratedPluginRegistrant.register(with: registry) + } + + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate + } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index e326d8f..e7b7e3b 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -50,6 +50,7 @@ This app requires photo library access to select image as document & upload it. UIBackgroundModes + fetch remote-notification FirebaseAppDelegateProxyEnabled diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index ff26054..8518cd7 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -19,7 +19,11 @@ class APIError { APIError(this.errorCode, this.errorMessage, this.errorType); - Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType,}; + Map toJson() => { + 'errorCode': errorCode, + 'errorMessage': errorMessage, + 'errorType': errorType, + }; @override String toString() { @@ -79,28 +83,29 @@ class ApiClient { print("body:$bodyJson"); } var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData); - // try { - if (!kReleaseMode) { - logger.i("res: " + response.body); - } - var jsonData = jsonDecode(response.body); - if (jsonData["IsAuthenticated"] != null) { - AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; - } - if (jsonData["ErrorMessage"] == null) { - return factoryConstructor(jsonData); - } else { - APIError? apiError; - apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType']); - throw APIException(APIException.BAD_REQUEST, error: apiError); + try { + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + + var jsonData = jsonDecode(response.body); + if (jsonData["IsAuthenticated"] != null) { + AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; + } + if (jsonData["ErrorMessage"] == null) { + return factoryConstructor(jsonData); + } else { + APIError? apiError; + apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType'] ?? 0); + throw APIException(APIException.BAD_REQUEST, error: apiError); + } + } catch (ex) { + if (ex is APIException) { + rethrow; + } else { + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + } } - // } catch (ex) { - // if (ex is APIException) { - // rethrow; - // } else { - // throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); - // } - // } } Future postJsonForResponse(String url, T jsonObject, diff --git a/lib/api/offers_and_discounts_api_client.dart b/lib/api/offers_and_discounts_api_client.dart index 1d3153c..8c92539 100644 --- a/lib/api/offers_and_discounts_api_client.dart +++ b/lib/api/offers_and_discounts_api_client.dart @@ -17,7 +17,7 @@ class OffersAndDiscountsApiClient { List getSaleCategoriesList = []; String url = "${ApiConsts.cocRest}Mohemm_ITG_GetCategories"; - Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgPageSize": 100, "ItgPageNo": 1}; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgPageSize": 100, "ItgPageNo": 1, "ItgIsActive": true}; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject( @@ -55,12 +55,12 @@ class OffersAndDiscountsApiClient { (response) { var body = json.decode(response['Mohemm_ITG_ResponseItem']); - var bodyData = json.decode(body['result']['data']); + var bodyData = body['result']['data']; - if(bodyData != null) { + if (bodyData != null) { bodyData.forEach((v) { - getSaleCategoriesList.add(OffersListModel.fromJson(v)); - }); + getSaleCategoriesList.add(OffersListModel.fromJson(v)); + }); } return getSaleCategoriesList; }, diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 731a45e..ea7b85e 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/request_detail_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; @@ -76,7 +77,7 @@ class AppState { bool get getIsDemoMarathon => _isDemoMarathon; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 3.9, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 4.0, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; @@ -180,12 +181,4 @@ class AppState { bool cancelRequestTrancsection = true; - - String? _deviceNotificationToken; - - String? get deviceNotificationToken => _deviceNotificationToken; - - set deviceNotificationToken(String? deviceNotificationToken) { - _deviceNotificationToken = deviceNotificationToken; - } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 56b0008..96fd4b0 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,7 +4,7 @@ class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; @@ -44,7 +44,6 @@ class ApiConsts { static int tabletMinLength = 500; } - class SharedPrefsConsts { static String isRememberMe = "remember_me"; static String username = "username"; diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index 336b87c..cebf76d 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -1,12 +1,15 @@ import 'dart:convert'; import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:firebase_core/firebase_core.dart'; -//final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - +final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); class AppNotifications { static final AppNotifications _instance = AppNotifications._internal(); @@ -15,45 +18,66 @@ class AppNotifications { factory AppNotifications() => _instance; - // Future requestPermissions() async { - // if (Platform.isIOS) { - // await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); - // } else if (Platform.isAndroid) { - // AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation(); - // bool? granted = await androidImplementation?.requestPermission(); - // if (granted == false) { - // print("-------------------- Permission Granted ------------------------"); - // print(granted); - // await Permission.notification.request(); - // } - // } - // } - - // Future isAndroidPermGranted() async { - // if (Platform.isAndroid) { - // bool granted = await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.areNotificationsEnabled() ?? false; - // } - // } - - void initNotification(String? firebaseToken) async { - // await requestPermissions(); + Future requestPermissions() async { + if (Platform.isIOS) { + await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); + } else if (Platform.isAndroid) { + AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation(); + bool? granted = await androidImplementation?.requestPermission(); + if (granted == false) { + if (kDebugMode) { + print("-------------------- Permission Granted ------------------------"); + print(granted); + } + await Permission.notification.request(); + } + } + } + + void init(String? firebaseToken) async { + await requestPermissions(); AppState().setDeviceToken = firebaseToken; - // await Permission.notification.isDenied.then((value) { - // if (value) { - // Permission.notification.request(); - // } - // }); + await Permission.notification.isDenied.then((bool value) { + if (value) { + Permission.notification.request(); + } + }); RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); + if (initialMessage != null) _handleMessage(initialMessage); FirebaseMessaging.onMessage.listen((RemoteMessage message) { if (message.notification != null) _handleMessage(message); }); - FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage); + + FirebaseMessaging.onMessageOpenedApp.listen(_handleOpenApp); + + FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); + + FirebaseMessaging.instance.onTokenRefresh.listen((String token) { + AppState().setDeviceToken = token; + }); } void _handleMessage(RemoteMessage message) { - print("Handle Message"); - logger.w(json.encode(message)); + Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + } + + void _handleOpenApp(RemoteMessage message) { + Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); } } + +AndroidNotificationChannel channel = const AndroidNotificationChannel( + "high_importance_channel", + "High Importance Notifications", + importance: Importance.high, +); + +Future backgroundMessageHandler(RemoteMessage message) async { + await Firebase.initializeApp(); + Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + logger.w(message.data["user_chat_history_response"]); + Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); +} diff --git a/lib/classes/push-notification-handler.dart b/lib/classes/push-notification-handler.dart deleted file mode 100644 index b95ceb2..0000000 --- a/lib/classes/push-notification-handler.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:mohem_flutter_app/app_state/app_state.dart'; - -// |--> Push Notification Background -Future backgroundMessageHandler(message) async { - print("Firebase backgroundMessageHandler!!!"); -} - -class PushNotificationHandler { - final BuildContext context; - static PushNotificationHandler? _instance; - - PushNotificationHandler(this.context) { - PushNotificationHandler._instance = this; - } - - static PushNotificationHandler getInstance() => _instance!; - - void init() async { - FirebaseMessaging.onMessage.listen((RemoteMessage message) async { - if (Platform.isIOS) { - await Future.delayed(Duration(milliseconds: 3000)).then((value) { - newMessage(message); - }); - } else { - newMessage(message); - } - }); - - FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async { - if (Platform.isIOS) { - await Future.delayed(Duration(milliseconds: 3000)).then((value) { - newMessage(message); - }); - } else { - newMessage(message); - } - }); - - FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) { - print("Push Notification onTokenRefresh: " + fcm_token); - AppState().setDeviceToken = fcm_token; - }); - - FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); - } - - void newMessage(RemoteMessage remoteMessage) async { - print("Remote Message: " + remoteMessage.data.toString()); - if (remoteMessage.data.isEmpty) { - return; - } - } -} diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 1563767..f3497d3 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -533,6 +533,9 @@ class CodegenLoader extends AssetLoader{ "startingIn": "يبدأ في", "youAreOutOfContest": "أنت خارج المسابقة.", "winners": "الفائزين!!!", + "expireAfter": "تنتهي بعد", + "oneWeek": "أسبوع 1", + "twoWeek": "2 أسبوع", "noUpcoming": "لا يوجد قادم", "fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية", "noWinner": "حزين! لم يفز أحد اليوم.", @@ -1058,6 +1061,9 @@ static const Map en_US = { "startingIn": "Starting in", "youAreOutOfContest": "You are out of the contest.", "winners": "WINNERS!!!", + "expireAfter": "Expires After", + "oneWeek": "1 Week", + "twoWeek": "2 Week", "noUpcoming": "There is no upcoming", "fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified.", "noWinner": "Sad! No one won today.", diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 1671b72..4eb91c9 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -503,6 +503,9 @@ abstract class LocaleKeys { static const startingIn = 'startingIn'; static const youAreOutOfContest = 'youAreOutOfContest'; static const winners = 'winners'; + static const expireAfter = 'expireAfter'; + static const oneWeek = 'oneWeek'; + static const twoWeek = 'twoWeek'; static const noUpcoming = 'noUpcoming'; static const fakeLocation = 'fakeLocation'; static const noWinner = 'noWinner'; diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index 37be8d8..642c8ec 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -6,6 +6,8 @@ // ignore_for_file: lines_longer_than_80_chars // ignore_for_file: depend_on_referenced_packages +import 'package:audio_session/audio_session_web.dart'; +import 'package:camera_web/camera_web.dart'; import 'package:file_picker/_internal/file_picker_web.dart'; import 'package:firebase_core_web/firebase_core_web.dart'; import 'package:firebase_messaging_web/firebase_messaging_web.dart'; @@ -13,6 +15,8 @@ import 'package:fluttertoast/fluttertoast_web.dart'; import 'package:geolocator_web/geolocator_web.dart'; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:image_picker_for_web/image_picker_for_web.dart'; +import 'package:just_audio_web/just_audio_web.dart'; +import 'package:record_web/record_web.dart'; import 'package:shared_preferences_web/shared_preferences_web.dart'; import 'package:url_launcher_web/url_launcher_web.dart'; import 'package:video_player_web/video_player_web.dart'; @@ -21,6 +25,8 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart'; // ignore: public_member_api_docs void registerPlugins(Registrar registrar) { + AudioSessionWeb.registerWith(registrar); + CameraPlugin.registerWith(registrar); FilePickerWeb.registerWith(registrar); FirebaseCoreWeb.registerWith(registrar); FirebaseMessagingWeb.registerWith(registrar); @@ -28,6 +34,8 @@ void registerPlugins(Registrar registrar) { GeolocatorPlugin.registerWith(registrar); GoogleMapsPlugin.registerWith(registrar); ImagePickerPlugin.registerWith(registrar); + JustAudioPlugin.registerWith(registrar); + RecordPluginWeb.registerWith(registrar); SharedPreferencesPlugin.registerWith(registrar); UrlLauncherPlugin.registerWith(registrar); VideoPlayerPlugin.registerWith(registrar); diff --git a/lib/models/items_for_sale/get_employee_ads_list.dart b/lib/models/items_for_sale/get_employee_ads_list.dart index 68aa805..7b7b7a6 100644 --- a/lib/models/items_for_sale/get_employee_ads_list.dart +++ b/lib/models/items_for_sale/get_employee_ads_list.dart @@ -11,7 +11,7 @@ class EmployeePostedAds { String? countryName; String? currencyCode; String? startDate; - String? endDate; + DateTime? endDate; int? quotePrice; int? employeeNumber; String? profilePicture; @@ -29,32 +29,32 @@ class EmployeePostedAds { EmployeePostedAds( {this.itemSaleID, - this.title, - this.titleAr, - this.description, - this.descriptionAr, - this.categoryID, - this.categoryTitle, - this.regionID, - this.regionName, - this.countryName, - this.currencyCode, - this.startDate, - this.endDate, - this.quotePrice, - this.employeeNumber, - this.profilePicture, - this.fullName, - this.emailAddress, - this.mobileNumber, - this.isApproved, - this.status, - this.itemAttachments, - this.created, - this.isActive, - this.pageSize, - this.pageNo, - this.languageId}); + this.title, + this.titleAr, + this.description, + this.descriptionAr, + this.categoryID, + this.categoryTitle, + this.regionID, + this.regionName, + this.countryName, + this.currencyCode, + this.startDate, + this.endDate, + this.quotePrice, + this.employeeNumber, + this.profilePicture, + this.fullName, + this.emailAddress, + this.mobileNumber, + this.isApproved, + this.status, + this.itemAttachments, + this.created, + this.isActive, + this.pageSize, + this.pageNo, + this.languageId}); EmployeePostedAds.fromJson(Map json) { itemSaleID = json['itemSaleID']; @@ -115,8 +115,7 @@ class EmployeePostedAds { data['isApproved'] = this.isApproved; data['status'] = this.status; if (this.itemAttachments != null) { - data['itemAttachments'] = - this.itemAttachments!.map((v) => v.toJson()).toList(); + data['itemAttachments'] = this.itemAttachments!.map((v) => v.toJson()).toList(); } data['created'] = this.created; data['isActive'] = this.isActive; @@ -138,16 +137,7 @@ class ItemAttachments { String? content; String? filePath; - ItemAttachments( - {this.attachmentId, - this.fileName, - this.contentType, - this.attachFileStream, - this.base64String, - this.isActive, - this.referenceItemId, - this.content, - this.filePath}); + ItemAttachments({this.attachmentId, this.fileName, this.contentType, this.attachFileStream, this.base64String, this.isActive, this.referenceItemId, this.content, this.filePath}); ItemAttachments.fromJson(Map json) { attachmentId = json['attachmentId']; diff --git a/lib/models/items_for_sale/item_review_model.dart b/lib/models/items_for_sale/item_review_model.dart index 4aac997..1f6d9d2 100644 --- a/lib/models/items_for_sale/item_review_model.dart +++ b/lib/models/items_for_sale/item_review_model.dart @@ -9,16 +9,8 @@ class ItemReviewModel { num? itemPrice; List? itemPhotos; GetSaleCategoriesList? selectedSaleCategory; - - ItemReviewModel( - this.itemTitle, - this.itemDescription, - this.itemCondition, - this.selectedRegion, - this.itemPrice, - this.itemPhotos, - this.selectedSaleCategory, - ); + DateTime endDate; + ItemReviewModel(this.itemTitle, this.itemDescription, this.itemCondition, this.selectedRegion, this.itemPrice, this.itemPhotos, this.selectedSaleCategory, this.endDate); Map toJson() { Map data = new Map(); @@ -29,7 +21,7 @@ class ItemReviewModel { data['itemPrice'] = this.itemPrice; data['itemPhotos'] = this.itemPhotos; data['selectedSaleCategory'] = this.selectedSaleCategory; + data['endDate'] = this.endDate; return data; } - } diff --git a/lib/models/offers_and_discounts/get_offers_list.dart b/lib/models/offers_and_discounts/get_offers_list.dart index 2ba42ea..e48f3f1 100644 --- a/lib/models/offers_and_discounts/get_offers_list.dart +++ b/lib/models/offers_and_discounts/get_offers_list.dart @@ -1,96 +1,192 @@ class OffersListModel { - String? title; - String? titleAR; - String? description; - String? descriptionAR; + int? offersDiscountId; + String? titleEn; + String? titleAr; + String? descriptionEn; + String? descriptionAr; String? startDate; String? endDate; - String? logo; - String? bannerImage; - String? discount; - String? rowID; + int? categoryId; String? categoryNameEn; String? categoryNameAr; - String? categoryID; - String? isHasLocation; + String? discount; + String? location; + int? statusId; + String? statusTitle; + bool? isHasLocation; + String? discountDescription; + String? websiteUrl; + bool? bookMarked; + bool? isHotDeal; + List? offersDiscountImageColl; + dynamic locationList; String? created; - String? publishedDesc; - String? published; - String? expireAfter; - String? status; - String? isActive; - String? totalItems; + String? bannerImage; + String? logo; + bool? isActive; + int? pageSize; + int? pageNo; + int? languageId; OffersListModel( - {this.title, - this.titleAR, - this.description, - this.descriptionAR, - this.startDate, - this.endDate, - this.logo, - this.bannerImage, - this.discount, - this.rowID, - this.categoryNameEn, - this.categoryNameAr, - this.categoryID, - this.isHasLocation, - this.created, - this.publishedDesc, - this.published, - this.expireAfter, - this.status, - this.isActive, - this.totalItems}); + {this.offersDiscountId, + this.titleEn, + this.titleAr, + this.descriptionEn, + this.descriptionAr, + this.startDate, + this.endDate, + this.categoryId, + this.categoryNameEn, + this.categoryNameAr, + this.discount, + this.location, + this.statusId, + this.statusTitle, + this.isHasLocation, + this.discountDescription, + this.websiteUrl, + this.bookMarked, + this.isHotDeal, + this.offersDiscountImageColl, + this.locationList, + this.created, + this.bannerImage, + this.logo, + this.isActive, + this.pageSize, + this.pageNo, + this.languageId}); OffersListModel.fromJson(Map json) { - title = json['Title']; - titleAR = json['Title_AR']; - description = json['Description']; - descriptionAR = json['Description_AR']; - startDate = json['Start Date']; - endDate = json['End Date']; - logo = json['Logo']; - bannerImage = json['Banner_Image']; - discount = json['Discount']; - rowID = json['rowID']; + offersDiscountId = json['offersDiscountId']; + titleEn = json['titleEn']; + titleAr = json['titleAr']; + descriptionEn = json['descriptionEn']; + descriptionAr = json['descriptionAr']; + startDate = json['startDate']; + endDate = json['endDate']; + categoryId = json['categoryId']; categoryNameEn = json['categoryName_en']; categoryNameAr = json['categoryName_ar']; - categoryID = json['categoryID']; - isHasLocation = json['IsHasLocation']; + discount = json['discount']; + location = json['location']; + statusId = json['statusId']; + statusTitle = json['statusTitle']; + isHasLocation = json['isHasLocation']; + discountDescription = json['discountDescription']; + websiteUrl = json['websiteUrl']; + bookMarked = json['bookMarked']; + isHotDeal = json['isHotDeal']; + if (json['offersDiscountImageColl'] != null) { + offersDiscountImageColl = []; + json['offersDiscountImageColl'].forEach((v) { + offersDiscountImageColl!.add(new OffersDiscountImageColl.fromJson(v)); + }); + } + locationList = json['locationList']; created = json['created']; - publishedDesc = json['PublishedDesc']; - published = json['Published']; - expireAfter = json['ExpireAfter']; - status = json['Status']; - isActive = json['IsActive']; - totalItems = json['TotalItems']; + bannerImage = json['banner_Image']; + logo = json['logo']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; } Map toJson() { Map data = new Map(); - data['Title'] = this.title; - data['Title_AR'] = this.titleAR; - data['Description'] = this.description; - data['Description_AR'] = this.descriptionAR; - data['Start Date'] = this.startDate; - data['End Date'] = this.endDate; - data['Logo'] = this.logo; - data['Banner_Image'] = this.bannerImage; - data['Discount'] = this.discount; - data['rowID'] = this.rowID; + data['offersDiscountId'] = this.offersDiscountId; + data['titleEn'] = this.titleEn; + data['titleAr'] = this.titleAr; + data['descriptionEn'] = this.descriptionEn; + data['descriptionAr'] = this.descriptionAr; + data['startDate'] = this.startDate; + data['endDate'] = this.endDate; + data['categoryId'] = this.categoryId; data['categoryName_en'] = this.categoryNameEn; data['categoryName_ar'] = this.categoryNameAr; - data['categoryID'] = this.categoryID; - data['IsHasLocation'] = this.isHasLocation; + data['discount'] = this.discount; + data['location'] = this.location; + data['statusId'] = this.statusId; + data['statusTitle'] = this.statusTitle; + data['isHasLocation'] = this.isHasLocation; + data['discountDescription'] = this.discountDescription; + data['websiteUrl'] = this.websiteUrl; + data['bookMarked'] = this.bookMarked; + data['isHotDeal'] = this.isHotDeal; + if (this.offersDiscountImageColl != null) { + data['offersDiscountImageColl'] = this.offersDiscountImageColl!.map((v) => v.toJson()).toList(); + } + data['locationList'] = this.locationList; data['created'] = this.created; - data['PublishedDesc'] = this.publishedDesc; - data['Published'] = this.published; - data['ExpireAfter'] = this.expireAfter; - data['Status'] = this.status; - data['IsActive'] = this.isActive; - data['TotalItems'] = this.totalItems; + data['banner_Image'] = this.bannerImage; + data['logo'] = this.logo; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} + +class OffersDiscountImageColl { + int? imageAttachmentId; + String? fileName; + String? contentType; + String? attachFileStream; + String? base64String; + int? referenceItemId; + String? filePath; + String? imageTag; + bool? isActive; + int? pageSize; + int? pageNo; + int? languageId; + + OffersDiscountImageColl( + {this.imageAttachmentId, + this.fileName, + this.contentType, + this.attachFileStream, + this.base64String, + this.referenceItemId, + this.filePath, + this.imageTag, + this.isActive, + this.pageSize, + this.pageNo, + this.languageId}); + + OffersDiscountImageColl.fromJson(Map json) { + imageAttachmentId = json['imageAttachmentId']; + fileName = json['fileName']; + contentType = json['contentType']; + attachFileStream = json['attachFileStream']; + base64String = json['base64String']; + referenceItemId = json['referenceItemId']; + filePath = json['filePath']; + imageTag = json['imageTag']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + Map data = new Map(); + data['imageAttachmentId'] = this.imageAttachmentId; + data['fileName'] = this.fileName; + data['contentType'] = this.contentType; + data['attachFileStream'] = this.attachFileStream; + data['base64String'] = this.base64String; + data['referenceItemId'] = this.referenceItemId; + data['filePath'] = this.filePath; + data['imageTag'] = this.imageTag; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; return data; } } diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 71d7ccb..08b148d 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -16,6 +16,7 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/encryption.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; @@ -23,6 +24,7 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as userLoginToken; import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/widgets/image_picker.dart'; import 'package:open_file/open_file.dart'; @@ -120,14 +122,12 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - void getUserRecentChats() async { + Future getUserRecentChats() async { ChatUserModel recentChat = await ChatApiClient().getRecentChats(); ChatUserModel favUList = await ChatApiClient().getFavUsers(); if (favUList.response != null && recentChat.response != null) { favUsersList = favUList.response!; - favUsersList.sort( - (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase()), - ); + favUsersList.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); for (dynamic user in recentChat.response!) { for (dynamic favUser in favUList.response!) { if (user.id == favUser.id) { @@ -137,16 +137,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } pChatHistory = recentChat.response ?? []; - pChatHistory!.sort( - (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase()), - ); + pChatHistory!.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); searchedChats = pChatHistory; isLoading = false; - await invokeUserChatHistoryNotDeliveredAsync( - userId: int.parse( - AppState().chatDetails!.response!.id.toString(), - ), - ); + await invokeUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString())); sort(); notifyListeners(); if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { @@ -325,12 +319,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { user.userStatus = items.first["userStatus"]; } } - if (teamMembersList != null) { - if (teamMembersList.isNotEmpty) { - for (ChatUser user in teamMembersList!) { - if (user.id == items.first["id"]) { - user.userStatus = items.first["userStatus"]; - } + if (teamMembersList.isNotEmpty) { + for (ChatUser user in teamMembersList!) { + if (user.id == items.first["id"]) { + user.userStatus = items.first["userStatus"]; } } } @@ -1457,4 +1449,21 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } return Material.TextDirection.ltr; } + + void openChatByNoti(BuildContext context) async { + SingleUserChatModel nUser = SingleUserChatModel.fromJson( + jsonDecode(await Utils.getStringFromPrefs("notificationData")), + ); + Utils.saveStringFromPrefs("isAppOpendByChat", "false"); + Utils.saveStringFromPrefs("notificationData", "null"); + Future.delayed(const Duration(seconds: 1)); + for (ChatUser user in searchedChats!) { + if (user.id == nUser.targetUserId) { + Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); + return; + } else { + openChatByNoti(context); + } + } + } } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index aa9a38f..5899699 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -190,7 +190,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { accrualList = await DashboardApiClient().getAccrualBalances(DateFormat("MM/dd/yyyy").format(date)); isLeaveTicketBalanceLoading = false; leaveBalanceAccrual = accrualList![0]; - ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0); + ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0) + (accrualList![3].accrualNetEntitlement ?? 0.0); notifyListeners(); } catch (ex) { isLeaveTicketBalanceLoading = false; diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index bbb3048..2e23254 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.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'; @@ -50,7 +51,13 @@ class _ChatHomeState extends State { } if (data.searchedChats == null || data.searchedChats!.isEmpty) { data.isLoading = true; - data.getUserRecentChats(); + data.getUserRecentChats().whenComplete(() async { + String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + String notificationData = await Utils.getStringFromPrefs("notificationData"); + if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { + data.openChatByNoti(context); + } + }); } } diff --git a/lib/ui/chat/chat_home_screen.dart b/lib/ui/chat/chat_home_screen.dart index aa47053..04d7c2e 100644 --- a/lib/ui/chat/chat_home_screen.dart +++ b/lib/ui/chat/chat_home_screen.dart @@ -26,14 +26,10 @@ class ChatHomeScreen extends StatefulWidget { class _ChatHomeScreenState extends State { TextEditingController search = TextEditingController(); - late ChatProviderModel data; - - final RefreshController _rc = RefreshController(initialRefresh: false); @override void initState() { super.initState(); - data = Provider.of(context, listen: false); } @override diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 1a91636..af6f903 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:ui' as ui; import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -15,6 +16,7 @@ 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/main.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; @@ -61,7 +63,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb marathonProvider = Provider.of(context, listen: false); cProvider = Provider.of(context, listen: false); _bHubCon(); - _onRefresh(); + _onRefresh(true); }); } @@ -91,15 +93,41 @@ class _DashboardScreenState extends State with WidgetsBindingOb } void _bHubCon() { - cProvider.getUserAutoLoginToken().whenComplete(() { - cProvider.buildHubConnection(); - Future.delayed(const Duration(seconds: 2), () { - cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - }); + cProvider.getUserAutoLoginToken().whenComplete(() async { + String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + if (isAppOpendByChat != null && isAppOpendByChat == "true") { + Utils.showLoading(context); + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () async { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + gotoChat(context); + }); + } else { + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + }); + } }); } - void _onRefresh() async { + Future checkHubCon() async { + if (chatHubConnection.state == HubConnectionState.Connected) { + await chatHubConnection.stop(); + await chatHubConnection.start(); + } else if (chatHubConnection.state != HubConnectionState.Connected) { + await chatHubConnection.start(); + } + } + + void gotoChat(BuildContext context) async { + if (chatHubConnection.state == HubConnectionState.Connected) { + Utils.hideLoading(context); + Navigator.pushNamed(context, AppRoutes.chat); + } + } + + void _onRefresh(bool isFromInit) async { data.initProvider(); // data.getITGNotification().then((value) { // print("--------------------detail_1-----------------"); @@ -114,6 +142,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchMenuEntries(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); + if (!isFromInit) checkHubCon(); _refreshController.refreshCompleted(); } @@ -213,7 +242,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb color: MyColors.gradiantEndColor, ), controller: _refreshController, - onRefresh: _onRefresh, + onRefresh: () { + _onRefresh(false); + }, child: SingleChildScrollView( child: Column( children: [ @@ -414,7 +445,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb Radius.circular(50), ), child: Hero( - tag: "ItemImage" + data.getOffersList[index].rowID!, + tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, transitionOnUserGestures: true, child: Image.network( data.getOffersList[index].bannerImage!, @@ -426,8 +457,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb 4.height, Expanded( child: AppState().isArabic(context) - ? data.getOffersList[index].titleAR!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].title!.toText12(isCenter: true, maxLine: 1), + ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), ), ], ), @@ -581,7 +612,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.getOffersList.forEach((OffersListModel element) { if (counter <= 4) { - if (element.rowID != offersListModelObj.rowID) { + if (element.offersDiscountId != offersListModelObj.offersDiscountId) { getOffersDetailList.add(element); counter++; } diff --git a/lib/ui/landing/today_attendance_screen2.dart b/lib/ui/landing/today_attendance_screen2.dart index f0228eb..a72df34 100644 --- a/lib/ui/landing/today_attendance_screen2.dart +++ b/lib/ui/landing/today_attendance_screen2.dart @@ -50,23 +50,23 @@ class _TodayAttendanceScreenState extends State { icon: const Icon(Icons.arrow_back_ios, color: Colors.white), onPressed: () => Navigator.pop(context), ), - actions: [ - IconButton( - onPressed: () { - data.fetchAttendanceTracking(context); - }, - icon: const Icon( - Icons.ac_unit, - color: Colors.white, - ), - ) - ], + // actions: [ + // IconButton( + // onPressed: () { + // data.fetchAttendanceTracking(context); + // }, + // icon: const Icon( + // Icons.ac_unit, + // color: Colors.white, + // ), + // ) + // ], ), backgroundColor: MyColors.backgroundBlackColor, body: Consumer( builder: (context, model, child) { return (model.isAttendanceTrackingLoading - ? Center(child: CircularProgressIndicator()) + ? const Center(child: CircularProgressIndicator()) : Column( children: [ Container( diff --git a/lib/ui/landing/widget/menus_widget.dart b/lib/ui/landing/widget/menus_widget.dart index 3e24f63..64855ee 100644 --- a/lib/ui/landing/widget/menus_widget.dart +++ b/lib/ui/landing/widget/menus_widget.dart @@ -96,7 +96,7 @@ class MenusWidget extends StatelessWidget { Row( children: [ Expanded( - child: data.leaveBalance.toString().toText16(color: Colors.white, isBold: true, maxlines: 1), + child: data.leaveBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1), ), RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), ], @@ -123,7 +123,7 @@ class MenusWidget extends StatelessWidget { Row( children: [ Expanded( - child: data.ticketBalance.toString().toText16(color: Colors.white, isBold: true, maxlines: 1), + child: data.ticketBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1), ), RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), ], diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 1c10bb6..69750fa 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -13,7 +13,6 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/notifications.dart'; -import 'package:mohem_flutter_app/classes/push-notification-handler.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -30,6 +29,7 @@ import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:safe_device/safe_device.dart'; +import 'package:wifi_iot/wifi_iot.dart'; class LoginScreen extends StatefulWidget { LoginScreen({Key? key}) : super(key: key); @@ -95,9 +95,15 @@ class _LoginScreenState extends State { try { Utils.showLoading(context); await Firebase.initializeApp(); + // await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( + // alert: true, + // badge: true, + // sound: true, + // ); + // await FirebaseMessaging.instance.requestPermission(); _firebaseMessaging = FirebaseMessaging.instance; firebaseToken = await _firebaseMessaging.getToken(); - AppNotifications().initNotification(firebaseToken); + AppNotifications().init(firebaseToken); loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); if (loginInfo == null) { await checkPrefs(); @@ -167,7 +173,7 @@ class _LoginScreenState extends State { if (!kReleaseMode) { // username.text = "15444"; // Maha User // username.text = "15153"; // Tamer User - // password.text = "Abcd@1234"; + // password.text = "Abcd@12345"; // username.text = "206535"; // Hashim User // password.text = "Namira786"; @@ -230,6 +236,14 @@ class _LoginScreenState extends State { Navigator.pushNamed(context, AppRoutes.forgotPassword); }), ), + 20.height, + // DefaultButton( + // "Connect HMG Network", + // () async { + // SystemChannels.textInput.invokeMethod('TextInput.hide'); + // connectWithHmgNetwork(); + // }, + // ), ], ), ) @@ -245,4 +259,30 @@ class _LoginScreenState extends State { ), ); } + + void connectWithHmgNetwork() async { + try { + bool isConnected = await WiFiForIoTPlugin.connect("MOHEMM-CONNECT", password: "0987654321", joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false); + + if (isConnected) { + await WiFiForIoTPlugin.forceWifiUsage(true); + // if (Platform.isIOS) { + // await closeWifiRequest(); + // await Future.delayed(Duration(seconds: 6)); + // } else { + // await WiFiForIoTPlugin.forceWifiUsage(true); + // } + } + } catch (e) { + print("----------------o----"); + print(e); + } + } + + Future closeWifiRequest() async { + if (Platform.isAndroid) { + await WiFiForIoTPlugin.forceWifiUsage(false); + } + return await WiFiForIoTPlugin.disconnect(); + } } diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index cfa808a..30feb71 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -324,20 +324,22 @@ class _VerifyLastLoginScreenState extends State { Future performApiCall(String _title, String _icon, int _flag, int sendVerificationFlat, {bool isDirectLogin = false}) async { try { - if (isDirectLogin) + if (isDirectLogin) { setState(() { Utils.showLoading(context); }); - else + } else { Utils.showLoading(context); + } await LoginApiClient().checkMobileAppVersion(); await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); - if (!isDirectLogin) + if (!isDirectLogin) { BasicMemberInformationModel? memberInformationModel = await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType(0, AppState().memberLoginList?.pMOBILENUMBER, sendVerificationFlat, AppState().getUserName); + } if (isDirectLogin) performDirectApiCall(_title, _icon, _flag, "", null); if (!isDirectLogin) Utils.hideLoading(context); - if (!isDirectLogin) + if (!isDirectLogin) { OtpDialog( context, sendVerificationFlat, @@ -353,6 +355,7 @@ class _VerifyLastLoginScreenState extends State { performApiCall(_title, _icon, _flag, sendVerificationFlat, isDirectLogin: isDirectLogin); }, ).displayDialog(context); + } } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, null); @@ -372,6 +375,7 @@ class _VerifyLastLoginScreenState extends State { mobileLoginInfoListModel!.deviceToken!, Platform.isAndroid ? "android" : "ios"); AppState().setMemberInformationListModel = genericResponseModel!.memberInformationList?.first; + AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; if (genericResponseModel.errorMessage != null) { Utils.showToast(genericResponseModel.errorMessage ?? ""); // Navigator.pop(context); diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index c79f929..4d11bb8 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -137,6 +137,7 @@ class _DynamicInputScreenState extends State { getEitDffStructureList = abc; int index = getEitDffStructureList!.indexWhere((element) => element.sEGMENTNAME == segmentId); getEitDffStructureList![index].eSERVICESVS!.clear(); + getEitDffStructureList![index].eSERVICESDV = ESERVICESDV(); if (eServicesResponseModel.isNotEmpty) getEitDffStructureList![index].eSERVICESVS!.addAll(eServicesResponseModel); // getEitDffStructureList = genericResponseModel?.getEITDFFStructureList ?? []; //getEitDffStructureList = getEitDffStructureList!.where((element) => element.dISPLAYFLAG != "N").toList(); diff --git a/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart b/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart index 9b82d9d..5e3f749 100644 --- a/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart +++ b/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart @@ -37,7 +37,7 @@ class _AddItemDetailsFragmentState extends State { String itemTitle = ""; String itemDescription = ""; num itemPrice = 0; - String selectedItemCondition = "new"; + String selectedItemCondition = "1"; List getRegionsList = []; GetRegionsList selectedRegion = GetRegionsList(); @@ -88,16 +88,16 @@ class _AddItemDetailsFragmentState extends State { itemDescription = value; }, ).paddingOnly(top: 12), - LocaleKeys.itemCondition.tr().toText14().paddingOnly(top: 21), + LocaleKeys.expireAfter.tr().toText14().paddingOnly(top: 21), Row( children: [ - ShowRadio(title: LocaleKeys.newString.tr(), value: "new", groupValue: selectedItemCondition, selectedColor: MyColors.gradiantStartColor).onPress(() { - selectedItemCondition = "new"; + ShowRadio(title: LocaleKeys.oneWeek.tr(), value: "1", groupValue: selectedItemCondition, selectedColor: MyColors.gradiantStartColor).onPress(() { + selectedItemCondition = "1"; setState(() {}); }), 12.width, - ShowRadio(title: LocaleKeys.used.tr(), value: "used", groupValue: selectedItemCondition, selectedColor: MyColors.gradiantStartColor).onPress(() { - selectedItemCondition = "used"; + ShowRadio(title: LocaleKeys.twoWeek.tr(), value: "2", groupValue: selectedItemCondition, selectedColor: MyColors.gradiantStartColor).onPress(() { + selectedItemCondition = "2"; setState(() {}); }), ], @@ -166,8 +166,18 @@ class _AddItemDetailsFragmentState extends State { ); } + DateTime getEndDate() { + DateTime date = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day); + DateTime endDate; + if (selectedItemCondition == "1") { + return endDate = DateTime(date.year, date.month, date.day + 7); + } else { + return endDate = DateTime(date.year, date.month, date.day + 7); + } + } + ItemReviewModel getItemReviewObject() { - ItemReviewModel itemReviewModel = ItemReviewModel(itemTitle, itemDescription, selectedItemCondition, selectedRegion, itemPrice, images, widget.selectedSaleCategory); + ItemReviewModel itemReviewModel = ItemReviewModel(itemTitle, itemDescription, selectedItemCondition, selectedRegion, itemPrice, images, widget.selectedSaleCategory, getEndDate()); return itemReviewModel; } @@ -246,7 +256,7 @@ class _AddItemDetailsFragmentState extends State { Future getAdDetails() async { // todo need to change this method later , its not a good approach to do it like this. String details = await Utils.getStringFromPrefs(SharedPrefsConsts.editItemForSale); - if(details.isNotEmpty) { + if (details.isNotEmpty) { var body = json.decode(details); AddItemDetailsFragment.isUpdate = true; @@ -259,6 +269,7 @@ class _AddItemDetailsFragmentState extends State { selectedItemCondition = body["itemCondition"].toString().toLowerCase(); selectedRegionAd.regionID = body["selectedRegion"]["regionID"]; selectedRegionAd.regionName = body["selectedRegion"]["regionName"]; + selectedRegion = selectedRegionAd; itemPrice = body["itemPrice"]; selectedSaleCategoryAd.categoryID = body["selectedSaleCategory"]["categoryID"]; @@ -266,8 +277,8 @@ class _AddItemDetailsFragmentState extends State { if (body["itemPhotos"].length != 0) { images.add(body["itemPhotos"][0]); } - ItemReviewModel itemReviewModel = - ItemReviewModel(body["itemTitle"], body["itemDescription"], body["itemCondition"].toString().toLowerCase(), selectedRegionAd, body["itemPrice"], images, selectedSaleCategoryAd); + ItemReviewModel itemReviewModel = ItemReviewModel( + body["itemTitle"], body["itemDescription"], body["itemCondition"].toString().toLowerCase(), selectedRegionAd, body["itemPrice"], images, selectedSaleCategoryAd, getEndDate()); AddItemDetailsFragment.itemReviewModel = itemReviewModel; SelectCategoryFragment.selectedSaleCategory = selectedSaleCategoryAd; diff --git a/lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart b/lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart index 190460e..1e3581a 100644 --- a/lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart +++ b/lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart @@ -27,12 +27,13 @@ class ItemReviewFragment extends StatefulWidget { class _ItemReviewFragmentState extends State { ItemReviewModel? itemReviewModel; late bool isUpdate; - + String? validFor = ''; @override void initState() { itemReviewModel = AddItemDetailsFragment.itemReviewModel; itemReviewModel!.selectedSaleCategory = SelectCategoryFragment.selectedSaleCategory; isUpdate = AddItemDetailsFragment.isUpdate; + validFor = itemReviewModel?.itemCondition; super.initState(); } @@ -105,7 +106,7 @@ class _ItemReviewFragmentState extends State { size: 20, color: MyColors.redColor, ).paddingOnly(top: 21), - "This ad will be valid for 2 weeks after approval.".toText11(color: MyColors.redColor).paddingOnly(left: 10, right: 10), + "This ad will be valid for $validFor weeks after approval.".toText11(color: MyColors.redColor).paddingOnly(left: 10, right: 10), ], ), const Spacer(), diff --git a/lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart b/lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart index 02db148..ffce243 100644 --- a/lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart +++ b/lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart @@ -154,7 +154,7 @@ class _MyPostedAdsFragmentState extends State { List itemPhotos = []; itemPhotos.add(employeePostedAdsList[index].itemAttachments![0].content!.toString()); ItemReviewModel itemReviewModel = ItemReviewModel(employeePostedAdsList[index].title, employeePostedAdsList[index].description, employeePostedAdsList[index].status, - selectedRegion, employeePostedAdsList[index].quotePrice, itemPhotos, selectedSaleCategory); + selectedRegion, employeePostedAdsList[index].quotePrice, itemPhotos, selectedSaleCategory, employeePostedAdsList[index].endDate!); Utils.saveStringFromPrefs(SharedPrefsConsts.editItemForSale, jsonEncode(itemReviewModel.toJson())); Navigator.pushNamed(context, AppRoutes.addNewItemForSale, arguments: 1); }).expanded, @@ -188,6 +188,7 @@ class _MyPostedAdsFragmentState extends State { request.fields['ItgQuotePrice'] = employeePostedAds.quotePrice.toString(); request.fields['RegionID'] = employeePostedAds.regionID.toString(); request.fields['Itg_EndDate'] = employeePostedAds.endDate.toString(); + request.fields['endDate'] = employeePostedAds.endDate.toString(); request.fields['Channel'] = "31"; request.fields['ItgIsActive'] = "false"; request.fields['LogInToken'] = loginTokenID!; diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index e9f46d7..d980728 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -57,14 +57,14 @@ class _OffersAndDiscountsDetailsState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Hero( - tag: "ItemImage" + getOffersList[0].rowID!, + tag: "ItemImage" + getOffersList[0].offersDiscountId.toString()!, // transitionOnUserGestures: true, child: RepaintBoundary( key: _globalKey, child: ClipRRect( borderRadius: BorderRadius.circular(6), child: Image.network( - getOffersList[0].bannerImage!, + getOffersList[0].bannerImage ?? "", fit: BoxFit.contain, ), ).paddingAll(12), @@ -72,10 +72,10 @@ class _OffersAndDiscountsDetailsState extends State { ), 8.height, AppState().isArabic(context) - ? getOffersList[0].titleAR!.toText22(isBold: true, color: const Color(0xff2B353E)).center - : getOffersList[0].title!.toText22(isBold: true, color: const Color(0xff2B353E)).center, + ? getOffersList[0].titleAr!.toText22(isBold: true, color: const Color(0xff2B353E)).center + : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, Html( - data: AppState().isArabic(context) ? getOffersList[0].descriptionAR! : getOffersList[0].description ?? "", + data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", onLinkTap: (String? url, RenderContext context, Map attributes, _) { launchUrl(Uri.parse(url!)); }, @@ -127,7 +127,7 @@ class _OffersAndDiscountsDetailsState extends State { Directory tempDir = await getTemporaryDirectory(); File file = await File('${tempDir.path}/${DateTime.now().toString()}.png').create(); await file.writeAsBytes(pngBytes); - await Share.shareFiles([(file.path)], text: AppState().isArabic(context) ? getOffersList[0].titleAR : getOffersList[0].title); + await Share.shareFiles([(file.path)], text: AppState().isArabic(context) ? getOffersList[0].titleAr : getOffersList[0].titleEn); } catch (ex) { debugPrint(ex.toString()); } @@ -155,21 +155,21 @@ class _OffersAndDiscountsDetailsState extends State { mainAxisSize: MainAxisSize.min, children: [ Hero( - tag: "ItemImage" + getOffersList.rowID!, + tag: "ItemImage" + getOffersList.offersDiscountId.toString()!, transitionOnUserGestures: true, child: AspectRatio( aspectRatio: 148 / 127, child: ClipRRect( borderRadius: BorderRadius.circular(6), child: Image.network( - getOffersList.bannerImage!, + getOffersList.bannerImage ?? "", fit: BoxFit.contain, ), ), ), ), 5.height, - getOffersList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), + getOffersList.titleEn!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), // Html( // data: AppState().isArabic(context) ? getOffersList.descriptionAR! : getOffersList.description ?? "", // // onLinkTap: (String? url, RenderContext context, Map attributes, _) { @@ -178,7 +178,7 @@ class _OffersAndDiscountsDetailsState extends State { // ), // getOffersList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), // 16.height, - getOffersList.discount!.toText14(isBold: true, maxlines: 1), + getOffersList.discountDescription!.toText14(isBold: true, maxlines: 1), 8.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -195,11 +195,12 @@ class _OffersAndDiscountsDetailsState extends State { void getOfferLocation() {} Widget checkDate(String endDate) { - DateTime endDateObj = DateFormat("yyyy-MM-dd").parse(endDate); - if (endDateObj.isAfter(DateTime.now())) { - return "Offer Valid".toText16(isBold: true, color: MyColors.greenColor); - } else { - return "Offer Expired".toText16(isBold: true, color: MyColors.redColor); - } + // this new api always return valid offer and discount so commenting the expired one + // DateTime endDateObj = DateFormat("yyyy-MM-dd").parse(endDate); + // if (endDateObj.isAfter(DateTime.now())) { + return "Offer Valid".toText16(isBold: true, color: MyColors.greenColor); + // } else { + // return "Offer Expired".toText16(isBold: true, color: MyColors.redColor); + // } } } diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart index c62cc9c..fd2c19e 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart @@ -157,22 +157,22 @@ class _OffersAndDiscountsHomeState extends State { mainAxisSize: MainAxisSize.min, children: [ Hero( - tag: "ItemImage" + getOffersList.rowID!, + tag: "ItemImage" + getOffersList.offersDiscountId.toString()!, transitionOnUserGestures: true, child: AspectRatio( aspectRatio: 118 / 127, child: ClipRRect( borderRadius: BorderRadius.circular(6), child: Image.network( - getOffersList.bannerImage!, + getOffersList.bannerImage ?? "", fit: BoxFit.contain, ), ), ), ), AppState().isArabic(context) - ? getOffersList.titleAR!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1) - : getOffersList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), + ? getOffersList.titleAr!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1) + : getOffersList.titleEn!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), // Html( // data: AppState().isArabic(context) ? getOffersList.descriptionAR! : getOffersList.description ?? "", // // onLinkTap: (String? url, RenderContext context, Map attributes, _) { @@ -181,7 +181,7 @@ class _OffersAndDiscountsHomeState extends State { // ), // getOffersList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), // 8.height, - getOffersList.discount!.toText14(isBold: true, maxlines: 1), + getOffersList.discountDescription!.toText14(isBold: true, maxlines: 1), 20.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -199,9 +199,9 @@ class _OffersAndDiscountsHomeState extends State { results = getOffersList; } else { if (AppState().isArabic(context)) { - results = getOffersList.where((offer) => offer.titleAR!.toLowerCase().contains(enteredKeyword.toLowerCase())).toList(); + results = getOffersList.where((offer) => offer.titleAr!.toLowerCase().contains(enteredKeyword.toLowerCase())).toList(); } else { - results = getOffersList.where((offer) => offer.title!.toLowerCase().contains(enteredKeyword.toLowerCase())).toList(); + results = getOffersList.where((offer) => offer.titleEn!.toLowerCase().contains(enteredKeyword.toLowerCase())).toList(); } } setState(() { @@ -218,7 +218,7 @@ class _OffersAndDiscountsHomeState extends State { getOffersList.forEach((element) { if (counter <= 4) { - if (element.rowID != offersListModelObj.rowID) { + if (element.offersDiscountId != offersListModelObj.offersDiscountId) { getOffersDetailList.add(element); counter++; } @@ -229,12 +229,13 @@ class _OffersAndDiscountsHomeState extends State { } Widget checkDate(String endDate) { - DateTime endDateObj = DateFormat("yyyy-MM-dd").parse(endDate); - if (endDateObj.isAfter(DateTime.now())) { - return LocaleKeys.offerValid.tr().toText14(isBold: true, color: MyColors.greenColor); - } else { - return LocaleKeys.offerExpired.tr().toText14(isBold: true, color: MyColors.redColor); - } + // this new api always return valid offer and discount so commenting the expired one + // DateTime endDateObj = DateFormat("yyyy-MM-dd").parse(endDate); + // if (endDateObj.isAfter(DateTime.now())) { + return LocaleKeys.offerValid.tr().toText14(isBold: true, color: MyColors.greenColor); + // } else { + // return LocaleKeys.offerExpired.tr().toText14(isBold: true, color: MyColors.redColor); + // } } void getCategoriesListAPI() async { diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index 6b89c42..03d4847 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -12,6 +12,7 @@ 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/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/privilege_list_model.dart'; 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/dialogs/confirm_dialog.dart'; @@ -47,7 +48,7 @@ class _MarkAttendanceWidgetState extends State { void checkAttendanceAvailability() async { bool isAvailable = await NfcManager.instance.isAvailable(); setState(() { - AppState().privilegeListModel!.forEach((element) { + AppState().privilegeListModel!.forEach((PrivilegeListModel element) { if (element.serviceName == "enableNFC") { if (isAvailable) if (element.previlege ?? false) isNfcEnabled = true; } else if (element.serviceName == "enableQR") { @@ -144,6 +145,7 @@ class _MarkAttendanceWidgetState extends State { Future performNfcAttendance(DashboardProviderModel model, {String lat = "0", String lng = "0"}) async { if (Platform.isIOS) { + Utils.readNFc(onRead: (String nfcId) async { Utils.showLoading(context); try { @@ -152,7 +154,7 @@ class _MarkAttendanceWidgetState extends State { Utils.hideLoading(context); showDialog( context: context, - builder: (cxt) => ConfirmDialog( + builder: (BuildContext cxt) => ConfirmDialog( message: g?.errorEndUserMessage ?? "Unexpected error occurred", onTap: () { Navigator.pop(context); @@ -172,9 +174,7 @@ class _MarkAttendanceWidgetState extends State { } } catch (ex) { Utils.hideLoading(context); - Utils.handleException(ex, context, (msg) { - Utils.confirmDialog(context, msg); - }); + Utils.handleException(ex, context, null); } }); } else { @@ -186,7 +186,7 @@ class _MarkAttendanceWidgetState extends State { Utils.hideLoading(context); showDialog( context: context, - builder: (cxt) => ConfirmDialog( + builder: (BuildContext cxt) => ConfirmDialog( message: g?.errorEndUserMessage ?? "Unexpected error occurred", onTap: () { Navigator.pop(context); @@ -206,7 +206,7 @@ class _MarkAttendanceWidgetState extends State { } catch (ex) { print(ex); Utils.hideLoading(context); - Utils.handleException(ex, context, (msg) { + Utils.handleException(ex, context, (String msg) { Utils.confirmDialog(context, msg); }); } @@ -228,19 +228,23 @@ class _MarkAttendanceWidgetState extends State { } if (isConnected) { - if (Platform.isIOS) { - await closeWifiRequest(); - await Future.delayed(Duration(seconds: 6)); - } else { - await WiFiForIoTPlugin.forceWifiUsage(true); - } + // if (Platform.isIOS) { + // await closeWifiRequest(); + // await Future.delayed(Duration(seconds: 6)); + // } else { + // await WiFiForIoTPlugin.forceWifiUsage(true); + // } + await WiFiForIoTPlugin.forceWifiUsage(true); + await Future.delayed(const Duration(seconds: 6)); try { GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 3, nfcValue: "", isGpsRequired: isWifiLocationEnabled, lat: lat, long: lng); bool status = await model.fetchAttendanceTracking(context); Utils.hideLoading(context); - if (Platform.isAndroid) { - await closeWifiRequest(); - } + // if (Platform.isAndroid) { + // await closeWifiRequest(); + // } + + await closeWifiRequest(); showMDialog( context, backgroundColor: Colors.transparent, @@ -250,9 +254,7 @@ class _MarkAttendanceWidgetState extends State { } catch (ex) { await closeWifiRequest(); Utils.hideLoading(context); - Utils.handleException(ex, context, (msg) { - Utils.confirmDialog(context, msg); - }); + Utils.handleException(ex, context, null); } } else { Utils.hideLoading(context); @@ -270,7 +272,7 @@ class _MarkAttendanceWidgetState extends State { Future performQrCodeAttendance(DashboardProviderModel model, {String lat = "0", String lng = "0"}) async { var qrCodeValue = await Navigator.of(context).push( MaterialPageRoute( - builder: (context) => QrScannerDialog(), + builder: (BuildContext context) => QrScannerDialog(), ), ); if (qrCodeValue != null) { @@ -288,9 +290,7 @@ class _MarkAttendanceWidgetState extends State { } catch (ex) { print(ex); Utils.hideLoading(context); - Utils.handleException(ex, context, (msg) { - Utils.confirmDialog(context, msg); - }); + Utils.handleException(ex, context, null); } } } @@ -304,9 +304,7 @@ class _MarkAttendanceWidgetState extends State { } catch (ex) { print(ex); Utils.hideLoading(context); - Utils.handleException(ex, context, (msg) { - Utils.confirmDialog(context, msg); - }); + Utils.handleException(ex, context, null); } } diff --git a/pubspec.yaml b/pubspec.yaml index f8748e6..367db22 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -67,7 +67,7 @@ dependencies: month_year_picker: ^0.2.0+1 month_picker_dialog_2: 0.5.5 open_file: ^3.2.1 - wifi_iot: ^0.3.16 + wifi_iot: ^0.3.18 flutter_html: ^3.0.0-alpha.6 # flutter_barcode_scanner: ^2.0.0 qr_code_scanner: ^1.0.0 @@ -92,7 +92,8 @@ dependencies: swipe_to: ^1.0.2 flutter_webrtc: ^0.9.16 camera: ^0.10.0+4 - #flutter_local_notifications: any + flutter_local_notifications: any + #firebase_analytics: any #Chat Voice Message Recoding & Play audio_waveforms: ^0.1.5+1