From cbddd807d426b272c86f949f520d0d902d0790f7 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 23 Oct 2025 15:39:38 +0300 Subject: [PATCH 01/31] internal audit design complete --- lib/controllers/api_routes/urls.dart | 4 +- .../providers/api/all_requests_provider.dart | 10 + .../providers/api/user_provider.dart | 1 + .../widgets/request_category_list.dart | 4 + lib/main.dart | 12 + lib/models/enums/user_types.dart | 3 +- lib/models/user.dart | 5 + .../service_request_detail_view.dart | 78 ++--- .../create_system_internal_audit_form.dart | 196 +++++++++++ .../pages/internal_audit_detail_page.dart | 178 ++++++++++ .../pages/internal_audit_item_view.dart | 113 ++++++ .../pages/update_internal_audit_page.dart | 327 ++++++++++++++++++ .../internal_audit_finding_type_provider.dart | 34 ++ .../create_request-type_bottomsheet.dart | 11 +- .../my_request/all_requests_filter_page.dart | 4 + .../my_request/my_requests_page.dart | 18 + .../requests/request_paginated_listview.dart | 12 +- .../widgets/request_item_view_list.dart | 8 +- pubspec.lock | 8 + 19 files changed, 975 insertions(+), 51 deletions(-) create mode 100644 lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart create mode 100644 lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart create mode 100644 lib/modules/internal_audit_module/pages/internal_audit_item_view.dart create mode 100644 lib/modules/internal_audit_module/pages/update_internal_audit_page.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 89b58897..49ce0e4d 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,8 +4,8 @@ class URLs { static const String appReleaseBuildNumber = "26"; // static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 470f803d..71d1f46f 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -133,15 +133,25 @@ class AllRequestsProvider extends ChangeNotifier { List getStatues(BuildContext context) { List list = [1, 2, 3, 4]; + //TODO need to refactor this code .... if (context.userProvider.isAssessor) { list = [9]; return list; } + if (context.userProvider.isQualityUser) { + //TODO Need to replace with actual number.. + // list = [10]; + list = [1]; + return list; + } if (!context.userProvider.isNurse) { list.add(5); } + if (context.userProvider.isEngineer) { + list.add(10); + } list.add(6); // task module if (context.settingProvider.isUserFlowMedical && !context.userProvider.isNurse) { diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart index f8c93d63..5d1495d5 100644 --- a/lib/controllers/providers/api/user_provider.dart +++ b/lib/controllers/providers/api/user_provider.dart @@ -45,6 +45,7 @@ class UserProvider extends ChangeNotifier { bool get isNurse => user!.type == UsersTypes.normal_user; bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl; + bool get isQualityUser => user!.type == UsersTypes.qualityUser; VerifyOtpModel _verifyOtpModel = VerifyOtpModel(); SwipeTransaction _swipeTransactionModel = SwipeTransaction(); diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index f2df78fb..c92ab6b2 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -51,6 +52,9 @@ class RequestCategoryList extends StatelessWidget { return TaskRequestItemView(requestData: request); case 9: return TrafRequestItemView(requestData: request); + //TODO need to verify this ... + case 10: + return InternalAuditItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/main.dart b/lib/main.dart index 70880a3b..2ee8fd64 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,6 +29,10 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/modules/traf_module/traf_request_provider.dart'; @@ -98,6 +102,8 @@ import 'controllers/providers/api/gas_refill_comments.dart'; import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/settings/setting_provider.dart'; import 'dashboard_latest/dashboard_provider.dart'; +import 'modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'new_views/pages/gas_refill_request_form.dart'; import 'providers/lookups/classification_lookup_provider.dart'; import 'providers/lookups/department_lookup_provider.dart'; @@ -285,6 +291,9 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => PpmServiceProvider()), ChangeNotifierProvider(create: (_) => CommentsProvider()), ChangeNotifierProvider(create: (_) => GasRefillCommentsProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditCheckListProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditFindingTypeProvider()), ///todo deleted //ChangeNotifierProvider(create: (_) => RequestStatusProvider()), @@ -352,6 +361,9 @@ class MyApp extends StatelessWidget { ProfilePage.id: (_) => const ProfilePage(), ReportBugPage.id: (_) => const ReportBugPage(), HelpCenterPage.id: (_) => const HelpCenterPage(), + CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(), + CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(), + UpdateInternalAuditPage.id: (_) => const UpdateInternalAuditPage(), // SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), // SwipeHistoryView.routeName: (_) => const SwipeHistoryView(), }, diff --git a/lib/models/enums/user_types.dart b/lib/models/enums/user_types.dart index 63f1d9d7..cd6b5f13 100644 --- a/lib/models/enums/user_types.dart +++ b/lib/models/enums/user_types.dart @@ -3,5 +3,6 @@ enum UsersTypes { normal_user, // 1 nurse, // 1 assessor, - assessorTl + assessorTl, + qualityUser } diff --git a/lib/models/user.dart b/lib/models/user.dart index 3ffc5b29..2c4f3e19 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,3 +1,4 @@ +import 'dart:developer'; import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -97,6 +98,8 @@ class User { UsersTypes? get type { switch (userRoles?.first.value) { + case "R-7": // Head Nurse Role + return UsersTypes.qualityUser; case "R-6": return UsersTypes.engineer; case "R-7": // Nurse Role @@ -107,6 +110,8 @@ class User { return UsersTypes.assessor; case "R-19": // Head Nurse Role return UsersTypes.assessorTl; + //TODO need to replace with actual data when confirm + default: return null; } diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart index cb63de73..8b8da1cd 100644 --- a/lib/modules/cm_module/views/components/service_request_detail_view.dart +++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart @@ -72,52 +72,44 @@ class _ServiceRequestDetailViewState extends State { ? const CircularProgressIndicator(color: AppColor.primary10).center : requestProvider.currentWorkOrder == null ? const NoDataFound() - : Stack( - children: [ - Column( + : Column( + children: [ + SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider), - initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider), - 12.height, - assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider), - 12.height, - if (context.userProvider.user!.type == UsersTypes.engineer && - !requestProvider.isReadOnlyRequest && - requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[ - costCard(context, requestProvider), - 12.height, - ], - contactInfoCard(context, requestProvider.currentWorkOrder!.data!), - 20.height, - ], - ), - ).expanded, - SafeArea( - top: false, - right: false, - left: false, - child: FooterActionButton.requestDetailsFooterWidget( - workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!, - status: requestProvider.currentWorkOrder?.data?.status, - isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null, - activities: requestProvider.currentWorkOrder!.data?.activities ?? [], - userProvider: _userProvider, - context: context), - ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider), + initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider), + 12.height, + assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider), + 12.height, + if (context.userProvider.user!.type == UsersTypes.engineer && + !requestProvider.isReadOnlyRequest && + requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[ + costCard(context, requestProvider), + 12.height, + ], + contactInfoCard(context, requestProvider.currentWorkOrder!.data!), + 20.height, ], ), - //no need to show timer as discussed with backend - // if (requestProvider.timer != null && requestProvider.timer!.isActive) ...[ - // const TimerWidget(), - // ] - ], - ); + ).expanded, + SafeArea( + top: false, + right: false, + left: false, + child: FooterActionButton.requestDetailsFooterWidget( + workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!, + status: requestProvider.currentWorkOrder?.data?.status, + isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null, + activities: requestProvider.currentWorkOrder!.data?.activities ?? [], + userProvider: _userProvider, + context: context), + ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + ], + ); }); } diff --git a/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart new file mode 100644 index 00000000..051e2dfd --- /dev/null +++ b/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart @@ -0,0 +1,196 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; + +class CreateSystemInternalAuditForm extends StatefulWidget { + static const String id = "/create-system-audit-view"; + + const CreateSystemInternalAuditForm({Key? key}) : super(key: key); + + @override + _CreateSystemInternalAuditFormState createState() => _CreateSystemInternalAuditFormState(); +} +//TODO remove unnecessary code + +class _CreateSystemInternalAuditFormState extends State with TickerProviderStateMixin { + late TextEditingController _commentController; + late InternalAuditProvider _internalAuditProvider; + final InternalAuditModel _internalAuditModel = InternalAuditModel(); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + final List _deviceImages = []; + bool showLoading = false; + + @override + void initState() { + super.initState(); + _commentController = TextEditingController(); + _internalAuditProvider = Provider.of(context, listen: false); + } + + @override + void dispose() { + _commentController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: 'System Internal Audit Checklist'.addTranslation), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoCompletePartsField( + assetId: 0, + clearAfterPick: false, + byName: true, + initialValue: _internalAuditModel.woOrderNo ?? "", + onPick: (part) { + _internalAuditModel.woOrderNo = part.name; + setState(() {}); + }, + ), + 12.height, + // if(_internalAuditModel.woOrderNo!=null) + _workOrderInfoWidget(context), + 12.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Finding Type'.addTranslation, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: _internalAuditModel.auditCheckList, + onSelect: (status) { + if (status != null) { + _internalAuditModel.auditCheckList = status; + setState(() {}); + } + }, + ), + 12.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: 'Finding Description'.addTranslation, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + showShadow: false, + onSaved: (text) {}, + ), + 16.height, + AttachmentPicker( + label: context.translation.attachments, + attachment: _deviceImages, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), + ), + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: context.translation.submitRequest, + onPressed: _submit, + ), + ), + ], + ), + ), + ); + } + + Future _submit() async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + List attachement = []; + for (var item in _deviceImages) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + } + // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + } + } + + Widget _workOrderInfoWidget(BuildContext context) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: showLoading ? Colors.white : const Color(0xffF4F6FC), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: const Color(0xff212936).withOpacity(.03), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Text( + "WO Type", + style: TextStyle( + fontSize: 14.toScreenWidth, + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + color: Colors.black87, + decoration: TextDecoration.none, + ), + ).toShimmer(isShow: showLoading, context: context).expanded, + const Icon( + Icons.info, + color: Color(0xff7D859A), + size: 20, + ), + ], + ), + 6.height, + "${context.translation.site}: ${'ABC'}".bodyText(context), + "${'Eng. Name'.addTranslation}: ${'ABC'}".bodyText(context), + "${'Asset Name'.addTranslation}: ${'ABC'}".bodyText(context), + "${context.translation.model}: ${'ABC'}".bodyText(context), + "${context.translation.manufacture}: ${'ABC'}".bodyText(context), + "${'SN'.addTranslation}: ${'ABC'}".bodyText(context), + "${context.translation.assetNo}: ${'ABC'}".bodyText(context), + ], + ), + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart new file mode 100644 index 00000000..dd36f431 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart @@ -0,0 +1,178 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; + +class InternalAuditDetailPage extends StatefulWidget { + static const String id = "/details-internal-audit"; + + final int auditId; + + InternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); + + @override + _InternalAuditDetailPageState createState() { + return _InternalAuditDetailPageState(); + } +} + +class _InternalAuditDetailPageState extends State { + bool isWoType = true; + + @override + void initState() { + super.initState(); + //TODO need to get and assign data . + // Provider.of(context, listen: false).getInternalAuditById(widget.auditId); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + //TODO need to check when implementing provider needed or not . + return Scaffold( + appBar: const DefaultAppBar(title: "Request Details"), + body: Selector( + selector: (_, provider) => provider.isLoading, + builder: (_, isLoading, __) { + if (isLoading) return const ALoading(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + assetInformation(), + 8.height, + isWoType ? workOrderInformation() : requestDetails(), + 8.height, + //TODO need to check for comments + // if (model.comment?.isNotEmpty ?? false) ...[ + const Divider().defaultStyle(context), + Text( + "Comments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + // model.comment!.bodyText(context), + // 8.height, + // ], + //TODO need to check for attachments + // if ( _model.attachment.isNotEmpty) ...[ + const Divider().defaultStyle(context), + Text( + "Attachments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + // FilesList(images: _model.attachment?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + // ], + ], + ).paddingAll(0).toShadowContainer(context), + ).expanded, + if (context.userProvider.isEngineer) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: "Update", + onPressed: () { + Navigator.pushNamed(context, UpdateInternalAuditPage.id); + }), + ), + ], + ); + }, + )); + } + + Widget workOrderInformation() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "WO Info", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.woNumber}: ${'-'}'.bodyText(context), + '${'WO Type'.addTranslation}: ${'-'}'.bodyText(context), + '${context.translation.site}: ${'-'}'.bodyText(context), + '${context.translation.assetName}: ${'-'}'.bodyText(context), + '${context.translation.manufacture}: ${'-'}'.bodyText(context), + '${context.translation.model}: ${'-'}'.bodyText(context), + ], + ); + } + + Widget requestDetails() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "Request Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + checklistWidget(value: 'Asset Tag'.addTranslation), + checklistWidget(value: 'Expired PM Tag'.addTranslation), + ], + ); + } + + Widget assetInformation() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Asset Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.assetName}: ${'-'}'.bodyText(context), + '${context.translation.assetNo}: ${'-'}'.bodyText(context), + '${context.translation.manufacture}: ${'-'}'.bodyText(context), + '${context.translation.model}: ${'-'}'.bodyText(context), + ], + ); + } + + Widget checklistWidget({required String value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + value: true, + activeColor: AppColor.neutral120, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(horizontal: -4, vertical: -3), + onChanged: (value) {}, + ), + value.bodyText(context), + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart new file mode 100644 index 00000000..20a81aaf --- /dev/null +++ b/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_detail_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class InternalAuditItemView extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const InternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + //TODO need to refactor this code repetation @waseem + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestData!.statusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), + ), + 1.width.expanded, + Text( + requestData!.transactionDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + // (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), + ("Internal Audit Request").heading5(context), + // infoWidget(label: context.translation.requestType, value: requestData?.requestTypeName, context: context), + + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + // (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), + ("Internal Audit Request").heading5(context), + 8.height, + // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} diff --git a/lib/modules/internal_audit_module/pages/update_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/update_internal_audit_page.dart new file mode 100644 index 00000000..a5b23624 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/update_internal_audit_page.dart @@ -0,0 +1,327 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; +import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart'; + +class UpdateInternalAuditPage extends StatefulWidget { + static const String id = "update-internal-audit"; + final model; + + const UpdateInternalAuditPage({this.model, Key? key}) : super(key: key); + + @override + State createState() => _UpdateInternalAuditPageState(); +} + +class _UpdateInternalAuditPageState extends State { + final bool _isLoading = false; + double totalWorkingHours = 0.0; + late UserProvider _userProvider; + + // GasRefillDetails _currentDetails = GasRefillDetails(); + final TextEditingController _commentController = TextEditingController(); + final TextEditingController _workingHoursController = TextEditingController(); + + // final GasRefillModel _formModel = GasRefillModel(gasRefillDetails: []); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool _firstTime = true; + List _attachments = []; + List timerList = []; + + @override + void initState() { + super.initState(); + // if (widget.gasRefillModel != null) { + // _formModel.fromGasRefillModel(widget.gasRefillModel!); + // _commentController.text = _formModel.techComment ?? ""; + // calculateWorkingTime(); + // try { + // _deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty); + // _currentDetails.deliverdQty = _deliveredQuantity!.value; + // } catch (ex) {} + // } + // if (_formModel.gasRefillAttachments != null && _formModel.gasRefillAttachments!.isNotEmpty) { + // _attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.attachmentName!)).toList()); + // } + } + + void calculateWorkingTime() { + // final timers = _formModel.gasRefillTimers ?? []; + // totalWorkingHours = timers.fold(0.0, (sum, item) { + // if (item.startDate == null || item.endDate == null) return sum; + // try { + // final start = DateTime.parse(item.startDate!); + // final end = DateTime.parse(item.endDate!); + // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + // return sum + diffInHours; + // } catch (_) { + // return sum; + // } + // }); + // + // timerList = timers.map((e) { + // return TimerHistoryModel( + // id: e.id, + // startTime: e.startDate, + // endTime: e.endDate, + // workingHours: e.workingHours, + // ); + // }).toList(); + } + + @override + void setState(VoidCallback fn) { + if (mounted) super.setState(() {}); + } + + _onSubmit(BuildContext context, int status) async { + bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + + // if (isTimerPickerEnable) { + // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.gasRefillTimePicker == null) { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // } else { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // + // if (_currentDetails.deliverdQty == null) { + // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); + // return false; + // } + // _formModel.gasRefillDetails = []; + // _formModel.gasRefillDetails?.add(_currentDetails); + // + // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; + // if (_formModel.gasRefillTimePicker != null) { + // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null + // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // } + // _formModel.timerModelList?.forEach((timer) { + // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: timer.startAt!.toIso8601String(), // Handle potential null + // endDate: timer.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // }); + // _formModel.gasRefillAttachments = []; + // for (var item in _attachments) { + // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; + // _formModel.gasRefillAttachments?.add(GasRefillAttachments( + // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); + // } + + // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { + // Navigator.pop(context); + // if (success) { + // if (status == 1) { + // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + // // when click complete then this request remove from the list and status changes to closed.. + // _gasRefillProvider?.reset(); + // allRequestsProvider.getAllRequests(context, typeTransaction: 2); + // } + // Navigator.pop(context); + // } + // }); + } + + @override + void dispose() { + _commentController.dispose(); + _workingHoursController.dispose(); + super.dispose(); + } + + void updateTimer({TimerModel? timer}) { + // _formModel.timer = timer; + // if (timer?.startAt != null && timer?.endAt != null) { + // _formModel.timerModelList = _formModel.timerModelList ?? []; + // _formModel.timerModelList!.add(timer!); + // } + // notifyListeners(); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + if (_firstTime) { + String? clientName; + // if (widget.gasRefillModel != null) { + // _gasRefillProvider!.expectedDateTime = DateTime.tryParse(_formModel.expectedDate ?? ""); + // _formModel.timer = TimerModel(startAt: DateTime.tryParse(widget.gasRefillModel?.startDate ?? ""), endAt: DateTime.tryParse(widget.gasRefillModel?.endDate ?? "")); + // } else { + // _formModel.timer = null; + // } + } + + return Scaffold( + appBar: DefaultAppBar( + title: 'Update Information'.addTranslation, + onWillPopScope: () { + _onSubmit(context, 0); + }, + ), + key: _scaffoldKey, + body: Form( + key: _formKey, + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + AppTextFormField( + labelText: 'Debrief'.addTranslation, + textInputType: TextInputType.multiline, + hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + alignLabelWithHint: true, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + controller: _commentController, + onChange: (value) {}, + onSaved: (value) {}, + ), + 8.height, + _timerWidget(context, totalWorkingHours), + 16.height, + AttachmentPicker( + label: context.translation.attachFiles, + attachment: _attachments, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset( + color: AppColor.primary10, + ), + ), + 8.height, + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + AppFilledButton( + label: context.translation.save, + buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, + textColor: context.isDark ? AppColor.white10 : AppColor.black10, + onPressed: () => _onSubmit(context, 0), + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: () => _onSubmit(context, 1), + ).expanded, + ], + ), + ), + ], + )), + ), + ).handlePopScope( + cxt: context, + onSave: () { + _onSubmit(context, 0); + }); + } + + Widget _timerWidget(BuildContext context, double totalWorkingHours) { + TimerModel? timer = TimerModel(); + TimerModel? timerPicker; + List? timerModelList = []; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + AppTimer( + label: context.translation.workingHours, + timer: timer, + // pickerFromDate: DateTime.tryParse(widget.gasRefillModel?.createdDate ?? ''), + pickerFromDate: DateTime.tryParse(''), + pickerTimer: timerPicker, + onPick: (time) { + //timerPicker = time; + }, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + // color: AppColor.neutral100, + borderRadius: BorderRadius.circular(10), + ), + timerProgress: (isRunning) {}, + onChange: (timer) async { + updateTimer(timer: timer); + return true; + }, + ), + if (totalWorkingHours > 0.0) ...[ + 12.height, + WorkingTimeTile( + timerList: timerList, + totalWorkingTime: totalWorkingHours, + ), + ], + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart new file mode 100644 index 00000000..c9ee41a8 --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart @@ -0,0 +1,34 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class InternalAuditFindingTypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading ?? false) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} diff --git a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart index cca09e6e..1988336f 100644 --- a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart +++ b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; @@ -7,6 +9,8 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -90,8 +94,11 @@ class CreateRequestModel { static List requestsList(BuildContext context) { List list = []; - - if (context.userProvider.isAssessor) { + log('user type is ${context.userProvider.isQualityUser}'); + if (context.userProvider.isQualityUser) { + list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id)); + list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id)); + } else if (context.userProvider.isAssessor) { list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); } else if (context.userProvider.isEngineer) { if (Provider.of(context, listen: false).engineerCanCreateCM) { diff --git a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart index c1c4729f..e6521f23 100644 --- a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart +++ b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart @@ -70,6 +70,7 @@ class _AllRequestsFilterPageState extends State { if (isEngineer) { types[context.translation.recurrentWo] = 5; + types["Internal Audit".addTranslation] = 10; } if (context.settingProvider.isUserFlowMedical) { @@ -79,8 +80,11 @@ class _AllRequestsFilterPageState extends State { if (!isEngineer) { types['TRAF'] = 9; } + if (context.userProvider.isAssessor) { types = {"TRAF": 9}; + }if (context.userProvider.isQualityUser) { + types = {"Internal Audit": 10}; } final statuses = { diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 8ac38ab6..30f86273 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -1,5 +1,7 @@ //request main page +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; @@ -40,9 +42,11 @@ class _MyRequestsPageState extends State { Request(2, context.translation.gasRefill), Request(3, context.translation.transferAsset), Request(4, context.translation.preventiveMaintenance), + ]; if (Provider.of(context, listen: false).user!.type != UsersTypes.normal_user) { requestsList.add(Request(5, context.translation.recurrentWo)); + } //TODO unCommit this to enable task requestsList.add(Request(6, context.translation.taskRequest)); @@ -53,6 +57,11 @@ class _MyRequestsPageState extends State { if (context.userProvider.user!.type == UsersTypes.normal_user) { requestsList.add(Request(9, 'TRAF')); } + if (context.userProvider.isEngineer) { + //TODO need to replace with actual number. + // requestsList.add(Request(10, 'Internal Audit')); + requestsList.add(Request(1, 'Internal Audit')); + } if (context.userProvider.isAssessor) { requestsList = [ @@ -60,6 +69,15 @@ class _MyRequestsPageState extends State { Request(9, 'TRAF'), ]; } + if (context.userProvider.isQualityUser) { + requestsList = [ + Request(null, context.translation.allWorkOrder), + //TODO need to replace with actual number. + + // Request(10, 'Internal Audit'), + Request(1, 'Internal Audit'), + ]; + } _provider = Provider.of(context, listen: false); _provider!.reset(); diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index d3064427..7b172e50 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -46,6 +47,7 @@ class RequestPaginatedListview extends StatelessWidget { } Widget _buildRequestItem(Data request) { + //TODO need to replace with switch statement bool isServiceRequest = request.transactionNo == 1; bool isGasRefill = request.transactionNo == 2; bool isAssetTransfer = request.transactionNo == 3; @@ -53,6 +55,7 @@ class RequestPaginatedListview extends StatelessWidget { bool isRecurrentTask = request.transactionNo == 5; bool isTask = request.transactionNo == 6; bool isTRAF = request.transactionNo == 9; + bool isInternalAudit = request.transactionNo == 10; if (isServiceRequest) { return ServiceRequestItemView(requestData: request, refreshData: false); @@ -66,9 +69,14 @@ class RequestPaginatedListview extends StatelessWidget { return RecurrentWoItemView(requestData: request); } else if (isTask) { return TaskRequestItemView(requestData: request); - } else if (isTRAF) { + } + else if (isTRAF) { return TrafRequestItemView(requestData: request); - } else { + } + else if (isInternalAudit) { + return InternalAuditItemView(requestData: request); + } + else { return Container( height: 100, width: double.infinity, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index e29703d4..08b1f51a 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -4,6 +4,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -29,8 +30,10 @@ class RequestItemViewList extends StatelessWidget { itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); switch (list[index].transactionType) { + // case 1: + // return ServiceRequestItemView(requestDetails: list[index]); case 1: - return ServiceRequestItemView(requestDetails: list[index]); + return InternalAuditItemView(requestDetails: list[index]); case 2: return GasRefillItemView(requestDetails: list[index]); case 3: @@ -45,6 +48,9 @@ class RequestItemViewList extends StatelessWidget { return TaskRequestItemView(requestDetails: list[index]); case 9: return TrafRequestItemView(requestDetails: list[index]); + //Need to verify the type No.. + case 10: + return InternalAuditItemView(requestDetails: list[index]); default: Container( height: 100, diff --git a/pubspec.lock b/pubspec.lock index 701decdc..fdc4903d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -177,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.1" + clipboard: + dependency: "direct main" + description: + name: clipboard + sha256: "1920c0337f8808be4166c5f1b236301ff381ef69633b0757c502d97f1f740102" + url: "https://pub.dev" + source: hosted + version: "2.0.2" clock: dependency: transitive description: From 09843a9625ac0bfbcf073bca35a10a278b56f5a0 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 28 Oct 2025 10:20:07 +0300 Subject: [PATCH 02/31] Ui Changes --- .../models/internal_audit_model.dart | 29 ++++ .../create_equipment_internal_audit_form.dart | 138 ++++++++++++++++++ .../internal_audit_checklist_provider.dart | 36 +++++ .../provider/internal_audit_provider.dart | 42 ++++++ 4 files changed, 245 insertions(+) create mode 100644 lib/modules/internal_audit_module/models/internal_audit_model.dart create mode 100644 lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_provider.dart diff --git a/lib/modules/internal_audit_module/models/internal_audit_model.dart b/lib/modules/internal_audit_module/models/internal_audit_model.dart new file mode 100644 index 00000000..693b384d --- /dev/null +++ b/lib/modules/internal_audit_module/models/internal_audit_model.dart @@ -0,0 +1,29 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/fault_description.dart'; +import 'package:test_sa/models/lookup.dart'; + +class InternalAuditModel { + String? id; + int? deviceId; + String? deviceArName; + String? woOrderNo; + List? devicePhotos; + Lookup? auditCheckList; + String? comments; + Asset? device; + + InternalAuditModel({ + this.id, + this.deviceArName, + this.devicePhotos, + this.deviceId, + this.woOrderNo, + this.comments, + }); + +} + diff --git a/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart new file mode 100644 index 00000000..83655836 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart @@ -0,0 +1,138 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; + +class CreateEquipmentInternalAuditForm extends StatefulWidget { + static const String id = "/create-internal-audit-view"; + + const CreateEquipmentInternalAuditForm({Key? key}) : super(key: key); + + @override + _CreateEquipmentInternalAuditFormState createState() => _CreateEquipmentInternalAuditFormState(); +} + +class _CreateEquipmentInternalAuditFormState extends State with TickerProviderStateMixin { + late TextEditingController _commentController; + final InternalAuditModel _internalAuditModel = InternalAuditModel(); + final List _deviceImages = []; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + super.initState(); + _commentController = TextEditingController(); + } + + @override + void dispose() { + _commentController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: 'Equipment Internal Audit Checklist'.addTranslation), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AssetPicker( + device: _internalAuditModel.device, + borderColor: AppColor.black20, + buttonColor: AppColor.white936, + onPick: (asset) async { + _internalAuditModel.device = asset; + setState(() {}); + }, + ), + 16.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Internal Audit Checklist'.addTranslation, + showShadow: false, + initialValue: _internalAuditModel.auditCheckList, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (status) { + if (status != null) { + _internalAuditModel.auditCheckList = status; + setState(() {}); + } + }, + ), + 16.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: 'Remarks'.addTranslation, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + showShadow: false, + onSaved: (text) {}, + ), + 16.height, + AttachmentPicker( + label: context.translation.attachments, + attachment: _deviceImages, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), + ), + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(label: context.translation.submitRequest, buttonColor: AppColor.primary10, onPressed: _submit), + ), + ], + ), + ), + ); + } + + Future _submit() async { + InternalAuditProvider internalAuditProvider = Provider.of(context, listen: false); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + List attachement = []; + for (var item in _deviceImages) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + } + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + } + } +} diff --git a/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart new file mode 100644 index 00000000..3240bf2d --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart @@ -0,0 +1,36 @@ + +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class InternalAuditCheckListProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading ?? false) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart new file mode 100644 index 00000000..983bd6ca --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -0,0 +1,42 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/device/asset_search.dart'; +import 'package:test_sa/models/lookup.dart'; + +class InternalAuditProvider extends ChangeNotifier { + final pageItemNumber = 10; + final searchPageItemNumber = 10; + int pageNo = 1; + void reset() { + pageNo = 1; + stateCode = null; + } + int? stateCode; + bool isDetailLoading = false; + bool nextPage = false; + bool isNextPageLoading = false; + bool isLoading = false; + Future getInternalAuditById(int id) async { + try { + isLoading = true; + notifyListeners(); + //Need to replace + Response response = await ApiManager.instance.get("${URLs.getTRAFById}?id=$id"); + if (response.statusCode >= 200 && response.statusCode < 300) { + // trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]); + } + isLoading = false; + notifyListeners(); + return 0; + } catch (error) { + isLoading = false; + notifyListeners(); + return -1; + } + } +} From 18a53d751892526dccac78c03cbc44b7d7ce3e71 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 5 Nov 2025 09:23:14 +0300 Subject: [PATCH 03/31] chat list ui added. --- assets/images/star_empty.svg | 3 + assets/images/star_filled.svg | 3 + lib/extensions/context_extension.dart | 4 + lib/modules/cx_module/chat/chat_page.dart | 36 +++++ .../cx_module/chat/chat_rooms_page.dart | 92 ++++++++++++ lib/modules/cx_module/survey_page.dart | 137 ++++++++++++++++++ lib/new_views/pages/login_page.dart | 4 + 7 files changed, 279 insertions(+) create mode 100644 assets/images/star_empty.svg create mode 100644 assets/images/star_filled.svg create mode 100644 lib/modules/cx_module/chat/chat_page.dart create mode 100644 lib/modules/cx_module/chat/chat_rooms_page.dart create mode 100644 lib/modules/cx_module/survey_page.dart diff --git a/assets/images/star_empty.svg b/assets/images/star_empty.svg new file mode 100644 index 00000000..03cb916c --- /dev/null +++ b/assets/images/star_empty.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/star_filled.svg b/assets/images/star_filled.svg new file mode 100644 index 00000000..16abaa52 --- /dev/null +++ b/assets/images/star_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/extensions/context_extension.dart b/lib/extensions/context_extension.dart index 85299f73..82960243 100644 --- a/lib/extensions/context_extension.dart +++ b/lib/extensions/context_extension.dart @@ -19,6 +19,7 @@ extension BuildContextExtension on BuildContext { SettingProvider get settingProvider => Provider.of(this, listen: false); UserProvider get userProvider => Provider.of(this, listen: false); + bool isTablet() { final mediaQueryData = MediaQuery.of(this); final double screenWidth = mediaQueryData.size.width; @@ -27,6 +28,9 @@ extension BuildContextExtension on BuildContext { bool isTablet = (devicePixelRatio < 2 && (screenWidth >= 700 || screenHeight >= 700)) || (devicePixelRatio >= 2 && (screenWidth >= 1000 || screenHeight >= 1000)); return isTablet; } + + + void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog( context: this, builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title), diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart new file mode 100644 index 00000000..64b1f626 --- /dev/null +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + +class ChatPage extends StatefulWidget { + ChatPage({Key? key}) : super(key: key); + + @override + _ChatPageState createState() { + return _ChatPageState(); + } +} + +class _ChatPageState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const DefaultAppBar(title: "Req No. 343443"), + body: Column( + children: [ + + + ], + ), + ); + } +} diff --git a/lib/modules/cx_module/chat/chat_rooms_page.dart b/lib/modules/cx_module/chat/chat_rooms_page.dart new file mode 100644 index 00000000..70883f80 --- /dev/null +++ b/lib/modules/cx_module/chat/chat_rooms_page.dart @@ -0,0 +1,92 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + +class ChatRoomsPage extends StatefulWidget { + ChatRoomsPage({Key? key}) : super(key: key); + + @override + _ChatPageState createState() { + return _ChatPageState(); + } +} + +class _ChatPageState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const DefaultAppBar(title: "Chats"), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Request No. : 432212", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50, fontWeight: FontWeight.w600), + ), + Text( + "Request No. : 432212", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + ], + ).expanded, + getStatus(), + 8.width, + const Icon( + Icons.arrow_forward_ios_rounded, + size: 12, + color: AppColor.black20, + ), + ], + ).paddingOnly(top: 4, bottom: 4).onPress(() { + Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage())); + return; + }), + separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), + itemCount: 10) + .toShadowContainer(context, borderRadius: 20, showShadow: false, padding: 12))); + } + + Widget getStatus() { + Color color = const Color(0xff3B755C); + return Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), + decoration: BoxDecoration( + color: const Color(0xff62BE96).withOpacity(.6), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + "In Progress", + maxLines: 1, + style: AppTextStyles.tinyFont2.copyWith(color: color), + ), + ); + } +} diff --git a/lib/modules/cx_module/survey_page.dart b/lib/modules/cx_module/survey_page.dart new file mode 100644 index 00000000..08c00de0 --- /dev/null +++ b/lib/modules/cx_module/survey_page.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_rooms_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + +class SurveyPage extends StatefulWidget { + SurveyPage({Key? key}) : super(key: key); + + @override + _SurveyPageState createState() { + return _SurveyPageState(); + } +} + +class _SurveyPageState extends State { + int serviceSatisfiedRating = -1; + int serviceProvidedRating = -1; + String comments = ""; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const DefaultAppBar(title: "Survey"), + body: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "How satisfied are you with our services?", + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + 12.height, + SizedBox( + height: 32, + child: ListView.separated( + itemBuilder: (cxt, index) => (serviceSatisfiedRating >= index ? 'star_filled'.toSvgAsset() : 'star_empty'.toSvgAsset()).onPress(() { + setState(() { + serviceSatisfiedRating = index; + }); + }), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (cxt, index) => 8.width, + itemCount: 5, + scrollDirection: Axis.horizontal, + ), + ), + 16.height, + Text( + "Was the service provided promptly by our engineer?", + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + 12.height, + SizedBox( + height: 32, + child: ListView.separated( + itemBuilder: (cxt, index) => (serviceProvidedRating >= index ? 'star_filled'.toSvgAsset() : 'star_empty'.toSvgAsset()).onPress(() { + setState(() { + serviceProvidedRating = index; + }); + }), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (cxt, index) => 8.width, + itemCount: 5, + scrollDirection: Axis.horizontal, + ), + ), + 16.height, + Text( + "Request Type", + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + 16.height, + AppTextFormField( + initialValue: "", + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + labelText: "Additional Comments", + backgroundColor: AppColor.fieldBgColor(context), + style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)), + floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + showShadow: false, + onChange: (value) { + comments = value; + }, + ), + ], + ).toShadowContainer(context, borderRadius: 20, showShadow: false)) + .expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + label: context.translation.submit, + buttonColor: AppColor.primary10, + onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => ChatRoomsPage())); + return; + if (serviceSatisfiedRating < 0) { + "Provide rate services satisfaction".showToast; + return; + } + if (serviceProvidedRating < 0) { + "Provide rate services provided by engineer".showToast; + return; + } + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart index 8c54e927..61760688 100644 --- a/lib/new_views/pages/login_page.dart +++ b/lib/new_views/pages/login_page.dart @@ -12,6 +12,7 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/general_response_model.dart'; +import 'package:test_sa/modules/cx_module/survey_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/forget_password_module/forget_passwod_verify_otp.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart'; @@ -225,6 +226,9 @@ class _LoginPageState extends State { } Future _login() async { + // Navigator.push(context, MaterialPageRoute(builder: (context) => SurveyPage())); + // + // return; if (!_formKey.currentState!.validate()) return; if (privacyPolicyChecked == false) { From 96b65e99fa4c5cd959587e449a79cbea56beae47 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 6 Nov 2025 09:10:42 +0300 Subject: [PATCH 04/31] chat list ui added-1. --- assets/images/chat_attachment.svg | 3 + assets/images/chat_delivered.svg | 3 + assets/images/chat_mic.svg | 4 + assets/images/chat_msg_send.svg | 4 + assets/images/chat_seen.svg | 5 + assets/images/chat_sent.svg | 4 + lib/modules/cx_module/chat/chat_page.dart | 327 ++++++++++++++++++ .../cx_module/chat/chat_rooms_page.dart | 14 + lib/modules/cx_module/survey_page.dart | 5 +- lib/new_views/pages/login_page.dart | 6 +- pubspec.lock | 8 + pubspec.yaml | 1 + 12 files changed, 379 insertions(+), 5 deletions(-) create mode 100644 assets/images/chat_attachment.svg create mode 100644 assets/images/chat_delivered.svg create mode 100644 assets/images/chat_mic.svg create mode 100644 assets/images/chat_msg_send.svg create mode 100644 assets/images/chat_seen.svg create mode 100644 assets/images/chat_sent.svg diff --git a/assets/images/chat_attachment.svg b/assets/images/chat_attachment.svg new file mode 100644 index 00000000..80d2003b --- /dev/null +++ b/assets/images/chat_attachment.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/chat_delivered.svg b/assets/images/chat_delivered.svg new file mode 100644 index 00000000..4ac9df87 --- /dev/null +++ b/assets/images/chat_delivered.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/chat_mic.svg b/assets/images/chat_mic.svg new file mode 100644 index 00000000..60b5d00f --- /dev/null +++ b/assets/images/chat_mic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/chat_msg_send.svg b/assets/images/chat_msg_send.svg new file mode 100644 index 00000000..e0ad1ebc --- /dev/null +++ b/assets/images/chat_msg_send.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/chat_seen.svg b/assets/images/chat_seen.svg new file mode 100644 index 00000000..f6aa3475 --- /dev/null +++ b/assets/images/chat_seen.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/chat_sent.svg b/assets/images/chat_sent.svg new file mode 100644 index 00000000..0af44564 --- /dev/null +++ b/assets/images/chat_sent.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 64b1f626..26b982fa 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -1,4 +1,11 @@ +import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; class ChatPage extends StatefulWidget { @@ -11,6 +18,13 @@ class ChatPage extends StatefulWidget { } class _ChatPageState extends State { + bool isSender = false; + bool isAudioRecording = false; + + String? recordedFilePath; + final RecorderController recorderController = RecorderController(); + PlayerController playerController = PlayerController(); + @override void initState() { super.initState(); @@ -18,17 +32,330 @@ class _ChatPageState extends State { @override void dispose() { + recorderController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: AppColor.white10, appBar: const DefaultAppBar(title: "Req No. 343443"), body: Column( children: [ + Container( + color: AppColor.neutral50, + constraints: const BoxConstraints(maxHeight: 56), + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Text( + "Engineer: Mahmoud Shrouf", + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), + ).expanded, + 4.width, + Text( + "View All Documents", + style: AppTextStyles.bodyText.copyWith( + color: AppColor.white10, + decoration: TextDecoration.underline, + decorationColor: AppColor.white10, + ), + ), + ], + ), + ), + Container( + // width: double.infinity, + color: AppColor.neutral100, + child: ListView( + padding: const EdgeInsets.all(16), + children: [ + recipientMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"), + recipientMsgCard(false, "testing"), + recipientMsgCard(false, "testing testing testing"), + dateCard("Mon 27 Oct"), + senderMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"), + senderMsgCard(false, "Please let me know what is the issue?"), + ], + )).expanded, + Divider(height: 1, thickness: 1, color: const Color(0xff767676).withOpacity(.11)), + SafeArea( + child: ConstrainedBox( + constraints: const BoxConstraints(minHeight: 56), + child: Row( + children: [ + if (recordedFilePath == null) ...[ + isAudioRecording + ? AudioWaveforms( + size: Size(MediaQuery.of(context).size.width, 56.0), + + // enableGesture: true, + + waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), + padding: const EdgeInsets.only(left: 16), + recorderController: recorderController, // Customize how waveforms looks. + ).expanded + : TextFormField( + cursorColor: AppColor.neutral50, + style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), + minLines: 1, + maxLines: 3, + textInputAction: TextInputAction.none, + keyboardType: TextInputType.multiline, + decoration: InputDecoration( + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + border: InputBorder.none, + errorBorder: InputBorder.none, + contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), + alignLabelWithHint: true, + filled: true, + constraints: const BoxConstraints(), + suffixIconConstraints: const BoxConstraints(), + hintText: "Type your message here...", + hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), + // suffixIcon: Row( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.end, + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // + // 8.width, + // ], + // ) + ), + ).expanded, + IconButton( + onPressed: () {}, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: "chat_attachment".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + ], + if (recordedFilePath == null) + ...[] + else ...[ + IconButton( + onPressed: () async { + await playerController.preparePlayer(path: recordedFilePath!); + playerController.startPlayer(); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.play_circle_fill_rounded, size: 20), + constraints: const BoxConstraints(), + ), + AudioFileWaveforms( + playerController: playerController, + size: Size(300, 50), + ).expanded, + IconButton( + onPressed: () async { + playerController.pausePlayer(); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.pause_circle_filled_outlined, size: 20), + constraints: const BoxConstraints(), + ), + IconButton( + onPressed: () {}, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: "delete".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + ], + // if (isAudioRecording && recorderController.isRecording) + // IconButton( + // onPressed: () {}, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "chat_msg_send".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), + if (isAudioRecording) + IconButton( + onPressed: () async { + isAudioRecording = false; + await recorderController.pause(); + recordedFilePath = await recorderController.stop(); + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: Icon(Icons.stop_circle_rounded), + constraints: const BoxConstraints(), + ) + else + IconButton( + onPressed: () async { + await recorderController.checkPermission(); + if (recorderController.hasPermission) { + setState(() { + isAudioRecording = true; + }); + recorderController.record(); + } else { + "Audio permission denied. Please enable from setting".showToast; + } + // if (!isPermissionGranted) { + // "Audio permission denied. Please enable from setting".showToast; + // return; + // } + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: "chat_mic".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + + + IconButton( + onPressed: () {}, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: "chat_msg_send".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + 8.width, + ], + ), + ), + ) + ], + ), + ); + } + + Widget dateCard(String date) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), + margin: const EdgeInsets.only(top: 16, bottom: 8), + decoration: BoxDecoration( + color: AppColor.neutral50, + borderRadius: BorderRadius.circular(6), + ), + child: Text(date, style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10))) + .center; + } + Widget senderMsgCard(bool showHeader, String msg) { + Widget senderHeader = Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Jeniffer Jeniffer Jeniffer(Me)", + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), + ), + 8.width, + Container( + height: 26, + width: 26, + decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), + ), + ], + ); + + return Align( + alignment: Alignment.centerRight, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + if (showHeader) ...[senderHeader, 4.height] else 8.height, + Container( + padding: const EdgeInsets.all(8), + margin: const EdgeInsets.only(right: 26 + 8, left: 26 + 8), + decoration: BoxDecoration( + color: AppColor.white10, + borderRadius: BorderRadius.circular(6), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + msg, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), + ), + Text( + "2:00 PM", + style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)), + ), + ], + )), + ], + ), + ); + } + + Widget recipientMsgCard(bool showHeader, String msg) { + Widget recipientHeader = Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 26, + width: 26, + decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), + ), + 8.width, + Text( + "Mahmoud Shrouf", + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), + ) + ], + ); + + return Align( + alignment: Alignment.centerLeft, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (showHeader) ...[recipientHeader, 4.height] else 8.height, + Container( + padding: const EdgeInsets.all(8), + margin: const EdgeInsets.only(left: 26 + 8, right: 26 + 8), + decoration: BoxDecoration( + color: AppColor.primary10, + borderRadius: BorderRadius.circular(6), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + msg, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), + ), + Align( + alignment: Alignment.centerRight, + widthFactor: 1, + child: Text( + "2:00 PM", + style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.white10), + ), + ), + ], + )), ], ), ); diff --git a/lib/modules/cx_module/chat/chat_rooms_page.dart b/lib/modules/cx_module/chat/chat_rooms_page.dart index 70883f80..09c102ea 100644 --- a/lib/modules/cx_module/chat/chat_rooms_page.dart +++ b/lib/modules/cx_module/chat/chat_rooms_page.dart @@ -31,6 +31,7 @@ class _ChatPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: AppColor.neutral100, appBar: const DefaultAppBar(title: "Chats"), body: SingleChildScrollView( padding: const EdgeInsets.all(16), @@ -49,12 +50,25 @@ class _ChatPageState extends State { overflow: TextOverflow.ellipsis, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50, fontWeight: FontWeight.w600), ), + Text( + "Asset No. : HMG212", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), Text( "Request No. : 432212", maxLines: 1, overflow: TextOverflow.ellipsis, style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), + 6.height, + Text( + "Mon 27 Oct, 2:00 PM", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), ], ).expanded, getStatus(), diff --git a/lib/modules/cx_module/survey_page.dart b/lib/modules/cx_module/survey_page.dart index 08c00de0..ad8c0d28 100644 --- a/lib/modules/cx_module/survey_page.dart +++ b/lib/modules/cx_module/survey_page.dart @@ -39,6 +39,7 @@ class _SurveyPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: AppColor.neutral100, appBar: const DefaultAppBar(title: "Survey"), body: Column( children: [ @@ -117,8 +118,6 @@ class _SurveyPageState extends State { label: context.translation.submit, buttonColor: AppColor.primary10, onPressed: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => ChatRoomsPage())); - return; if (serviceSatisfiedRating < 0) { "Provide rate services satisfaction".showToast; return; @@ -127,6 +126,8 @@ class _SurveyPageState extends State { "Provide rate services provided by engineer".showToast; return; } + Navigator.push(context, MaterialPageRoute(builder: (context) => ChatRoomsPage())); + return; }, ), ), diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart index 61760688..8d36d425 100644 --- a/lib/new_views/pages/login_page.dart +++ b/lib/new_views/pages/login_page.dart @@ -226,9 +226,9 @@ class _LoginPageState extends State { } Future _login() async { - // Navigator.push(context, MaterialPageRoute(builder: (context) => SurveyPage())); - // - // return; + Navigator.push(context, MaterialPageRoute(builder: (context) => SurveyPage())); + + return; if (!_formKey.currentState!.validate()) return; if (privacyPolicyChecked == false) { diff --git a/pubspec.lock b/pubspec.lock index fdc4903d..7d69171a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.23" + audio_waveforms: + dependency: "direct main" + description: + name: audio_waveforms + sha256: "658fef41bbab299184b65ba2fd749e8ec658c1f7d54a21f7cf97fa96b173b4ce" + url: "https://pub.dev" + source: hosted + version: "1.3.0" audioplayers: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 70641f4d..f766ebde 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -95,6 +95,7 @@ dependencies: safe_device: ^1.2.1 toggle_switch: ^2.3.0 clipboard: ^2.0.2 + audio_waveforms: ^1.3.0 local_auth_darwin: any dev_dependencies: From 3b6a0eea3c43a944f18025756de0a6910760e171 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 6 Nov 2025 10:18:08 +0300 Subject: [PATCH 05/31] voice note ui added. --- lib/modules/cx_module/chat/chat_page.dart | 337 ++++++++++++++++------ 1 file changed, 242 insertions(+), 95 deletions(-) diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 26b982fa..5c5e34a9 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -8,6 +8,8 @@ import 'package:test_sa/modules/cm_module/views/components/action_button/footer_ import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } + class ChatPage extends StatefulWidget { ChatPage({Key? key}) : super(key: key); @@ -25,13 +27,22 @@ class _ChatPageState extends State { final RecorderController recorderController = RecorderController(); PlayerController playerController = PlayerController(); + ChatState chatState = ChatState.idle; + @override void initState() { super.initState(); + playerController.addListener(() async { + // if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) { + // await playerController.stopPlayer(); + // setState(() {}); + // } + }); } @override void dispose() { + playerController.dispose(); recorderController.dispose(); super.dispose(); } @@ -87,47 +98,37 @@ class _ChatPageState extends State { constraints: const BoxConstraints(minHeight: 56), child: Row( children: [ - if (recordedFilePath == null) ...[ - isAudioRecording - ? AudioWaveforms( - size: Size(MediaQuery.of(context).size.width, 56.0), - - // enableGesture: true, - - waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), - padding: const EdgeInsets.only(left: 16), - recorderController: recorderController, // Customize how waveforms looks. - ).expanded - : TextFormField( - cursorColor: AppColor.neutral50, - style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), - minLines: 1, - maxLines: 3, - textInputAction: TextInputAction.none, - keyboardType: TextInputType.multiline, - decoration: InputDecoration( - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - border: InputBorder.none, - errorBorder: InputBorder.none, - contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), - alignLabelWithHint: true, - filled: true, - constraints: const BoxConstraints(), - suffixIconConstraints: const BoxConstraints(), - hintText: "Type your message here...", - hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), - // suffixIcon: Row( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.end, - // mainAxisAlignment: MainAxisAlignment.end, - // children: [ - // - // 8.width, - // ], - // ) - ), - ).expanded, + if (chatState == ChatState.idle) ...[ + TextFormField( + cursorColor: AppColor.neutral50, + style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), + minLines: 1, + maxLines: 3, + textInputAction: TextInputAction.none, + keyboardType: TextInputType.multiline, + decoration: InputDecoration( + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + border: InputBorder.none, + errorBorder: InputBorder.none, + contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), + alignLabelWithHint: true, + filled: true, + constraints: const BoxConstraints(), + suffixIconConstraints: const BoxConstraints(), + hintText: "Type your message here...", + hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), + // suffixIcon: Row( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.end, + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // + // 8.width, + // ], + // ) + ), + ).expanded, IconButton( onPressed: () {}, style: const ButtonStyle( @@ -136,44 +137,191 @@ class _ChatPageState extends State { icon: "chat_attachment".toSvgAsset(width: 24, height: 24), constraints: const BoxConstraints(), ), - ], - if (recordedFilePath == null) - ...[] - else ...[ IconButton( onPressed: () async { - await playerController.preparePlayer(path: recordedFilePath!); - playerController.startPlayer(); + await recorderController.checkPermission(); + if (recorderController.hasPermission) { + chatState = ChatState.voiceRecordingStarted; + recorderController.record(); + setState(() {}); + } else { + "Audio permission denied. Please enable from setting".showToast; + } + // if (!isPermissionGranted) { + // "Audio permission denied. Please enable from setting".showToast; + // return; + // } }, style: const ButtonStyle( tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded ), - icon: const Icon(Icons.play_circle_fill_rounded, size: 20), + icon: "chat_mic".toSvgAsset(width: 24, height: 24), constraints: const BoxConstraints(), ), - AudioFileWaveforms( - playerController: playerController, - size: Size(300, 50), + ] else if (chatState == ChatState.voiceRecordingStarted) ...[ + AudioWaveforms( + size: Size(MediaQuery.of(context).size.width, 56.0), + waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), + padding: const EdgeInsets.only(left: 16), + recorderController: recorderController, // Customize how waveforms looks. ).expanded, IconButton( onPressed: () async { - playerController.pausePlayer(); + isAudioRecording = false; + await recorderController.pause(); + recordedFilePath = await recorderController.stop(); + chatState = ChatState.voiceRecordingCompleted; + setState(() {}); }, style: const ButtonStyle( tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded ), - icon: const Icon(Icons.pause_circle_filled_outlined, size: 20), + icon: Icon(Icons.stop_circle_rounded), constraints: const BoxConstraints(), - ), + ) + ] else if (chatState == ChatState.voiceRecordingCompleted) ...[ + if (playerController.playerState == PlayerState.playing) + IconButton( + onPressed: () async { + await playerController.pausePlayer(); + await playerController.stopPlayer(); + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.stop_circle_outlined, size: 20), + constraints: const BoxConstraints(), + ) + else + IconButton( + onPressed: () async { + await playerController.preparePlayer(path: recordedFilePath!); + await playerController.startPlayer(); + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.play_circle_fill_rounded, size: 20), + constraints: const BoxConstraints(), + ), + AudioFileWaveforms( + playerController: playerController, + waveformData: recorderController.waveData, + enableSeekGesture: false, + continuousWaveform: false, + waveformType: WaveformType.long, + playerWaveStyle: const PlayerWaveStyle( + fixedWaveColor: AppColor.neutral50, + liveWaveColor: AppColor.primary10, + showSeekLine: true, + ), + size: Size(MediaQuery.of(context).size.width, 56.0), + ).expanded, IconButton( - onPressed: () {}, + onPressed: () async { + await playerController.stopPlayer(); + recorderController.reset(); + recordedFilePath = null; + chatState = ChatState.idle; + setState(() {}); + }, style: const ButtonStyle( tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded ), - icon: "delete".toSvgAsset(width: 24, height: 24), + icon: "delete_icon".toSvgAsset(width: 24, height: 24), constraints: const BoxConstraints(), ), ], + + // if (recordedFilePath == null) ...[ + // isAudioRecording + // ? AudioWaveforms( + // size: Size(MediaQuery.of(context).size.width, 56.0), + // + // // enableGesture: true, + // + // waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), + // padding: const EdgeInsets.only(left: 16), + // recorderController: recorderController, // Customize how waveforms looks. + // ).expanded + // : TextFormField( + // cursorColor: AppColor.neutral50, + // style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), + // minLines: 1, + // maxLines: 3, + // textInputAction: TextInputAction.none, + // keyboardType: TextInputType.multiline, + // decoration: InputDecoration( + // enabledBorder: InputBorder.none, + // focusedBorder: InputBorder.none, + // border: InputBorder.none, + // errorBorder: InputBorder.none, + // contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), + // alignLabelWithHint: true, + // filled: true, + // constraints: const BoxConstraints(), + // suffixIconConstraints: const BoxConstraints(), + // hintText: "Type your message here...", + // hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), + // // suffixIcon: Row( + // // mainAxisSize: MainAxisSize.min, + // // crossAxisAlignment: CrossAxisAlignment.end, + // // mainAxisAlignment: MainAxisAlignment.end, + // // children: [ + // // + // // 8.width, + // // ], + // // ) + // ), + // ).expanded, + // IconButton( + // onPressed: () {}, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "chat_attachment".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), + // ], + // if (recordedFilePath == null) + // ...[] + // else ...[ + // IconButton( + // onPressed: () async { + // await playerController.preparePlayer(path: recordedFilePath!); + // playerController.startPlayer(); + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: const Icon(Icons.play_circle_fill_rounded, size: 20), + // constraints: const BoxConstraints(), + // ), + // AudioFileWaveforms( + // playerController: playerController, + // size: Size(300, 50), + // ).expanded, + // IconButton( + // onPressed: () async { + // playerController.pausePlayer(); + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: const Icon(Icons.pause_circle_filled_outlined, size: 20), + // constraints: const BoxConstraints(), + // ), + // IconButton( + // onPressed: () {}, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "delete".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), + // ], // if (isAudioRecording && recorderController.isRecording) // IconButton( // onPressed: () {}, @@ -183,45 +331,44 @@ class _ChatPageState extends State { // icon: "chat_msg_send".toSvgAsset(width: 24, height: 24), // constraints: const BoxConstraints(), // ), - if (isAudioRecording) - IconButton( - onPressed: () async { - isAudioRecording = false; - await recorderController.pause(); - recordedFilePath = await recorderController.stop(); - setState(() {}); - }, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - ), - icon: Icon(Icons.stop_circle_rounded), - constraints: const BoxConstraints(), - ) - else - IconButton( - onPressed: () async { - await recorderController.checkPermission(); - if (recorderController.hasPermission) { - setState(() { - isAudioRecording = true; - }); - recorderController.record(); - } else { - "Audio permission denied. Please enable from setting".showToast; - } - // if (!isPermissionGranted) { - // "Audio permission denied. Please enable from setting".showToast; - // return; - // } - }, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - ), - icon: "chat_mic".toSvgAsset(width: 24, height: 24), - constraints: const BoxConstraints(), - ), - - + // if (isAudioRecording) + // IconButton( + // onPressed: () async { + // isAudioRecording = false; + // await recorderController.pause(); + // recordedFilePath = await recorderController.stop(); + // chatState = ChatState.voiceRecordingCompleted; + // setState(() {}); + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: Icon(Icons.stop_circle_rounded), + // constraints: const BoxConstraints(), + // ) + // else + // IconButton( + // onPressed: () async { + // await recorderController.checkPermission(); + // if (recorderController.hasPermission) { + // setState(() { + // isAudioRecording = true; + // }); + // recorderController.record(); + // } else { + // "Audio permission denied. Please enable from setting".showToast; + // } + // // if (!isPermissionGranted) { + // // "Audio permission denied. Please enable from setting".showToast; + // // return; + // // } + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "chat_mic".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), IconButton( onPressed: () {}, From a8e8774040aa97fc7a5d89ebae29d6826f50d88d Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 6 Nov 2025 11:42:46 +0300 Subject: [PATCH 06/31] internal audit api's implementation in progress --- lib/controllers/api_routes/urls.dart | 11 + .../providers/api/all_requests_provider.dart | 5 +- .../widgets/request_category_list.dart | 6 +- lib/main.dart | 6 +- .../equipment_internal_audit_data_model.dart | 284 ++++++++++++++++++ .../equipment_internal_audit_form_model.dart | 41 +++ .../internal_audit_attachment_model.dart | 23 ++ .../models/internal_audit_model.dart | 29 -- .../system_internal_audit_form_model.dart | 82 +++++ .../create_equipment_internal_audit_form.dart | 59 ++-- .../equipment_internal_audit_detail_page.dart | 192 ++++++++++++ .../equipment_internal_audit_item_view.dart} | 25 +- .../create_system_internal_audit_form.dart | 107 +++++-- ..._audit_work_order_auto_complete_field.dart | 149 +++++++++ .../system_internal_audit_detail_page.dart} | 13 +- .../system_internal_audit_item_view.dart | 118 ++++++++ .../internal_audit_checklist_provider.dart | 2 +- .../internal_audit_finding_type_provider.dart | 2 +- .../provider/internal_audit_provider.dart | 80 ++++- .../internal_audit_wo_type_provider.dart | 35 +++ .../create_request-type_bottomsheet.dart | 4 +- .../my_request/my_requests_page.dart | 11 +- .../requests/request_paginated_listview.dart | 19 +- .../widgets/request_item_view_list.dart | 28 +- 24 files changed, 1202 insertions(+), 129 deletions(-) create mode 100644 lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart create mode 100644 lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart create mode 100644 lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart delete mode 100644 lib/modules/internal_audit_module/models/internal_audit_model.dart create mode 100644 lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart rename lib/modules/internal_audit_module/pages/{ => equipment_internal_audit}/create_equipment_internal_audit_form.dart (71%) create mode 100644 lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart rename lib/modules/internal_audit_module/pages/{internal_audit_item_view.dart => equipment_internal_audit/equipment_internal_audit_item_view.dart} (77%) rename lib/modules/internal_audit_module/pages/{ => system_internal_audit}/create_system_internal_audit_form.dart (66%) create mode 100644 lib/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart rename lib/modules/internal_audit_module/pages/{internal_audit_detail_page.dart => system_internal_audit/system_internal_audit_detail_page.dart} (94%) create mode 100644 lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 49ce0e4d..dad15d8d 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -300,6 +300,7 @@ class URLs { static get getPentry => "$_baseUrl/return/pentry/details"; // get static get updatePentry => "$_baseUrl/Visit/UpdateVisit"; // get static get getPentryTaskStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=403"; // get + // get static get getPentryVisitStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=402"; // get static get getPentryStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=401"; // get // contacts @@ -310,4 +311,14 @@ class URLs { static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add static get getDepartmentBasedOnSite => "$_baseUrl/TRAFDataSource/GetDepartmentBasedOnSite"; // add + +//internal Audit + static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById"; + static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemById"; + static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43"; + static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500"; + static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502"; + static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment"; + static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; + } diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 71d1f46f..99f77a02 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -140,9 +140,8 @@ class AllRequestsProvider extends ChangeNotifier { return list; } if (context.userProvider.isQualityUser) { - //TODO Need to replace with actual number.. - // list = [10]; - list = [1]; + + list = [10,11]; return list; } diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index c92ab6b2..639b3e6a 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -54,7 +54,9 @@ class RequestCategoryList extends StatelessWidget { return TrafRequestItemView(requestData: request); //TODO need to verify this ... case 10: - return InternalAuditItemView(requestData: request); + return EquipmentInternalAuditItemView(requestData: request); + case 11: + return EquipmentInternalAuditItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/main.dart b/lib/main.dart index 2ee8fd64..a2f9bdca 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,10 +29,11 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/modules/traf_module/traf_request_provider.dart'; @@ -292,6 +293,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => CommentsProvider()), ChangeNotifierProvider(create: (_) => GasRefillCommentsProvider()), ChangeNotifierProvider(create: (_) => InternalAuditCheckListProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditWoTypeProvider()), ChangeNotifierProvider(create: (_) => InternalAuditProvider()), ChangeNotifierProvider(create: (_) => InternalAuditFindingTypeProvider()), diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart new file mode 100644 index 00000000..411789ec --- /dev/null +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart @@ -0,0 +1,284 @@ + class EquipmentInternalAuditDataModel { + int? id; + String? requestNo; + String? createdDate; + int? requestNoSequence; + Auditor? auditor; + Status? status; + Asset? asset; + AssignEmployee? assignEmployee; + dynamic manufacture; + String? remarks; + List? equipmentsFindings; + List? attachments; + + EquipmentInternalAuditDataModel({ + this.id, + this.requestNo, + this.createdDate, + this.requestNoSequence, + this.auditor, + this.status, + this.asset, + this.assignEmployee, + this.manufacture, + this.remarks, + this.equipmentsFindings, + this.attachments, + }); + + EquipmentInternalAuditDataModel.fromJson(Map json) { + id = json['id']; + requestNo = json['requestNo']; + createdDate = json['createdDate']; + requestNoSequence = json['requestNoSequence']; + auditor = json['auditor'] != null ? Auditor.fromJson(json['auditor']) : null; + status = json['status'] != null ? Status.fromJson(json['status']) : null; + asset = json['asset'] != null ? Asset.fromJson(json['asset']) : null; + assignEmployee = json['assignEmployee'] != null ? AssignEmployee.fromJson(json['assignEmployee']) : null; + manufacture = json['manufacture']; + remarks = json['remarks']; + if (json['equipmentsFindings'] != null) { + equipmentsFindings = []; + json['equipmentsFindings'].forEach((v) { + equipmentsFindings!.add(EquipmentsFinding.fromJson(v)); + }); + } + attachments = json['attachments'] != null ? List.from(json['attachments']) : []; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['requestNo'] = requestNo; + data['createdDate'] = createdDate; + data['requestNoSequence'] = requestNoSequence; + if (auditor != null) { + data['auditor'] = auditor!.toJson(); + } + if (status != null) { + data['status'] = status!.toJson(); + } + if (asset != null) { + data['asset'] = asset!.toJson(); + } + if (assignEmployee != null) { + data['assignEmployee'] = assignEmployee!.toJson(); + } + data['manufacture'] = manufacture; + data['remarks'] = remarks; + if (equipmentsFindings != null) { + data['equipmentsFindings'] = + equipmentsFindings!.map((v) => v.toJson()).toList(); + } + data['attachments'] = attachments; + return data; + } +} + +class Auditor { + String? userId; + String? userName; + String? email; + String? employeeId; + int? languageId; + String? extensionNo; + String? phoneNumber; + bool? isActive; + + Auditor({ + this.userId, + this.userName, + this.email, + this.employeeId, + this.languageId, + this.extensionNo, + this.phoneNumber, + this.isActive, + }); + + Auditor.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + extensionNo = json['extensionNo']; + phoneNumber = json['phoneNumber']; + isActive = json['isActive']; + } + + Map toJson() { + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['email'] = email; + data['employeeId'] = employeeId; + data['languageId'] = languageId; + data['extensionNo'] = extensionNo; + data['phoneNumber'] = phoneNumber; + data['isActive'] = isActive; + return data; + } +} + +class Status { + int? id; + String? name; + int? value; + + Status({this.id, this.name, this.value}); + + Status.fromJson(Map json) { + id = json['id']; + name = json['name']; + value = json['value']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['value'] = value; + return data; + } +} + +class Asset { + int? id; + String? assetNumber; + String? assetSerialNo; + String? assetName; + String? modelName; + String? manufacturerName; + String? siteName; + int? siteId; + String? modelDefinition; + + Asset({ + this.id, + this.assetNumber, + this.assetSerialNo, + this.assetName, + this.modelName, + this.manufacturerName, + this.siteName, + this.siteId, + this.modelDefinition, + }); + + Asset.fromJson(Map json) { + id = json['id']; + assetNumber = json['assetNumber']; + assetSerialNo = json['assetSerialNo']; + assetName = json['assetName']; + modelName = json['modelName']; + manufacturerName = json['manufacturerName']; + siteName = json['siteName']; + siteId = json['siteId']; + modelDefinition = json['modelDefinition']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['assetNumber'] = assetNumber; + data['assetSerialNo'] = assetSerialNo; + data['assetName'] = assetName; + data['modelName'] = modelName; + data['manufacturerName'] = manufacturerName; + data['siteName'] = siteName; + data['siteId'] = siteId; + data['modelDefinition'] = modelDefinition; + return data; + } +} + +class AssignEmployee { + String? userId; + String? userName; + String? email; + String? employeeId; + int? languageId; + String? extensionNo; + String? phoneNumber; + bool? isActive; + + AssignEmployee({ + this.userId, + this.userName, + this.email, + this.employeeId, + this.languageId, + this.extensionNo, + this.phoneNumber, + this.isActive, + }); + + AssignEmployee.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + extensionNo = json['extensionNo']; + phoneNumber = json['phoneNumber']; + isActive = json['isActive']; + } + + Map toJson() { + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['email'] = email; + data['employeeId'] = employeeId; + data['languageId'] = languageId; + data['extensionNo'] = extensionNo; + data['phoneNumber'] = phoneNumber; + data['isActive'] = isActive; + return data; + } +} + +class EquipmentsFinding { + int? id; + Finding? finding; + + EquipmentsFinding({this.id, this.finding}); + + EquipmentsFinding.fromJson(Map json) { + id = json['id']; + finding = json['finding'] != null ? Finding.fromJson(json['finding']) : null; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + if (finding != null) { + data['finding'] = finding!.toJson(); + } + return data; + } +} + +class Finding { + int? id; + String? name; + int? value; + + Finding({this.id, this.name, this.value}); + + Finding.fromJson(Map json) { + id = json['id']; + name = json['name']; + value = json['value']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['value'] = value; + return data; + } +} diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart new file mode 100644 index 00000000..e6a79e91 --- /dev/null +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart @@ -0,0 +1,41 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/fault_description.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; + +class EquipmentInternalAuditFormModel { + int? id=0; + String? deviceArName; + String? auditorId; + String? woOrderNo; + List? devicePhotos; + List findings =[]; + List attachments = []; + String? remarks; + Asset? device; + EquipmentInternalAuditFormModel({ + this.id, + this.deviceArName, + this.auditorId, + this.devicePhotos, + this.woOrderNo, + this.remarks, + }); + + Map toJson() { + return { + 'id': id??0, + 'assetId': device?.id, + 'auditorId': auditorId, + 'findings': findings.map((e) => {'findingId': e.value}).toList(), + 'attachments': attachments.map((e) => e.toJson()).toList(), + 'remarks': remarks, + }; + } + + +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart new file mode 100644 index 00000000..a81f2d17 --- /dev/null +++ b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart @@ -0,0 +1,23 @@ +class InternalAuditAttachments { + InternalAuditAttachments({this.id,this.originalName, this.name,this.createdBy}); + + int? id; + String? name; + String? originalName; + String ?createdBy; + InternalAuditAttachments.fromJson(Map json) { + id = json['id']; + name = json['name']; + originalName = json['originalName']; + createdBy = json['createdBy']; + } + + Map toJson() { + final Map data = {}; + // data['id'] = id; + data['name'] = name; + data['originalName'] = originalName; + // data['createdBy'] = createdBy; + return data; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/internal_audit_model.dart b/lib/modules/internal_audit_module/models/internal_audit_model.dart deleted file mode 100644 index 693b384d..00000000 --- a/lib/modules/internal_audit_module/models/internal_audit_model.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/src/widgets/framework.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/fault_description.dart'; -import 'package:test_sa/models/lookup.dart'; - -class InternalAuditModel { - String? id; - int? deviceId; - String? deviceArName; - String? woOrderNo; - List? devicePhotos; - Lookup? auditCheckList; - String? comments; - Asset? device; - - InternalAuditModel({ - this.id, - this.deviceArName, - this.devicePhotos, - this.deviceId, - this.woOrderNo, - this.comments, - }); - -} - diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart new file mode 100644 index 00000000..9750e9e0 --- /dev/null +++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart @@ -0,0 +1,82 @@ + +import 'dart:developer'; + +import 'package:test_sa/models/lookup.dart'; + +class SystemInternalAuditFormModel { + int? id = 0; + String? auditorId; + String? assignEmployeeId; + Lookup? findingType; + String? findingDescription; + Lookup? workOrderType; + int? correctiveMaintenanceId; + int? planPreventiveVisitId; + int? assetTransferId; + int? taskJobId; + int? taskAlertJobId; + int? gasRefillId; + int? planRecurrentTaskId; + int? statusId; + + SystemInternalAuditFormModel({ + this.id, + this.auditorId, + this.assignEmployeeId, + this.findingType, + this.findingDescription, + this.workOrderType, + this.correctiveMaintenanceId, + this.planPreventiveVisitId, + this.assetTransferId, + this.taskJobId, + this.taskAlertJobId, + this.gasRefillId, + this.planRecurrentTaskId, + this.statusId, + }); + + Map toJson() { + return { + 'id': id, + 'auditorId': auditorId, + 'assignEmployeeId': assignEmployeeId, + 'findingTypeId': findingType?.id, + 'findingDescription': findingDescription, + 'workOrderTypeId': workOrderType?.id, + 'correctiveMaintenanceId': correctiveMaintenanceId, + 'planPreventiveVisitId': planPreventiveVisitId, + 'assetTransferId': assetTransferId, + 'taskJobId': taskJobId, + 'taskAlertJobId': taskAlertJobId, + 'gasRefillId': gasRefillId, + 'planRecurrentTaskId': planRecurrentTaskId, + 'statusId': statusId, + }; + } +} + +class WoAutoCompleteModel { + int? id; + String? workOrderNo; + String? displayName; + + WoAutoCompleteModel({this.id, this.workOrderNo, this.displayName}); + + WoAutoCompleteModel.fromJson(Map json) { + id = json['id']; + workOrderNo = json['workOrderNo']; + displayName = json['workOrderNo']; + } + + Map toJson() { + final Map data = {}; + data['id'] =id; + data['woOrderNo'] = workOrderNo; + data['displayName'] = workOrderNo; + return data; + } +} + + + diff --git a/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart similarity index 71% rename from lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart rename to lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart index 83655836..db29aee6 100644 --- a/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart @@ -9,24 +9,24 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; -import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart'; import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import '../../../../../../new_views/common_widgets/default_app_bar.dart'; class CreateEquipmentInternalAuditForm extends StatefulWidget { - static const String id = "/create-internal-audit-view"; + static const String id = "/create-equipment-internal-audit-form"; const CreateEquipmentInternalAuditForm({Key? key}) : super(key: key); @@ -36,10 +36,11 @@ class CreateEquipmentInternalAuditForm extends StatefulWidget { class _CreateEquipmentInternalAuditFormState extends State with TickerProviderStateMixin { late TextEditingController _commentController; - final InternalAuditModel _internalAuditModel = InternalAuditModel(); - final List _deviceImages = []; + final EquipmentInternalAuditFormModel _equipmentinternalAuditModel = EquipmentInternalAuditFormModel(); + final List _attachments = []; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); + FocusNode auditCheckListNode = FocusNode(); @override void initState() { @@ -68,28 +69,27 @@ class _CreateEquipmentInternalAuditFormState extends State( + //TODO need to check layout issue... + MultipleItemDropDownMenu( context: context, - height: 56.toScreenHeight, - title: 'Internal Audit Checklist'.addTranslation, - showShadow: false, - initialValue: _internalAuditModel.auditCheckList, - backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, - onSelect: (status) { - if (status != null) { - _internalAuditModel.auditCheckList = status; - setState(() {}); - } + backgroundColor: AppColor.neutral100, + showShadow: false, + showCancel: true, + requestById: context.userProvider.user?.clientId, + title: 'Internal Audit Checklist'.addTranslation, + initialValue: _equipmentinternalAuditModel.findings, + onSelect: (value) { + _equipmentinternalAuditModel.findings = value ?? []; }, ), 16.height, @@ -100,14 +100,17 @@ class _CreateEquipmentInternalAuditFormState extends State(context, listen: false); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); - List attachement = []; - for (var item in _deviceImages) { + _equipmentinternalAuditModel.attachments = []; + for (var item in _attachments) { String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + _equipmentinternalAuditModel.attachments.add(InternalAuditAttachments(id: item.id, name: fileName)); } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + _equipmentinternalAuditModel.auditorId = context.userProvider.user?.userID; + bool status = await internalAuditProvider.addEquipmentInternalAudit(context: context, request: _equipmentinternalAuditModel); + Navigator.pop(context); + if(status){ + Navigator.pop(context); + } } } } diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart new file mode 100644 index 00000000..465a42db --- /dev/null +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart @@ -0,0 +1,192 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; + +class EquipmentInternalAuditDetailPage extends StatefulWidget { + static const String id = "/details-internal-audit"; + + final int auditId; + + const EquipmentInternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); + + @override + _EquipmentInternalAuditDetailPageState createState() { + return _EquipmentInternalAuditDetailPageState(); + } +} + +class _EquipmentInternalAuditDetailPageState extends State { + bool isWoType = true; + EquipmentInternalAuditDataModel? model; + late InternalAuditProvider _internalAuditProvider; + + @override + void initState() { + super.initState(); + _internalAuditProvider = Provider.of(context, listen: false); + WidgetsBinding.instance.addPostFrameCallback((_) { + getAuditData(); + }); + } + + Future getAuditData() async { + model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + //TODO need to check when implementing provider needed or not . + return Scaffold( + appBar: const DefaultAppBar(title: "Request Details"), + body: Selector( + selector: (_, provider) => provider.isLoading, + builder: (_, isLoading, __) { + if (isLoading) return const ALoading(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + assetDetails(), + 8.height, + requestDetails(), + 8.height, + //TODO need to check for comments + // if (model.comment?.isNotEmpty ?? false) ...[ + const Divider().defaultStyle(context), + Text( + "Comments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + // model.comment!.bodyText(context), + // 8.height, + // ], + //TODO need to check for attachments + // if ( _model.attachment.isNotEmpty) ...[ + const Divider().defaultStyle(context), + Text( + "Attachments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + // FilesList(images: _model.attachment?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + // ], + ], + ).paddingAll(0).toShadowContainer(context), + ).expanded, + if (context.userProvider.isEngineer) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: "Update", + onPressed: () { + Navigator.pushNamed(context, UpdateInternalAuditPage.id); + }), + ), + ], + ); + }, + )); + } + + Widget workOrderInformation() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "WO Info", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.woNumber}: ${'-'}'.bodyText(context), + '${'WO Type'.addTranslation}: ${'-'}'.bodyText(context), + '${context.translation.site}: ${'-'}'.bodyText(context), + '${context.translation.assetName}: ${'-'}'.bodyText(context), + '${context.translation.manufacture}: ${'-'}'.bodyText(context), + '${context.translation.model}: ${'-'}'.bodyText(context), + ], + ); + } + + Widget requestDetails() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "Request Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + if (model != null && model!.equipmentsFindings != null && model!.equipmentsFindings!.isNotEmpty) + ...model!.equipmentsFindings!.map((item) { + final findingName = item.finding?.name ?? 'Unknown'; + return checklistWidget(value: findingName.addTranslation); + }).toList() + else + Text('No findings available'.addTranslation), + ], + ); + } + + Widget assetDetails() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Asset Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.assetName}: ${model?.asset?.assetName ?? '-'}'.bodyText(context), + '${context.translation.assetNo}: ${model?.asset?.assetNumber ?? '-'}'.bodyText(context), + '${context.translation.manufacture}: ${model?.asset?.manufacturerName ?? '-'}'.bodyText(context), + '${context.translation.model}: ${model?.asset?.modelName ?? '-'}'.bodyText(context), + ], + ); + } + + Widget checklistWidget({required String value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + value: true, + activeColor: AppColor.neutral120, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(horizontal: -4, vertical: -3), + onChanged: (value) {}, + ), + value.bodyText(context), + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart similarity index 77% rename from lib/modules/internal_audit_module/pages/internal_audit_item_view.dart rename to lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart index 20a81aaf..4c4bbb57 100644 --- a/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -6,20 +8,21 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_detail_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; -class InternalAuditItemView extends StatelessWidget { +class EquipmentInternalAuditItemView extends StatelessWidget { final Data? requestData; final RequestsDetails? requestDetails; final bool showShadow; - const InternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + const EquipmentInternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); @override Widget build(BuildContext context) { //TODO need to refactor this code repetation @waseem + log('request details ${requestDetails?.toJson()}'); if (requestData != null) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -41,9 +44,8 @@ class InternalAuditItemView extends StatelessWidget { ], ), 8.height, - // (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), - ("Internal Audit Request").heading5(context), - // infoWidget(label: context.translation.requestType, value: requestData?.requestTypeName, context: context), + (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), + infoWidget(label: context.translation.assetNumber, value: requestData?.assetNumber, context: context), 8.height, Row( @@ -59,7 +61,7 @@ class InternalAuditItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestDetails!.id!))); }); } return Column( @@ -82,10 +84,11 @@ class InternalAuditItemView extends StatelessWidget { ], ), 8.height, - // (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), - ("Internal Audit Request").heading5(context), + (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), 8.height, - // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context), + infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context), + infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context), + infoWidget(label: context.translation.model, value: requestDetails!.model, context: context), 8.height, Row( mainAxisSize: MainAxisSize.min, @@ -100,7 +103,7 @@ class InternalAuditItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestDetails!.id!))); }); } diff --git a/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart similarity index 66% rename from lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart rename to lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart index 051e2dfd..64e8408b 100644 --- a/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -13,10 +14,13 @@ import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_mo import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; @@ -25,7 +29,7 @@ import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; -import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +import '../../../../../../../new_views/common_widgets/default_app_bar.dart'; class CreateSystemInternalAuditForm extends StatefulWidget { static const String id = "/create-system-audit-view"; @@ -40,22 +44,25 @@ class CreateSystemInternalAuditForm extends StatefulWidget { class _CreateSystemInternalAuditFormState extends State with TickerProviderStateMixin { late TextEditingController _commentController; late InternalAuditProvider _internalAuditProvider; - final InternalAuditModel _internalAuditModel = InternalAuditModel(); + final SystemInternalAuditFormModel _model = SystemInternalAuditFormModel(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); final List _deviceImages = []; + late TextEditingController _woAutoCompleteController; bool showLoading = false; @override void initState() { super.initState(); _commentController = TextEditingController(); + _woAutoCompleteController = TextEditingController(); _internalAuditProvider = Provider.of(context, listen: false); } @override void dispose() { _commentController.dispose(); + _woAutoCompleteController.dispose(); super.dispose(); } @@ -73,13 +80,31 @@ class _CreateSystemInternalAuditFormState extends State( + context: context, + height: 56.toScreenHeight, + title: 'Wo Type'.addTranslation, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: _model.workOrderType, + onSelect: (status) { + if (status != null) { + _model.workOrderType = status; + _clearWorkOrderSelection(); + _woAutoCompleteController.clear(); + setState(() {}); + } + }, + ), + 12.height, + SystemAuditWoAutoCompleteField( + woTypeId: _model.workOrderType?.value, + controller: _woAutoCompleteController, clearAfterPick: false, - byName: true, - initialValue: _internalAuditModel.woOrderNo ?? "", - onPick: (part) { - _internalAuditModel.woOrderNo = part.name; + initialValue: '', + onPick: (wo) { + updateWorkOrderReference(woTypeId: _model.workOrderType?.value, selectedId:wo.id); setState(() {}); }, ), @@ -94,10 +119,10 @@ class _CreateSystemInternalAuditFormState extends State _SystemAuditWoAutoCompleteFieldState(); +} + +class _SystemAuditWoAutoCompleteFieldState extends State { + late InternalAuditProvider _provider; + + // + // late TextEditingController _controller; + + bool loading = false; + + @override + void initState() { + // w controller = widget.controller ?? TextEditingController(text: widget.initialValue); + super.initState(); + _provider = Provider.of(context, listen: false); + } + + @override + void didUpdateWidget(covariant SystemAuditWoAutoCompleteField oldWidget) { + // if (widget.initialValue != oldWidget.initialValue) { + // // _controller = widget.controller ?? TextEditingController(text: widget.initialValue); + // } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + if (widget.controller == null) { + // _controller.dispose(); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10)); + return Container( + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + child: Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) async { + if (textEditingValue.text.isEmpty) { + if (loading) { + setState(() { + loading = false; + }); + } + return const Iterable.empty(); + } + if (!loading) { + setState(() { + loading = true; + }); + } + List workOrders = (await _provider.getWorkOrderByWoType(text: textEditingValue.text, woId:widget.woTypeId)); + setState(() { + loading = false; + }); + return workOrders; + }, + displayStringForOption: (WoAutoCompleteModel option) => option.displayName ?? '', + fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { + return TextField( + controller: widget.controller, + focusNode: fieldFocusNode, + style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), + textAlign: TextAlign.start, + decoration: InputDecoration( + border: border, + disabledBorder: border, + focusedBorder: border, + enabledBorder: border, + errorBorder: border, + contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), + constraints: const BoxConstraints(), + suffixIconConstraints: const BoxConstraints(maxHeight: 24, maxWidth: 24 + 8), + filled: true, + fillColor: AppColor.fieldBgColor(context), + errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), + floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), + labelText: context.translation.woNumber, + labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)), + suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null, + ), + textInputAction: TextInputAction.search, + onChanged: (text) { + fieldTextEditingController.text = text; + }, + onSubmitted: (String value) { + onFieldSubmitted(); + }, + ); + }, + onSelected: (WoAutoCompleteModel selection) { + if (widget.clearAfterPick) { + widget.controller.clear(); + } else { + widget.controller.text = (selection.displayName ?? ""); + } + widget.onPick(selection); + }, + ), + ); + } + + // String getUrl(int? woTypeId) { + // if (woTypeId == null) return ''; + // String base = URLs.woAutoCompleteBase; + // var urlMap = { + // 1: '$base/ServiceRequest/WorkOrderAutoComplete', // CM + // 2: '$base/GasRefill/GetGasRefillAutoComplete', // Gas Refill + // 3: '$base/AssetTransfer/GetAssetTransferAutoComplete', // Asset Transfer + // 4: '$base/PlanPreventiveVisit/GetAutoCompletePlanPreventiveVisit', // PPM Request + // 5: '$base/PlanRecurrentTasks/GetPlanRecurrentTask', // Recurrent WO + // 6: '$base/TaskJobs/AutocompleteTaskJob', // Task + // 7: '$base/TaskJobs/AutocompleteTaskJob', // Recall & Alert + // }; + // return urlMap[woTypeId] ?? ''; + // } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart similarity index 94% rename from lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart rename to lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart index dd36f431..a4f459fe 100644 --- a/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart @@ -16,20 +16,19 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; -class InternalAuditDetailPage extends StatefulWidget { - static const String id = "/details-internal-audit"; - +class SystemInternalAuditDetailPage extends StatefulWidget { + static const String id = "/details-system-internal-audit"; final int auditId; - InternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); + SystemInternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); @override - _InternalAuditDetailPageState createState() { - return _InternalAuditDetailPageState(); + _SystemInternalAuditDetailPageState createState() { + return _SystemInternalAuditDetailPageState(); } } -class _InternalAuditDetailPageState extends State { +class _SystemInternalAuditDetailPageState extends State { bool isWoType = true; @override diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart new file mode 100644 index 00000000..db6e2c11 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart @@ -0,0 +1,118 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class SystemInternalAuditItemView extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const SystemInternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + //TODO need to refactor this code repetation @waseem + log('request details ${requestDetails?.toJson()}'); + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestData!.statusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), + ), + 1.width.expanded, + Text( + requestData!.transactionDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), + infoWidget(label: context.translation.assetNo, value: requestData?.assetNumber, context: context), + + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), + infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context), + infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context), + infoWidget(label: context.translation.model, value: requestDetails!.model, context: context), + 8.height, + // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} diff --git a/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart index 3240bf2d..e4454551 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart @@ -15,7 +15,7 @@ class InternalAuditCheckListProvider extends LoadingListNotifier { notifyListeners(); Response response; try { - response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + response = await ApiManager.instance.get(URLs.getInternalAuditChecklist); } catch (error) { loading = false; stateCode = -1; diff --git a/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart index c9ee41a8..9371cb1d 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart @@ -14,7 +14,7 @@ class InternalAuditFindingTypeProvider extends LoadingListNotifier { notifyListeners(); Response response; try { - response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + response = await ApiManager.instance.get(URLs.getInternalAuditFindingType); } catch (error) { loading = false; stateCode = -1; diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart index 983bd6ca..6f2a9b9d 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -2,34 +2,66 @@ import 'dart:convert'; import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset_search.dart'; import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; class InternalAuditProvider extends ChangeNotifier { final pageItemNumber = 10; final searchPageItemNumber = 10; int pageNo = 1; + void reset() { pageNo = 1; stateCode = null; } + int? stateCode; bool isDetailLoading = false; bool nextPage = false; bool isNextPageLoading = false; bool isLoading = false; - Future getInternalAuditById(int id) async { + + Future getEquipmentInternalAuditById(int id) async { try { isLoading = true; notifyListeners(); - //Need to replace - Response response = await ApiManager.instance.get("${URLs.getTRAFById}?id=$id"); + Response response = await ApiManager.instance.get( + "${URLs.getInternalAuditEquipmentById}?internalAuditEquipmentId=$id", + ); if (response.statusCode >= 200 && response.statusCode < 300) { - // trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]); + final decodedBody = jsonDecode(response.body); + EquipmentInternalAuditDataModel model = EquipmentInternalAuditDataModel.fromJson(decodedBody["data"]); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; } + } catch (error) { + isLoading = false; + notifyListeners(); + return null; + } + } + + Future getInternalSystemAuditById(int id) async { + try { + isLoading = true; + notifyListeners(); + Response response = await ApiManager.instance.get("${URLs.getInternalAuditSystemById}?AuditSystemId=$id"); + if (response.statusCode >= 200 && response.statusCode < 300) {} isLoading = false; notifyListeners(); return 0; @@ -39,4 +71,44 @@ class InternalAuditProvider extends ChangeNotifier { return -1; } } + + Future addEquipmentInternalAudit({ + required BuildContext context, + required EquipmentInternalAuditFormModel request, + }) async { + bool status = false; + Response response; + try { + response = await ApiManager.instance.post(URLs.addOrUpdateEquipmentInternalAudit, body: request.toJson()); + if (response.statusCode >= 200 && response.statusCode < 300) { + status = true; + notifyListeners(); + } else { + Fluttertoast.showToast(msg: "${context.translation.failedRequestMessage} :${json.decode(response.body)['message']}"); + status = false; + } + return status; + } catch (error) { + print(error); + status = false; + notifyListeners(); + return status; + } + } + + Future> getWorkOrderByWoType({String? text, required int? woId}) async { + late Response response; + try { + Response response = await ApiManager.instance.get("${URLs.getWoAutoComplete}?workOrderTypeId=$woId&search=$text"); + // response = await ApiManager.instance.post(url, body: {"search": text}); + List woOrderList = []; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + woOrderList = categoriesListJson.map((wo) => WoAutoCompleteModel.fromJson(wo)).toList(); + } + return woOrderList; + } catch (error) { + return []; + } + } } diff --git a/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart new file mode 100644 index 00000000..7c7b4e5e --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart @@ -0,0 +1,35 @@ + +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class InternalAuditWoTypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading ?? false) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getInternalAuditWoType); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + diff --git a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart index 1988336f..c88e576d 100644 --- a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart +++ b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart @@ -9,8 +9,8 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 30f86273..2f7bf6d0 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -58,9 +58,9 @@ class _MyRequestsPageState extends State { requestsList.add(Request(9, 'TRAF')); } if (context.userProvider.isEngineer) { - //TODO need to replace with actual number. - // requestsList.add(Request(10, 'Internal Audit')); - requestsList.add(Request(1, 'Internal Audit')); + // TODO need to replace with actual number. + requestsList.add(Request(10, 'Equipment Internal Audit')); + requestsList.add(Request(11, 'System Internal Audit')); } if (context.userProvider.isAssessor) { @@ -73,9 +73,8 @@ class _MyRequestsPageState extends State { requestsList = [ Request(null, context.translation.allWorkOrder), //TODO need to replace with actual number. - - // Request(10, 'Internal Audit'), - Request(1, 'Internal Audit'), + Request(10, 'Equipment Internal Audit'), + Request(11, 'System Internal Audit'), ]; } diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index 7b172e50..97e9bf58 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -55,7 +56,8 @@ class RequestPaginatedListview extends StatelessWidget { bool isRecurrentTask = request.transactionNo == 5; bool isTask = request.transactionNo == 6; bool isTRAF = request.transactionNo == 9; - bool isInternalAudit = request.transactionNo == 10; + bool isEquipmentInternalAudit = request.transactionNo == 10; + bool isSystemInternalAudit = request.transactionNo == 11; if (isServiceRequest) { return ServiceRequestItemView(requestData: request, refreshData: false); @@ -69,14 +71,13 @@ class RequestPaginatedListview extends StatelessWidget { return RecurrentWoItemView(requestData: request); } else if (isTask) { return TaskRequestItemView(requestData: request); - } - else if (isTRAF) { + } else if (isTRAF) { return TrafRequestItemView(requestData: request); - } - else if (isInternalAudit) { - return InternalAuditItemView(requestData: request); - } - else { + } else if (isEquipmentInternalAudit) { + return EquipmentInternalAuditItemView(requestData: request); + } else if (isSystemInternalAudit) { + return SystemInternalAuditItemView(requestData: request); + } else { return Container( height: 100, width: double.infinity, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 08b1f51a..ec9b9d31 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -1,12 +1,16 @@ //request tab page +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart'; @@ -29,11 +33,19 @@ class RequestItemViewList extends StatelessWidget { shrinkWrap: true, itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); + if (list[index].transactionType == null) { + return EquipmentInternalAuditItemView(requestDetails: list[index]); + // return Container( + // height: 100, + // width: double.infinity, + // color: AppColor.neutral40, + // ); + } switch (list[index].transactionType) { - // case 1: - // return ServiceRequestItemView(requestDetails: list[index]); case 1: - return InternalAuditItemView(requestDetails: list[index]); + return ServiceRequestItemView(requestDetails: list[index]); + // case 1: + // return InternalAuditItemView(requestDetails: list[index]); case 2: return GasRefillItemView(requestDetails: list[index]); case 3: @@ -48,9 +60,11 @@ class RequestItemViewList extends StatelessWidget { return TaskRequestItemView(requestDetails: list[index]); case 9: return TrafRequestItemView(requestDetails: list[index]); - //Need to verify the type No.. - case 10: - return InternalAuditItemView(requestDetails: list[index]); + //Need to verify the type No.. + case 10: + return EquipmentInternalAuditItemView(requestDetails: list[index]); + case 11: + return SystemInternalAuditItemView(requestDetails: list[index]); default: Container( height: 100, From 81dd799672c33480e3d9b5638617c30c9297fff4 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 6 Nov 2025 11:44:08 +0300 Subject: [PATCH 07/31] internal audit api's implementation in progress --- .../equipment_internal_audit_detail_page.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart index 465a42db..6d842b29 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart @@ -75,15 +75,15 @@ class _EquipmentInternalAuditDetailPageState extends State Date: Sun, 9 Nov 2025 17:19:14 +0300 Subject: [PATCH 08/31] chat provider , api client added. --- .../cx_module/chat/chat_api_client.dart | 316 +++ lib/modules/cx_module/chat/chat_provider.dart | 1963 +++++++++++++++++ 2 files changed, 2279 insertions(+) create mode 100644 lib/modules/cx_module/chat/chat_api_client.dart create mode 100644 lib/modules/cx_module/chat/chat_provider.dart diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart new file mode 100644 index 00000000..5af7d273 --- /dev/null +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -0,0 +1,316 @@ +// import 'dart:convert'; +// import 'dart:io'; +// import 'dart:typed_data'; +// +// import 'package:flutter/foundation.dart'; +// import 'package:flutter/material.dart'; +// import 'package:http/http.dart'; +// 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/exceptions/api_exception.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/create_group_request.dart' as createGroup; +// import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart'; +// import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; +// import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' as groups; +// import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +// import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user; +// import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; +// +// class ChatApiClient { +// static final ChatApiClient _instance = ChatApiClient._internal(); +// +// ChatApiClient._internal(); +// +// factory ChatApiClient() => _instance; +// +// Future getUserLoginToken() async { +// user.UserAutoLoginModel userLoginResponse = user.UserAutoLoginModel(); +// String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken; +// Response response = await ApiClient().postJsonForResponse( +// "${ApiConsts.chatLoginTokenUrl}externaluserlogin", +// { +// "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), +// "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", +// "isMobile": true, +// "platform": Platform.isIOS ? "ios" : "android", +// "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, +// "isHuaweiDevice": AppState().getIsHuawei, +// "voipToken": Platform.isIOS ? "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba" : "", +// }, +// ); +// +// if (!kReleaseMode) { +// logger.i("login-res: " + response.body); +// } +// if (response.statusCode == 200) { +// userLoginResponse = user.userAutoLoginModelFromJson(response.body); +// } else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) { +// getUserLoginToken(); +// } else { +// userLoginResponse = user.userAutoLoginModelFromJson(response.body); +// Utils.showToast(userLoginResponse.errorResponses!.first.message!); +// } +// return userLoginResponse; +// } +// +// Future getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { +// ChatUserModel chatUserModel; +// Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo}, +// token: AppState().chatDetails!.response!.token); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// chatUserModel = chatUserModelFromJson(response.body); +// return chatUserModel; +// } +// +// //Get User Recent Chats +// Future getRecentChats() async { +// try { +// Response response = await ApiClient().getJsonForResponse( +// "${ApiConsts.chatRecentUrl}getchathistorybyuserid", +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return ChatUserModel.fromJson( +// json.decode(response.body), +// ); +// } catch (e) { +// throw e; +// } +// } +// +// // Get Favorite Users +// Future getFavUsers() async { +// Response favRes = await ApiClient().getJsonForResponse( +// "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}", +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + favRes.body); +// } +// return ChatUserModel.fromJson(json.decode(favRes.body)); +// } +// +// //Get User Chat History +// Future getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { +// try { +// Response response = await ApiClient().getJsonForResponse( +// "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return response; +// } catch (e) { +// getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); +// throw e; +// } +// } +// +// //Favorite Users +// Future favUser({required int userID, required int targetUserID}) async { +// Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); +// return favoriteChatUser; +// } +// +// //UnFavorite Users +// Future unFavUser({required int userID, required int targetUserID}) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// "${ApiConsts.chatFavUser}deleteFavUser", +// {"targetUserId": targetUserID, "userId": userID}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); +// return favoriteChatUser; +// } catch (e) { +// e as APIException; +// throw e; +// } +// } +// +// // Upload Chat Media +// Future uploadMedia(String userId, File file, String fileSource) async { +// if (kDebugMode) { +// print("${ApiConsts.chatMediaImageUploadUrl}upload"); +// print(AppState().chatDetails!.response!.token); +// } +// +// dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); +// request.fields.addAll({'userId': userId, 'fileSource': fileSource}); +// request.files.add(await MultipartFile.fromPath('files', file.path)); +// request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); +// StreamedResponse response = await request.send(); +// String data = await response.stream.bytesToString(); +// if (!kReleaseMode) { +// logger.i("res: " + data); +// } +// return jsonDecode(data); +// } +// +// // Download File For Chat +// Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { +// Response response = await ApiClient().postJsonForResponse( +// "${ApiConsts.chatMediaImageUploadUrl}download", +// {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, +// token: AppState().chatDetails!.response!.token, +// ); +// Uint8List data = Uint8List.fromList(response.bodyBytes); +// return data; +// } +// +// //Get Chat Users & Favorite Images +// Future> getUsersImages({required List encryptedEmails}) async { +// List imagesData = []; +// Response response = await ApiClient().postJsonForResponse( +// "${ApiConsts.chatUserImages}images", +// {"encryptedEmails": encryptedEmails, "fromClient": false}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// if (response.statusCode == 200) { +// imagesData = chatUserImageModelFromJson(response.body); +// } else if (response.statusCode == 500 || response.statusCode == 504) { +// getUsersImages(encryptedEmails: encryptedEmails); +// } else { +// Utils.showToast("Something went wrong while loading images"); +// imagesData = []; +// } +// return imagesData; +// } +// +// //group chat apis start here. +// Future getGroupsByUserId() async { +// try { +// Response response = await ApiClient().getJsonForResponse( +// "${ApiConsts.getGroupByUserId}${AppState().chatDetails!.response!.id}", +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return groups.GetUserGroups.fromRawJson(response.body); +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; +// } +// } +// +// Future deleteGroup(int? groupId) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.deleteGroup, +// {"groupId": groupId}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return response; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; +// } +// } +// +// Future updateGroupAdmin(int? groupId, List groupList) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.updateGroupAdmin, +// {"groupId": groupId, "groupUserList": groupList}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return response; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; +// } +// } +// +// Future> getGroupChatHistory(int? groupId, List groupList) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.getGroupChatHistoryAsync, +// {"groupId": groupId, "targetUserList": groupList, "CurrentId": AppState().chatDetails!.response!.id}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// List groupChat = []; +// List groupChatData = json.decode(response.body); +// for (var i in groupChatData) { +// groupChat.add(GetGroupChatHistoryAsync.fromJson(i)); +// } +// +// groupChat.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); +// return groupChat; +// // for(GetGroupChatHistoryAsync i in groupChat) { +// // return GetGroupChatHistoryAsync.fromJson(jsonEncode(i)); +// // } +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; +// } +// } +// +// Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.addGroupsAndUsers, +// request, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return response.body; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; +// } +// } +// +// Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.updateGroupsAndUsers, +// request, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return response.body; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; +// } +// } +// } diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart new file mode 100644 index 00000000..b8668078 --- /dev/null +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -0,0 +1,1963 @@ +// import 'dart:async'; +// import 'dart:convert'; +// import 'dart:io'; +// import 'dart:typed_data'; +// import 'package:audio_waveforms/audio_waveforms.dart'; +// import 'package:easy_localization/easy_localization.dart'; +// import 'package:flutter/cupertino.dart'; +// import 'package:flutter/foundation.dart'; +// import 'package:flutter/services.dart'; +// import 'package:http/http.dart'; +// import 'package:just_audio/just_audio.dart' as JustAudio; +// import 'package:just_audio/just_audio.dart'; +// import 'package:mohem_flutter_app/api/chat/chat_api_client.dart'; +// import 'package:mohem_flutter_app/api/my_team/my_team_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/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/create_group_request.dart' as createGroup; +// import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart' as groupchathistory; +// import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; +// import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; +// import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' as groups; +// import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; +// 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/chat/target_users.dart'; +// 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_filex/open_filex.dart'; +// import 'package:path_provider/path_provider.dart'; +// import 'package:permission_handler/permission_handler.dart'; +// import 'package:signalr_netcore/hub_connection.dart'; +// import 'package:signalr_netcore/signalr_client.dart'; +// import 'package:uuid/uuid.dart'; +// import 'package:flutter/material.dart' as Material; +// +// class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { +// ScrollController scrollController = ScrollController(); +// +// TextEditingController message = TextEditingController(); +// TextEditingController search = TextEditingController(); +// TextEditingController searchGroup = TextEditingController(); +// +// List userChatHistory = [], repliedMsg = []; +// List? pChatHistory, searchedChats; +// String chatCID = ''; +// bool isLoading = true; +// bool isChatScreenActive = false; +// int receiverID = 0; +// late File selectedFile; +// String sFileType = ""; +// +// List favUsersList = []; +// int paginationVal = 0; +// int? cTypingUserId = 0; +// bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; +// +// // Audio Recoding Work +// Timer? _timer; +// int _recodeDuration = 0; +// bool isRecoding = false; +// bool isPause = false; +// bool isPlaying = false; +// String? path; +// String? musicFile; +// late Directory appDirectory; +// late RecorderController recorderController; +// late PlayerController playerController; +// List getEmployeeSubordinatesList = []; +// List teamMembersList = []; +// groups.GetUserGroups userGroups = groups.GetUserGroups(); +// Material.TextDirection textDirection = Material.TextDirection.ltr; +// bool isRTL = false; +// String msgText = ""; +// +// //Chat Home Page Counter +// int chatUConvCounter = 0; +// +// late List groupChatHistory, groupChatReplyData; +// +// /// Search Provider +// List? chatUsersList = []; +// int pageNo = 1; +// +// bool disbaleChatForThisUser = false; +// List? uGroups = [], searchGroups = []; +// +// Future getUserAutoLoginToken() async { +// userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); +// +// if (userLoginResponse.StatusCode == 500) { +// disbaleChatForThisUser = true; +// notifyListeners(); +// } +// +// if (userLoginResponse.response != null) { +// AppState().setchatUserDetails = userLoginResponse; +// } else { +// AppState().setchatUserDetails = userLoginResponse; +// Utils.showToast( +// userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", +// ); +// disbaleChatForThisUser = true; +// notifyListeners(); +// } +// } +// +// Future buildHubConnection() async { +// chatHubConnection = await getHubConnection(); +// await chatHubConnection.start(); +// if (kDebugMode) { +// logger.i("Hub Conn: Startedddddddd"); +// } +// chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); +// chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); +// +// //group On message +// +// chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived); +// } +// +// Future getHubConnection() async { +// HubConnection hub; +// HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); +// hub = HubConnectionBuilder() +// .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) +// .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); +// return hub; +// } +// +// void registerEvents() { +// chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); +// // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); +// +// chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); +// chatHubConnection.on("OnUserTypingAsync", onUserTyping); +// chatHubConnection.on("OnUserCountAsync", userCountAsync); +// // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); +// chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); +// chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); +// chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); +// +// // +// // {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]} +// +// if (kDebugMode) { +// logger.i("All listeners registered"); +// } +// } +// +// Future getUserRecentChats() async { +// ChatUserModel recentChat = await ChatApiClient().getRecentChats(); +// ChatUserModel favUList = await ChatApiClient().getFavUsers(); +// // userGroups = await ChatApiClient().getGroupsByUserId(); +// if (favUList.response != null && recentChat.response != null) { +// favUsersList = favUList.response!; +// 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) { +// user.isFav = favUser.isFav; +// } +// } +// } +// } +// pChatHistory = recentChat.response ?? []; +// uGroups = userGroups.groupresponse ?? []; +// 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())); +// sort(); +// notifyListeners(); +// if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { +// getUserImages(); +// } +// } +// +// Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { +// await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); +// return ""; +// } +// +// void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { +// isLoading = true; +// if (isNewChat) userChatHistory = []; +// if (!loadMore) paginationVal = 0; +// isChatScreenActive = true; +// receiverID = receiverUID; +// Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); +// if (response.statusCode == 204) { +// if (isNewChat) { +// userChatHistory = []; +// } else if (loadMore) {} +// } else { +// if (loadMore) { +// List temp = getSingleUserChatModel(response.body).reversed.toList(); +// userChatHistory.addAll(temp); +// } else { +// userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); +// } +// } +// isLoading = false; +// notifyListeners(); +// +// if (isChatScreenActive && receiverUID == receiverID) { +// markRead(userChatHistory, receiverUID); +// } +// +// generateConvId(); +// } +// +// void generateConvId() async { +// Uuid uuid = const Uuid(); +// chatCID = uuid.v4(); +// } +// +// void markRead(List data, int receiverID) { +// for (SingleUserChatModel element in data!) { +// if (AppState().chatDetails!.response!.id! == element.targetUserId) { +// if (element.isSeen != null) { +// if (!element.isSeen!) { +// element.isSeen = true; +// dynamic data = [ +// { +// "userChatHistoryId": element.userChatHistoryId, +// "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, +// "isDelivered": true, +// "isSeen": true, +// } +// ]; +// updateUserChatHistoryStatusAsync(data); +// notifyListeners(); +// } +// } +// for (ChatUser element in searchedChats!) { +// if (element.id == receiverID) { +// element.unreadMessageCount = 0; +// chatUConvCounter = 0; +// } +// } +// } +// } +// notifyListeners(); +// } +// +// void updateUserChatHistoryStatusAsync(List data) { +// try { +// chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); +// } catch (e) { +// throw e; +// } +// } +// +// void updateUserChatHistoryOnMsg(List data) { +// try { +// chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); +// } catch (e) { +// throw e; +// } +// } +// +// List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); +// +// List getGroupChatHistoryAsync(String str) => +// List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); +// +// Future uploadAttachments(String userId, File file, String fileSource) async { +// dynamic result; +// try { +// Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); +// if (response != null) { +// result = response; +// } else { +// result = []; +// } +// } catch (e) { +// throw e; +// } +// return result; +// } +// +// void updateUserChatStatus(List? args) { +// dynamic items = args!.toList(); +// for (var cItem in items[0]) { +// for (SingleUserChatModel chat in userChatHistory) { +// if (cItem["contantNo"].toString() == chat.contantNo.toString()) { +// chat.isSeen = cItem["isSeen"]; +// chat.isDelivered = cItem["isDelivered"]; +// } +// } +// } +// notifyListeners(); +// } +// +// void getGroupUserStatus(List? args) { +// //note: need to implement this function... +// print(args); +// } +// +// void onChatSeen(List? args) { +// dynamic items = args!.toList(); +// // for (var user in searchedChats!) { +// // if (user.id == items.first["id"]) { +// // user.userStatus = items.first["userStatus"]; +// // } +// // } +// // notifyListeners(); +// } +// +// void userCountAsync(List? args) { +// dynamic items = args!.toList(); +// // logger.d(items); +// //logger.d("---------------------------------User Count Async -------------------------------------"); +// //logger.d(items); +// // for (var user in searchedChats!) { +// // if (user.id == items.first["id"]) { +// // user.userStatus = items.first["userStatus"]; +// // } +// // } +// // notifyListeners(); +// } +// +// void updateChatHistoryWindow(List? args) { +// dynamic items = args!.toList(); +// if (kDebugMode) { +// logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); +// } +// logger.d(items); +// // for (var user in searchedChats!) { +// // if (user.id == items.first["id"]) { +// // user.userStatus = items.first["userStatus"]; +// // } +// // } +// // notifyListeners(); +// } +// +// void chatNotDelivered(List? args) { +// dynamic items = args!.toList(); +// for (dynamic item in items[0]) { +// for (ChatUser element in searchedChats!) { +// if (element.id == item["currentUserId"]) { +// int? val = element.unreadMessageCount ?? 0; +// element.unreadMessageCount = val! + 1; +// } +// } +// } +// notifyListeners(); +// } +// +// void changeStatus(List? args) { +// dynamic items = args!.toList(); +// for (ChatUser user in searchedChats!) { +// 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"]; +// } +// } +// } +// +// notifyListeners(); +// } +// +// void filter(String value) async { +// List? tmp = []; +// if (value.isEmpty || value == "") { +// tmp = pChatHistory; +// } else { +// for (ChatUser element in pChatHistory!) { +// if (element.userName!.toLowerCase().contains(value.toLowerCase())) { +// tmp.add(element); +// } +// } +// } +// searchedChats = tmp; +// notifyListeners(); +// } +// +// Future onMsgReceived(List? parameters) async { +// List data = [], temp = []; +// for (dynamic msg in parameters!) { +// data = getSingleUserChatModel(jsonEncode(msg)); +// temp = getSingleUserChatModel(jsonEncode(msg)); +// data.first.targetUserId = temp.first.currentUserId; +// data.first.targetUserName = temp.first.currentUserName; +// data.first.targetUserEmail = temp.first.currentUserEmail; +// data.first.currentUserId = temp.first.targetUserId; +// data.first.currentUserName = temp.first.targetUserName; +// data.first.currentUserEmail = temp.first.targetUserEmail; +// +// if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { +// data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); +// } +// if (data.first.userChatReplyResponse != null) { +// if (data.first.fileTypeResponse != null) { +// if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { +// data.first.userChatReplyResponse!.image = await ChatApiClient() +// .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); +// data.first.userChatReplyResponse!.isImageLoaded = true; +// } +// } +// } +// } +// +// if (searchedChats != null) { +// dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); +// if (contain.isEmpty) { +// List emails = []; +// emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); +// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// searchedChats!.add( +// ChatUser( +// id: data.first.currentUserId, +// userName: data.first.currentUserName, +// email: data.first.currentUserEmail, +// unreadMessageCount: 0, +// isImageLoading: false, +// image: chatImages!.first.profilePicture ?? "", +// isImageLoaded: true, +// userStatus: 1, +// isTyping: false, +// userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), +// ), +// ); +// } +// } +// setMsgTune(); +// if (isChatScreenActive && data.first.currentUserId == receiverID) { +// userChatHistory.insert(0, data.first); +// } else { +// if (searchedChats != null) { +// for (ChatUser user in searchedChats!) { +// if (user.id == data.first.currentUserId) { +// int tempCount = user.unreadMessageCount ?? 0; +// user.unreadMessageCount = tempCount + 1; +// } +// } +// sort(); +// } +// } +// +// List list = [ +// { +// "userChatHistoryId": data.first.userChatHistoryId, +// "TargetUserId": temp.first.targetUserId, +// "isDelivered": true, +// "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false +// } +// ]; +// updateUserChatHistoryOnMsg(list); +// invokeChatCounter(userId: AppState().chatDetails!.response!.id!); +// notifyListeners(); +// } +// +// Future onGroupMsgReceived(List? parameters) async { +// List data = [], temp = []; +// +// for (dynamic msg in parameters!) { +// // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); +// data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); +// temp = data; +// // data.first.currentUserId = temp.first.currentUserId; +// // data.first.currentUserName = temp.first.currentUserName; +// // +// // data.first.currentUserId = temp.first.currentUserId; +// // data.first.currentUserName = temp.first.currentUserName; +// +// if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { +// data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); +// } +// if (data.first.groupChatReplyResponse != null) { +// if (data.first.fileTypeResponse != null) { +// if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { +// data.first.groupChatReplyResponse!.image = await ChatApiClient() +// .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); +// data.first.groupChatReplyResponse!.isImageLoaded = true; +// } +// } +// } +// } +// +// // if (searchedChats != null) { +// // dynamic contain = searchedChats! +// // .where((ChatUser element) => element.id == data.first.currentUserId); +// // if (contain.isEmpty) { +// // List emails = []; +// // emails.add(await EmailImageEncryption() +// // .encrypt(val: data.first.currentUserEmail!)); +// // List chatImages = +// // await ChatApiClient().getUsersImages(encryptedEmails: emails); +// // searchedChats!.add( +// // ChatUser( +// // id: data.first.currentUserId, +// // userName: data.first.currentUserName, +// // email: data.first.currentUserEmail, +// // unreadMessageCount: 0, +// // isImageLoading: false, +// // image: chatImages!.first.profilePicture ?? "", +// // isImageLoaded: true, +// // userStatus: 1, +// // isTyping: false, +// // userLocalDownlaodedImage: await downloadImageLocal( +// // chatImages.first.profilePicture, +// // data.first.currentUserId.toString()), +// // ), +// // ); +// // } +// // } +// groupChatHistory.insert(0, data.first); +// setMsgTune(); +// // if (isChatScreenActive && data.first.currentUserId == receiverID) { +// +// // } else { +// // if (searchedChats != null) { +// // for (ChatUser user in searchedChats!) { +// // if (user.id == data.first.currentUserId) { +// // int tempCount = user.unreadMessageCount ?? 0; +// // user.unreadMessageCount = tempCount + 1; +// // } +// // } +// sort(); +// //} +// //} +// // +// // List list = [ +// // { +// // "userChatHistoryId": data.first.groupId, +// // "TargetUserId": temp.first.currentUserId, +// // "isDelivered": true, +// // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID +// // ? true +// // : false +// // } +// // ]; +// // updateUserChatHistoryOnMsg(list); +// // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); +// notifyListeners(); +// } +// +// void OnSubmitChatAsync(List? parameters) { +// print(isChatScreenActive); +// print(receiverID); +// print(isChatScreenActive); +// logger.i(parameters); +// List data = [], temp = []; +// for (dynamic msg in parameters!) { +// data = getSingleUserChatModel(jsonEncode(msg)); +// temp = getSingleUserChatModel(jsonEncode(msg)); +// data.first.targetUserId = temp.first.currentUserId; +// data.first.targetUserName = temp.first.currentUserName; +// data.first.targetUserEmail = temp.first.currentUserEmail; +// data.first.currentUserId = temp.first.targetUserId; +// data.first.currentUserName = temp.first.targetUserName; +// data.first.currentUserEmail = temp.first.targetUserEmail; +// } +// if (isChatScreenActive && data.first.currentUserId == receiverID) { +// int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); +// logger.d(index); +// userChatHistory[index] = data.first; +// } +// +// notifyListeners(); +// } +// +// void sort() { +// searchedChats!.sort( +// (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), +// ); +// } +// +// void onUserTyping(List? parameters) { +// for (ChatUser user in searchedChats!) { +// if (user.id == parameters![1] && parameters[0] == true) { +// user.isTyping = parameters[0] as bool?; +// Future.delayed( +// const Duration(seconds: 2), +// () { +// user.isTyping = false; +// notifyListeners(); +// }, +// ); +// } +// } +// notifyListeners(); +// } +// +// int getFileType(String value) { +// switch (value) { +// case ".pdf": +// return 1; +// case ".png": +// return 3; +// case ".txt": +// return 5; +// case ".jpg": +// return 12; +// case ".jpeg": +// return 4; +// case ".xls": +// return 7; +// case ".xlsx": +// return 7; +// case ".doc": +// return 6; +// case ".docx": +// return 6; +// case ".ppt": +// return 8; +// case ".pptx": +// return 8; +// case ".zip": +// return 2; +// case ".rar": +// return 2; +// case ".aac": +// return 13; +// case ".mp3": +// return 14; +// case ".mp4": +// return 16; +// case ".mov": +// return 16; +// case ".avi": +// return 16; +// case ".flv": +// return 16; +// +// default: +// return 0; +// } +// } +// +// String getFileTypeDescription(String value) { +// switch (value) { +// case ".pdf": +// return "application/pdf"; +// case ".png": +// return "image/png"; +// case ".txt": +// return "text/plain"; +// case ".jpg": +// return "image/jpg"; +// case ".jpeg": +// return "image/jpeg"; +// case ".ppt": +// return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; +// case ".pptx": +// return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; +// case ".doc": +// return "application/vnd.openxmlformats-officedocument.wordprocessingm"; +// case ".docx": +// return "application/vnd.openxmlformats-officedocument.wordprocessingm"; +// case ".xls": +// return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; +// case ".xlsx": +// return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; +// case ".zip": +// return "application/octet-stream"; +// case ".rar": +// return "application/octet-stream"; +// case ".aac": +// return "audio/aac"; +// case ".mp3": +// return "audio/mp3"; +// case ".mp4": +// return "video/mp4"; +// case ".avi": +// return "video/avi"; +// case ".flv": +// return "video/flv"; +// case ".mov": +// return "video/mov"; +// +// default: +// return ""; +// } +// } +// +// Future sendChatToServer( +// {required int chatEventId, +// required fileTypeId, +// required int targetUserId, +// required String targetUserName, +// required chatReplyId, +// required bool isAttachment, +// required bool isReply, +// Uint8List? image, +// required bool isImageLoaded, +// String? userEmail, +// int? userStatus, +// File? voiceFile, +// required bool isVoiceAttached}) async { +// Uuid uuid = const Uuid(); +// String contentNo = uuid.v4(); +// String msg; +// if (isVoiceAttached) { +// msg = voiceFile!.path.split("/").last; +// } else { +// msg = message.text; +// logger.w(msg); +// } +// SingleUserChatModel data = SingleUserChatModel( +// userChatHistoryId: 0, +// chatEventId: chatEventId, +// chatSource: 1, +// contant: msg, +// contantNo: contentNo, +// conversationId: chatCID, +// createdDate: DateTime.now(), +// currentUserId: AppState().chatDetails!.response!.id, +// currentUserName: AppState().chatDetails!.response!.userName, +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isReplied: false, +// fileTypeId: fileTypeId, +// userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, +// fileTypeResponse: isAttachment +// ? FileTypeResponse( +// fileTypeId: fileTypeId, +// fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), +// fileKind: "file", +// fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, +// fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), +// ) +// : null, +// image: image, +// isImageLoaded: isImageLoaded, +// voice: isVoiceMsg ? voiceFile! : null, +// voiceController: isVoiceMsg ? AudioPlayer() : null); +// if (kDebugMode) { +// logger.i("model data: " + jsonEncode(data)); +// } +// userChatHistory.insert(0, data); +// isTextMsg = false; +// isReplyMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// sFileType = ""; +// message.clear(); +// notifyListeners(); +// +// String chatData = +// '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; +// +// await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); +// } +// +// //groupChatMessage +// +// Future sendGroupChatToServer( +// {required int chatEventId, +// required fileTypeId, +// required int targetGroupId, +// required String targetUserName, +// required chatReplyId, +// required bool isAttachment, +// required bool isReply, +// Uint8List? image, +// required bool isImageLoaded, +// String? userEmail, +// int? userStatus, +// File? voiceFile, +// required bool isVoiceAttached, +// required List userList}) async { +// Uuid uuid = const Uuid(); +// String contentNo = uuid.v4(); +// String msg; +// if (isVoiceAttached) { +// msg = voiceFile!.path.split("/").last; +// } else { +// msg = message.text; +// logger.w(msg); +// } +// groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( +// //userChatHistoryId: 0, +// chatEventId: chatEventId, +// chatSource: 1, +// contant: msg, +// contantNo: contentNo, +// conversationId: chatCID, +// createdDate: DateTime.now().toString(), +// currentUserId: AppState().chatDetails!.response!.id, +// currentUserName: AppState().chatDetails!.response!.userName, +// groupId: targetGroupId, +// groupName: targetUserName, +// isReplied: false, +// fileTypeId: fileTypeId, +// fileTypeResponse: isAttachment +// ? groupchathistory.FileTypeResponse( +// fileTypeId: fileTypeId, +// fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), +// fileKind: "file", +// fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, +// fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) +// : null, +// image: image, +// isImageLoaded: isImageLoaded, +// voice: isVoiceMsg ? voiceFile! : null, +// voiceController: isVoiceMsg ? AudioPlayer() : null); +// if (kDebugMode) { +// logger.i("model data: " + jsonEncode(data)); +// } +// groupChatHistory.insert(0, data); +// isTextMsg = false; +// isReplyMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// sFileType = ""; +// message.clear(); +// notifyListeners(); +// +// List targetUsers = []; +// +// for (GroupUserList element in userList) { +// targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); +// } +// +// String chatData = +// '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; +// +// await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); +// } +// +// void sendGroupChatMessage( +// BuildContext context, { +// required int targetUserId, +// required int userStatus, +// required String userEmail, +// required String targetUserName, +// required List userList, +// }) async { +// if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Text Message"); +// if (message.text.isEmpty) { +// return; +// } +// sendGroupChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: false, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: false, +// image: null, +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Text Message as Reply"); +// if (message.text.isEmpty) { +// return; +// } +// sendGroupChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: groupChatReplyData.first.groupChatHistoryId, +// isAttachment: false, +// isReply: true, +// isImageLoaded: groupChatReplyData.first.isImageLoaded!, +// image: groupChatReplyData.first.image, +// isVoiceAttached: false, +// voiceFile: null, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } +// // Attachment +// else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Image Message"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Image as Reply Msg"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: repliedMsg.first.userChatHistoryId, +// isReply: true, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } +// //Voice +// +// else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Voice Message"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// //, +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// notifyListeners(); +// } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { +// logger.d("// Voice as Reply Msg"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// notifyListeners(); +// } +// if (searchedChats != null) { +// dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); +// if (contain.isEmpty) { +// List emails = []; +// emails.add(await EmailImageEncryption().encrypt(val: userEmail)); +// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// searchedChats!.add( +// ChatUser( +// id: targetUserId, +// userName: targetUserName, +// unreadMessageCount: 0, +// email: userEmail, +// isImageLoading: false, +// image: chatImages.first.profilePicture ?? "", +// isImageLoaded: true, +// isTyping: false, +// isFav: false, +// userStatus: userStatus, +// // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), +// ), +// ); +// notifyListeners(); +// } +// } +// } +// +// void sendChatMessage( +// BuildContext context, { +// required int targetUserId, +// required int userStatus, +// required String userEmail, +// required String targetUserName, +// }) async { +// if (kDebugMode) { +// print("====================== Values ============================"); +// print("Is Text " + isTextMsg.toString()); +// print("isReply " + isReplyMsg.toString()); +// print("isAttachment " + isAttachmentMsg.toString()); +// print("isVoice " + isVoiceMsg.toString()); +// } +// //Text +// if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Text Message"); +// if (message.text.isEmpty) { +// return; +// } +// sendChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: false, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: false, +// image: null, +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus); +// } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Text Message as Reply"); +// if (message.text.isEmpty) { +// return; +// } +// sendChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: repliedMsg.first.userChatHistoryId, +// isAttachment: false, +// isReply: true, +// isImageLoaded: repliedMsg.first.isImageLoaded!, +// image: repliedMsg.first.image, +// isVoiceAttached: false, +// voiceFile: null, +// userEmail: userEmail, +// userStatus: userStatus); +// } +// // Attachment +// else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Image Message"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus); +// } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Image as Reply Msg"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: repliedMsg.first.userChatHistoryId, +// isReply: true, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus); +// } +// //Voice +// +// else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Voice Message"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus); +// notifyListeners(); +// } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { +// logger.d("// Voice as Reply Msg"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus); +// notifyListeners(); +// } +// if (searchedChats != null) { +// dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); +// if (contain.isEmpty) { +// List emails = []; +// emails.add(await EmailImageEncryption().encrypt(val: userEmail)); +// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// searchedChats!.add( +// ChatUser( +// id: targetUserId, +// userName: targetUserName, +// unreadMessageCount: 0, +// email: userEmail, +// isImageLoading: false, +// image: chatImages.first.profilePicture ?? "", +// isImageLoaded: true, +// isTyping: false, +// isFav: false, +// userStatus: userStatus, +// userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), +// ), +// ); +// notifyListeners(); +// } +// } +// // else { +// // List emails = []; +// // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); +// // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// // searchedChats!.add( +// // ChatUser( +// // id: targetUserId, +// // userName: targetUserName, +// // unreadMessageCount: 0, +// // email: userEmail, +// // isImageLoading: false, +// // image: chatImages.first.profilePicture ?? "", +// // isImageLoaded: true, +// // isTyping: false, +// // isFav: false, +// // userStatus: userStatus, +// // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), +// // ), +// // ); +// // notifyListeners(); +// // } +// } +// +// void selectImageToUpload(BuildContext context) { +// ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { +// if (checkFileSize(file.path)) { +// selectedFile = file; +// isAttachmentMsg = true; +// isTextMsg = false; +// sFileType = getFileExtension(file.path)!; +// message.text = file.path.split("/").last; +// Navigator.of(context).pop(); +// } else { +// Utils.showToast("Max 1 mb size is allowed to upload"); +// } +// notifyListeners(); +// }); +// } +// +// void removeAttachment() { +// isAttachmentMsg = false; +// sFileType = ""; +// message.text = ''; +// notifyListeners(); +// } +// +// String? getFileExtension(String fileName) { +// try { +// if (kDebugMode) { +// logger.i("ext: " + "." + fileName.split('.').last); +// } +// return "." + fileName.split('.').last; +// } catch (e) { +// return null; +// } +// } +// +// bool checkFileSize(String path) { +// int fileSizeLimit = 5120; +// File f = File(path); +// double fileSizeInKB = f.lengthSync() / 5000; +// double fileSizeInMB = fileSizeInKB / 5000; +// if (fileSizeInKB > fileSizeLimit) { +// return false; +// } else { +// return true; +// } +// } +// +// String getType(String type) { +// switch (type) { +// case ".pdf": +// return "assets/images/pdf.svg"; +// case ".png": +// return "assets/images/png.svg"; +// case ".txt": +// return "assets/icons/chat/txt.svg"; +// case ".jpg": +// return "assets/images/jpg.svg"; +// case ".jpeg": +// return "assets/images/jpg.svg"; +// case ".xls": +// return "assets/icons/chat/xls.svg"; +// case ".xlsx": +// return "assets/icons/chat/xls.svg"; +// case ".doc": +// return "assets/icons/chat/doc.svg"; +// case ".docx": +// return "assets/icons/chat/doc.svg"; +// case ".ppt": +// return "assets/icons/chat/ppt.svg"; +// case ".pptx": +// return "assets/icons/chat/ppt.svg"; +// case ".zip": +// return "assets/icons/chat/zip.svg"; +// case ".rar": +// return "assets/icons/chat/zip.svg"; +// case ".aac": +// return "assets/icons/chat/aac.svg"; +// case ".mp3": +// return "assets/icons/chat/zip.mp3"; +// default: +// return "assets/images/thumb.svg"; +// } +// } +// +// void chatReply(SingleUserChatModel data) { +// repliedMsg = []; +// data.isReplied = true; +// isReplyMsg = true; +// repliedMsg.add(data); +// notifyListeners(); +// } +// +// void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { +// groupChatReplyData = []; +// data.isReplied = true; +// isReplyMsg = true; +// groupChatReplyData.add(data); +// notifyListeners(); +// } +// +// void closeMe() { +// repliedMsg = []; +// isReplyMsg = false; +// notifyListeners(); +// } +// +// String dateFormte(DateTime data) { +// DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); +// f.format(data); +// return f.format(data); +// } +// +// Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { +// fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); +// if (favoriteChatUser.response != null) { +// for (ChatUser user in searchedChats!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); +// if (contain.isEmpty) { +// favUsersList.add(user); +// } +// } +// } +// +// for (ChatUser user in chatUsersList!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); +// if (contain.isEmpty) { +// favUsersList.add(user); +// } +// } +// } +// } +// if (fromSearch) { +// for (ChatUser user in favUsersList) { +// if (user.id == targetUserID) { +// user.userLocalDownlaodedImage = null; +// user.isImageLoading = false; +// user.isImageLoaded = false; +// } +// } +// } +// notifyListeners(); +// } +// +// Future unFavoriteUser({required int userID, required int targetUserID}) async { +// fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); +// +// if (favoriteChatUser.response != null) { +// for (ChatUser user in searchedChats!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// } +// } +// favUsersList.removeWhere( +// (ChatUser element) => element.id == targetUserID, +// ); +// } +// +// for (ChatUser user in chatUsersList!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// } +// } +// +// notifyListeners(); +// } +// +// void clearSelections() { +// searchedChats = pChatHistory; +// search.clear(); +// isChatScreenActive = false; +// receiverID = 0; +// paginationVal = 0; +// message.text = ''; +// isAttachmentMsg = false; +// repliedMsg = []; +// sFileType = ""; +// isReplyMsg = false; +// isTextMsg = false; +// isVoiceMsg = false; +// notifyListeners(); +// } +// +// void clearAll() { +// searchedChats = pChatHistory; +// search.clear(); +// isChatScreenActive = false; +// receiverID = 0; +// paginationVal = 0; +// message.text = ''; +// isTextMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// isReplyMsg = false; +// repliedMsg = []; +// sFileType = ""; +// } +// +// void disposeData() { +// if (!disbaleChatForThisUser) { +// search.clear(); +// isChatScreenActive = false; +// receiverID = 0; +// paginationVal = 0; +// message.text = ''; +// isTextMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// isReplyMsg = false; +// repliedMsg = []; +// sFileType = ""; +// deleteData(); +// favUsersList.clear(); +// searchedChats?.clear(); +// pChatHistory?.clear(); +// uGroups?.clear(); +// searchGroup?.clear(); +// chatHubConnection.stop(); +// AppState().chatDetails = null; +// } +// } +// +// void deleteData() { +// List exists = [], unique = []; +// if (searchedChats != null) exists.addAll(searchedChats!); +// exists.addAll(favUsersList!); +// Map profileMap = {}; +// for (ChatUser item in exists) { +// profileMap[item.email!] = item; +// } +// unique = profileMap.values.toList(); +// for (ChatUser element in unique!) { +// deleteFile(element.id.toString()); +// } +// } +// +// void getUserImages() async { +// List emails = []; +// List exists = [], unique = []; +// exists.addAll(searchedChats!); +// exists.addAll(favUsersList!); +// Map profileMap = {}; +// for (ChatUser item in exists) { +// profileMap[item.email!] = item; +// } +// unique = profileMap.values.toList(); +// for (ChatUser element in unique!) { +// emails.add(await EmailImageEncryption().encrypt(val: element.email!)); +// } +// +// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// for (ChatUser user in searchedChats!) { +// for (ChatUserImageModel uImage in chatImages) { +// if (user.email == uImage.email) { +// user.image = uImage.profilePicture ?? ""; +// user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); +// user.isImageLoading = false; +// user.isImageLoaded = true; +// } +// } +// } +// for (ChatUser favUser in favUsersList) { +// for (ChatUserImageModel uImage in chatImages) { +// if (favUser.email == uImage.email) { +// favUser.image = uImage.profilePicture ?? ""; +// favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); +// favUser.isImageLoading = false; +// favUser.isImageLoaded = true; +// } +// } +// } +// +// notifyListeners(); +// } +// +// Future downloadImageLocal(String? encodedBytes, String userID) async { +// File? myfile; +// if (encodedBytes == null) { +// return myfile; +// } else { +// await deleteFile(userID); +// Uint8List decodedBytes = base64Decode(encodedBytes); +// Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); +// String dirPath = '${appDocumentsDirectory.path}/chat_images'; +// if (!await Directory(dirPath).exists()) { +// await Directory(dirPath).create(); +// await File('$dirPath/.nomedia').create(); +// } +// late File imageFile = File("$dirPath/$userID.jpg"); +// imageFile.writeAsBytesSync(decodedBytes); +// return imageFile; +// } +// } +// +// Future deleteFile(String userID) async { +// Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); +// String dirPath = '${appDocumentsDirectory.path}/chat_images'; +// late File imageFile = File('$dirPath/$userID.jpg'); +// if (await imageFile.exists()) { +// await imageFile.delete(); +// } +// } +// +// Future downChatMedia(Uint8List bytes, String ext) async { +// String dir = (await getApplicationDocumentsDirectory()).path; +// File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); +// await file.writeAsBytes(bytes); +// return file.path; +// } +// +// void setMsgTune() async { +// JustAudio.AudioPlayer player = JustAudio.AudioPlayer(); +// await player.setVolume(1.0); +// String audioAsset = ""; +// if (Platform.isAndroid) { +// audioAsset = "assets/audio/pulse_tone_android.mp3"; +// } else { +// audioAsset = "assets/audio/pulse_tune_ios.caf"; +// } +// try { +// await player.setAsset(audioAsset); +// await player.load(); +// player.play(); +// } catch (e) { +// print("Error: $e"); +// } +// } +// +// Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { +// Utils.showLoading(context); +// if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { +// Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); +// try { +// String path = await downChatMedia(encodedString, fileTypeName ?? ""); +// Utils.hideLoading(context); +// OpenFilex.open(path); +// } catch (e) { +// Utils.showToast("Cannot open file."); +// } +// } +// } +// +// void onNewChatConversion(List? params) { +// dynamic items = params!.toList(); +// chatUConvCounter = items[0]["singleChatCount"] ?? 0; +// notifyListeners(); +// } +// +// Future invokeChatCounter({required int userId}) async { +// await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); +// return ""; +// } +// +// void userTypingInvoke({required int currentUser, required int reciptUser}) async { +// await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); +// } +// +// void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { +// var data = json.decode(json.encode(groupDetails.groupUserList)); +// await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); +// } +// +// //////// Audio Recoding Work //////////////////// +// +// Future initAudio({required int receiverId}) async { +// // final dir = Directory((Platform.isAndroid +// // ? await getExternalStorageDirectory() //FOR ANDROID +// // : await getApplicationSupportDirectory() //FOR IOS +// // )! +// appDirectory = await getApplicationDocumentsDirectory(); +// String dirPath = '${appDirectory.path}/chat_audios'; +// if (!await Directory(dirPath).exists()) { +// await Directory(dirPath).create(); +// await File('$dirPath/.nomedia').create(); +// } +// path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; +// recorderController = RecorderController() +// ..androidEncoder = AndroidEncoder.aac +// ..androidOutputFormat = AndroidOutputFormat.mpeg4 +// ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC +// ..sampleRate = 6000 +// ..updateFrequency = const Duration(milliseconds: 100) +// ..bitRate = 18000; +// playerController = PlayerController(); +// } +// +// void disposeAudio() { +// isRecoding = false; +// isPlaying = false; +// isPause = false; +// isVoiceMsg = false; +// recorderController.dispose(); +// playerController.dispose(); +// } +// +// void startRecoding(BuildContext context) async { +// await Permission.microphone.request().then((PermissionStatus status) { +// if (status.isPermanentlyDenied) { +// Utils.confirmDialog( +// context, +// "The app needs microphone access to be able to record audio.", +// onTap: () { +// Navigator.of(context).pop(); +// openAppSettings(); +// }, +// ); +// } else if (status.isDenied) { +// Utils.confirmDialog( +// context, +// "The app needs microphone access to be able to record audio.", +// onTap: () { +// Navigator.of(context).pop(); +// openAppSettings(); +// }, +// ); +// } else if (status.isGranted) { +// sRecoding(); +// } else { +// startRecoding(context); +// } +// }); +// } +// +// void sRecoding() async { +// isVoiceMsg = true; +// recorderController.reset(); +// await recorderController.record(path: path); +// _recodeDuration = 0; +// _startTimer(); +// isRecoding = !isRecoding; +// notifyListeners(); +// } +// +// Future _startTimer() async { +// _timer?.cancel(); +// _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { +// _recodeDuration++; +// if (_recodeDuration <= 59) { +// applyCounter(); +// } else { +// pauseRecoding(); +// } +// }); +// } +// +// void applyCounter() { +// buildTimer(); +// notifyListeners(); +// } +// +// Future pauseRecoding() async { +// isPause = true; +// isPlaying = true; +// recorderController.pause(); +// path = await recorderController.stop(false); +// File file = File(path!); +// file.readAsBytesSync(); +// path = file.path; +// await playerController.preparePlayer(path:file.path, volume: 1.0); +// _timer?.cancel(); +// notifyListeners(); +// } +// +// Future deleteRecoding() async { +// _recodeDuration = 0; +// _timer?.cancel(); +// if (path == null) { +// path = await recorderController.stop(true); +// } else { +// await recorderController.stop(true); +// } +// if (path != null && path!.isNotEmpty) { +// File delFile = File(path!); +// double fileSizeInKB = delFile.lengthSync() / 1024; +// double fileSizeInMB = fileSizeInKB / 1024; +// if (kDebugMode) { +// debugPrint("Deleted file size: ${delFile.lengthSync()}"); +// debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); +// debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); +// } +// if (await delFile.exists()) { +// delFile.delete(); +// } +// isPause = false; +// isRecoding = false; +// isPlaying = false; +// isVoiceMsg = false; +// notifyListeners(); +// } +// } +// +// String buildTimer() { +// String minutes = _formatNum(_recodeDuration ~/ 60); +// String seconds = _formatNum(_recodeDuration % 60); +// return '$minutes : $seconds'; +// } +// +// String _formatNum(int number) { +// String numberStr = number.toString(); +// if (number < 10) { +// numberStr = '0' + numberStr; +// } +// return numberStr; +// } +// +// Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { +// File file; +// try { +// String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; +// if (!await Directory(dirPath).exists()) { +// await Directory(dirPath).create(); +// await File('$dirPath/.nomedia').create(); +// } +// file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); +// await file.writeAsBytes(bytes); +// } catch (e) { +// if (kDebugMode) { +// print(e); +// } +// file = File(""); +// } +// return file; +// } +// +// void scrollToMsg(SingleUserChatModel data) { +// if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { +// int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); +// if (index >= 1) { +// double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; +// double target = contentSize * index / userChatHistory.length; +// scrollController.position.animateTo( +// target, +// duration: const Duration(seconds: 1), +// curve: Curves.easeInOut, +// ); +// } +// } +// } +// +// Future getTeamMembers() async { +// teamMembersList = []; +// isLoading = true; +// if (AppState().getemployeeSubordinatesList.isNotEmpty) { +// getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; +// for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { +// if (element.eMPLOYEEEMAILADDRESS != null) { +// if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { +// teamMembersList.add( +// ChatUser( +// id: int.parse(element.eMPLOYEENUMBER!), +// email: element.eMPLOYEEEMAILADDRESS, +// userName: element.eMPLOYEENAME, +// phone: element.eMPLOYEEMOBILENUMBER, +// userStatus: 0, +// unreadMessageCount: 0, +// isFav: false, +// isTyping: false, +// isImageLoading: false, +// image: element.eMPLOYEEIMAGE ?? "", +// isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, +// userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), +// ), +// ); +// } +// } +// } +// } else { +// getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); +// AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; +// for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { +// if (element.eMPLOYEEEMAILADDRESS != null) { +// if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { +// teamMembersList.add( +// ChatUser( +// id: int.parse(element.eMPLOYEENUMBER!), +// email: element.eMPLOYEEEMAILADDRESS, +// userName: element.eMPLOYEENAME, +// phone: element.eMPLOYEEMOBILENUMBER, +// userStatus: 0, +// unreadMessageCount: 0, +// isFav: false, +// isTyping: false, +// isImageLoading: false, +// image: element.eMPLOYEEIMAGE ?? "", +// isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, +// userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), +// ), +// ); +// } +// } +// } +// } +// +// for (ChatUser user in searchedChats!) { +// for (ChatUser teamUser in teamMembersList!) { +// if (user.id == teamUser.id) { +// teamUser.userStatus = user.userStatus; +// } +// } +// } +// +// isLoading = false; +// notifyListeners(); +// } +// +// void inputBoxDirection(String val) { +// if (val.isNotEmpty) { +// isTextMsg = true; +// } else { +// isTextMsg = false; +// } +// msgText = val; +// notifyListeners(); +// } +// +// void onDirectionChange(bool val) { +// isRTL = val; +// notifyListeners(); +// } +// +// Material.TextDirection getTextDirection(String v) { +// String str = v.trim(); +// if (str.isEmpty) return Material.TextDirection.ltr; +// int firstUnit = str.codeUnitAt(0); +// if (firstUnit > 0x0600 && firstUnit < 0x06FF || +// firstUnit > 0x0750 && firstUnit < 0x077F || +// firstUnit > 0x07C0 && firstUnit < 0x07EA || +// firstUnit > 0x0840 && firstUnit < 0x085B || +// firstUnit > 0x08A0 && firstUnit < 0x08B4 || +// firstUnit > 0x08E3 && firstUnit < 0x08FF || +// firstUnit > 0xFB50 && firstUnit < 0xFBB1 || +// firstUnit > 0xFBD3 && firstUnit < 0xFD3D || +// firstUnit > 0xFD50 && firstUnit < 0xFD8F || +// firstUnit > 0xFD92 && firstUnit < 0xFDC7 || +// firstUnit > 0xFDF0 && firstUnit < 0xFDFC || +// firstUnit > 0xFE70 && firstUnit < 0xFE74 || +// firstUnit > 0xFE76 && firstUnit < 0xFEFC || +// firstUnit > 0x10800 && firstUnit < 0x10805 || +// firstUnit > 0x1B000 && firstUnit < 0x1B0FF || +// firstUnit > 0x1D165 && firstUnit < 0x1D169 || +// firstUnit > 0x1D16D && firstUnit < 0x1D172 || +// firstUnit > 0x1D17B && firstUnit < 0x1D182 || +// firstUnit > 0x1D185 && firstUnit < 0x1D18B || +// firstUnit > 0x1D1AA && firstUnit < 0x1D1AD || +// firstUnit > 0x1D242 && firstUnit < 0x1D244) { +// return Material.TextDirection.rtl; +// } +// return Material.TextDirection.ltr; +// } +// +// void openChatByNoti(BuildContext context) async { +// SingleUserChatModel nUser = SingleUserChatModel(); +// Utils.saveStringFromPrefs("isAppOpendByChat", "false"); +// if (await Utils.getStringFromPrefs("notificationData") != "null") { +// nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); +// Utils.saveStringFromPrefs("notificationData", "null"); +// Future.delayed(const Duration(seconds: 2)); +// for (ChatUser user in searchedChats!) { +// if (user.id == nUser.targetUserId) { +// Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); +// return; +// } +// } +// } +// Utils.saveStringFromPrefs("notificationData", "null"); +// } +// +// //group chat functions added here +// +// void filterGroups(String value) async { +// // filter function added here. +// List tmp = []; +// if (value.isEmpty || value == "") { +// tmp = userGroups.groupresponse!; +// } else { +// for (groups.GroupResponse element in uGroups!) { +// if (element.groupName!.toLowerCase().contains(value.toLowerCase())) { +// tmp.add(element); +// } +// } +// } +// uGroups = tmp; +// notifyListeners(); +// } +// +// Future deleteGroup(GroupResponse groupDetails) async { +// isLoading = true; +// await ChatApiClient().deleteGroup(groupDetails.groupId); +// userGroups = await ChatApiClient().getGroupsByUserId(); +// uGroups = userGroups.groupresponse; +// isLoading = false; +// notifyListeners(); +// } +// +// Future getGroupChatHistory(groups.GroupResponse groupDetails) async { +// isLoading = true; +// groupChatHistory = await ChatApiClient().getGroupChatHistory(groupDetails.groupId, groupDetails.groupUserList as List); +// +// isLoading = false; +// +// notifyListeners(); +// } +// +// void updateGroupAdmin(int? groupId, List groupUserList) async { +// isLoading = true; +// await ChatApiClient().updateGroupAdmin(groupId, groupUserList); +// isLoading = false; +// notifyListeners(); +// } +// +// Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { +// isLoading = true; +// var groups = await ChatApiClient().addGroupAndUsers(request); +// userGroups.groupresponse!.add(GroupResponse.fromJson(json.decode(groups)['response'])); +// +// isLoading = false; +// notifyListeners(); +// } +// +// Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { +// isLoading = true; +// await ChatApiClient().updateGroupAndUsers(request); +// userGroups = await ChatApiClient().getGroupsByUserId(); +// uGroups = userGroups.groupresponse; +// isLoading = false; +// notifyListeners(); +// } +// } From 81dd189025d958c2d3a4d1069af95071b34969e0 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Mon, 10 Nov 2025 10:33:45 +0300 Subject: [PATCH 09/31] internal audit api's implementation in progress --- lib/controllers/api_routes/urls.dart | 5 +- lib/main.dart | 4 +- .../models/audit_form_model.dart | 56 +++ .../equipment_internal_audit_data_model.dart | 10 +- .../models/internal_audit_timer_model.dart | 35 ++ .../system_internal_audit_data_model.dart | 122 +++++++ .../system_internal_audit_form_model.dart | 123 ++++++- .../equipment_internal_audit_detail_page.dart | 42 +-- .../equipment_internal_audit_item_view.dart | 1 - .../update_equipment_internal_audit_page.dart | 342 ++++++++++++++++++ .../create_system_internal_audit_form.dart | 58 +-- .../system_internal_audit_detail_page.dart | 20 +- .../system_internal_audit_item_view.dart | 1 - .../update_system_internal_audit_page.dart} | 32 +- .../provider/internal_audit_provider.dart | 65 ++++ .../tasks_wo/update_task_request_view.dart | 2 +- .../widgets/request_item_view_list.dart | 16 +- 17 files changed, 836 insertions(+), 98 deletions(-) create mode 100644 lib/modules/internal_audit_module/models/audit_form_model.dart create mode 100644 lib/modules/internal_audit_module/models/internal_audit_timer_model.dart create mode 100644 lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart create mode 100644 lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart rename lib/modules/internal_audit_module/pages/{update_internal_audit_page.dart => system_internal_audit/update_system_internal_audit_page.dart} (89%) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index dad15d8d..36d8e431 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -314,11 +314,14 @@ class URLs { //internal Audit static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById"; - static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemById"; + static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2"; static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43"; static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500"; static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502"; static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment"; + static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem"; static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; + static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer"; + static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID"; } diff --git a/lib/main.dart b/lib/main.dart index a2f9bdca..c5b39ef2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -103,7 +103,7 @@ import 'controllers/providers/api/gas_refill_comments.dart'; import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/settings/setting_provider.dart'; import 'dashboard_latest/dashboard_provider.dart'; -import 'modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; import 'modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'new_views/pages/gas_refill_request_form.dart'; import 'providers/lookups/classification_lookup_provider.dart'; @@ -365,7 +365,7 @@ class MyApp extends StatelessWidget { HelpCenterPage.id: (_) => const HelpCenterPage(), CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(), CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(), - UpdateInternalAuditPage.id: (_) => const UpdateInternalAuditPage(), + UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(), // SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), // SwipeHistoryView.routeName: (_) => const SwipeHistoryView(), }, diff --git a/lib/modules/internal_audit_module/models/audit_form_model.dart b/lib/modules/internal_audit_module/models/audit_form_model.dart new file mode 100644 index 00000000..dd3e6975 --- /dev/null +++ b/lib/modules/internal_audit_module/models/audit_form_model.dart @@ -0,0 +1,56 @@ +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; + +class AuditFormModel { + int? id; + String? createdDate; + int? requestId; + String? debrief; + DateTime? startTime; + DateTime? endTime; + double? totalHours; + List? attachments; + bool? isComplete; + TimerModel? auditTimerModel = TimerModel(); + + AuditFormModel({ + this.id, + this.requestId, + this.debrief, + this.startTime, + this.endTime, + this.totalHours, + this.createdDate, + this.attachments, + this.isComplete, + this.auditTimerModel, + }); + + AuditFormModel.fromJson(Map json) { + id = json['id']; + requestId = json['requestId']; + debrief = json['debrief']; + startTime = json['startTime'] != null ? DateTime.tryParse(json['startTime']) : null; + endTime = json['endTime'] != null ? DateTime.tryParse(json['endTime']) : null; + totalHours = json['totalHours']?.toDouble(); + if (json['attachments'] != null) { + attachments = (json['attachments'] as List) + .map((e) => InternalAuditAttachments.fromJson(e)) + .toList(); + } + isComplete = json['isComplete']; + } + + Map toJson() { + return { + 'id': id, + 'requestId': requestId, + 'debrief': debrief, + 'startTime': startTime?.toIso8601String(), + 'endTime': endTime?.toIso8601String(), + 'totalHours': totalHours, + 'attachments': attachments?.map((e) => e.toJson()).toList(), + 'isComplete': isComplete, + }; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart index 411789ec..be9c00bb 100644 --- a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart @@ -1,4 +1,8 @@ - class EquipmentInternalAuditDataModel { + import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; + +class EquipmentInternalAuditDataModel { int? id; String? requestNo; String? createdDate; @@ -10,7 +14,7 @@ dynamic manufacture; String? remarks; List? equipmentsFindings; - List? attachments; + List? attachments; EquipmentInternalAuditDataModel({ this.id, @@ -44,7 +48,7 @@ equipmentsFindings!.add(EquipmentsFinding.fromJson(v)); }); } - attachments = json['attachments'] != null ? List.from(json['attachments']) : []; + // attachments = json['attachments'] != null ? List.from(json['attachments']) : []; } Map toJson() { diff --git a/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart b/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart new file mode 100644 index 00000000..708ab2d1 --- /dev/null +++ b/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart @@ -0,0 +1,35 @@ +class InternalAuditTimerModel { + int? id; + String? startDate; + String? endDate; + double? totalWorkingHour; + String? comment; + + InternalAuditTimerModel({ + this.id, + this.startDate, + this.endDate, + this.totalWorkingHour, + this.comment, + }); + + factory InternalAuditTimerModel.fromJson(Map json) { + return InternalAuditTimerModel( + id: json['id'] as int?, + startDate: json['startDate'], + endDate: json['endDate'], + totalWorkingHour: (json['totalWorkingHours'] as num?)?.toDouble(), + comment: json['comment'] as String?, + ); + } + + Map toJson() { + return { + 'id': id, + 'startDate': startDate, + 'endDate': endDate, + 'totalWorkingHours': totalWorkingHour, + 'comment': comment, + }; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart new file mode 100644 index 00000000..ae84e97f --- /dev/null +++ b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart @@ -0,0 +1,122 @@ +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; + +class SystemInternalAuditDataModel { + int? id; + int? assetGroupId; + String? requestNo; + int? requestNoSequence; + Auditor? auditor; + Lookup? status; + Lookup? findingType; + String? findingDescription; + Lookup? workOrderType; + Auditor? assignEmployee; + SystemAuditWorkOrderDetailModel? workOrderDetails; // Already exists as a separate model + String? createdBy; + String? createdDate; + String? modifiedBy; + String? modifiedDate; + + SystemInternalAuditDataModel({ + this.id, + this.assetGroupId, + this.requestNo, + this.requestNoSequence, + this.auditor, + this.status, + this.findingType, + this.findingDescription, + this.workOrderType, + this.assignEmployee, + this.workOrderDetails, + this.createdBy, + this.createdDate, + this.modifiedBy, + this.modifiedDate, + }); + + SystemInternalAuditDataModel.fromJson(Map json) { + id = json['id']; + assetGroupId = json['assetGroupId']; + requestNo = json['requestNo']; + requestNoSequence = json['requestNoSequence']; + auditor = json['auditor'] != null ? Auditor.fromJson(json['auditor']) : null; + status = json['status'] != null ? Lookup.fromJson(json['status']) : null; + findingType = json['findingType'] != null ? Lookup.fromJson(json['findingType']) : null; + findingDescription = json['findingDescription']; + workOrderType = json['workOrderType'] != null ? Lookup.fromJson(json['workOrderType']) : null; + assignEmployee = json['assignEmployee'] != null ? Auditor.fromJson(json['assignEmployee']) : null; + workOrderDetails = json['workOrderDetails'] != null ? SystemAuditWorkOrderDetailModel.fromJson(json['workOrderDetails']) : null; // Keep as-is + createdBy = json['createdBy']; + createdDate = json['createdDate']; + modifiedBy = json['modifiedBy']; + modifiedDate = json['modifiedDate']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['assetGroupId'] = assetGroupId; + data['requestNo'] = requestNo; + data['requestNoSequence'] = requestNoSequence; + if (auditor != null) data['auditor'] = auditor!.toJson(); + if (status != null) data['status'] = status!.toJson(); + if (findingType != null) data['findingType'] = findingType!.toJson(); + data['findingDescription'] = findingDescription; + if (workOrderType != null) data['workOrderType'] = workOrderType!.toJson(); + if (assignEmployee != null) data['assignEmployee'] = assignEmployee!.toJson(); + data['workOrderDetails'] = workOrderDetails; + data['createdBy'] = createdBy; + data['createdDate'] = createdDate; + data['modifiedBy'] = modifiedBy; + data['modifiedDate'] = modifiedDate; + return data; + } +} + +class Auditor { + String? userId; + String? userName; + String? email; + String? employeeId; + int? languageId; + String? extensionNo; + String? phoneNumber; + bool? isActive; + + Auditor({ + this.userId, + this.userName, + this.email, + this.employeeId, + this.languageId, + this.extensionNo, + this.phoneNumber, + this.isActive, + }); + + Auditor.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + extensionNo = json['extensionNo']; + phoneNumber = json['phoneNumber']; + isActive = json['isActive']; + } + + Map toJson() { + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['email'] = email; + data['employeeId'] = employeeId; + data['languageId'] = languageId; + data['extensionNo'] = extensionNo; + data['phoneNumber'] = phoneNumber; + data['isActive'] = isActive; + return data; + } +} diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart index 9750e9e0..4082eb03 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart @@ -4,7 +4,7 @@ import 'dart:developer'; import 'package:test_sa/models/lookup.dart'; class SystemInternalAuditFormModel { - int? id = 0; + int? id; String? auditorId; String? assignEmployeeId; Lookup? findingType; @@ -18,6 +18,7 @@ class SystemInternalAuditFormModel { int? gasRefillId; int? planRecurrentTaskId; int? statusId; + SystemAuditWorkOrderDetailModel ?workOrderDetailModel; SystemInternalAuditFormModel({ this.id, @@ -33,12 +34,13 @@ class SystemInternalAuditFormModel { this.taskAlertJobId, this.gasRefillId, this.planRecurrentTaskId, + this.workOrderDetailModel, this.statusId, }); Map toJson() { return { - 'id': id, + // 'id': id, 'auditorId': auditorId, 'assignEmployeeId': assignEmployeeId, 'findingTypeId': findingType?.id, @@ -77,6 +79,123 @@ class WoAutoCompleteModel { return data; } } +class SystemAuditWorkOrderDetailModel { + String? createdBy; + DateTime? createdDate; + String? modifiedBy; + DateTime? modifiedDate; + int? id; + String? workOrderNo; + String? woAssignedEngineer; + String? woAssetNo; + String? wosn; + String? woAssetName; + String? woModel; + String? woManufacturer; + String? woSite; + String? woDepartment; + String? wOPMScheduleDate; + String? wOPMActualVisitDate; + String? wOAssetTransferDestinationSite; + String? wOAssetTransferSenderEngineer; + String? wOAssetTransferReceiverEngineer; + String? wOTaskAlertJobImpactedStatus; + String? wOTaskAlertJobAcknowledgment; + String? wOGasRefillType; + String? wORecurrentTaskTaskType; + String? wORecurrentTaskPlanNo; + String? wORecurrentTaskPlanName; + String? wORecurrentTaskStatus; + + SystemAuditWorkOrderDetailModel({ + this.createdBy, + this.createdDate, + this.modifiedBy, + this.modifiedDate, + this.id, + this.workOrderNo, + this.woAssignedEngineer, + this.woAssetNo, + this.wosn, + this.woAssetName, + this.woModel, + this.woManufacturer, + this.woSite, + this.woDepartment, + this.wOPMScheduleDate, + this.wOPMActualVisitDate, + this.wOAssetTransferDestinationSite, + this.wOAssetTransferSenderEngineer, + this.wOAssetTransferReceiverEngineer, + this.wOTaskAlertJobImpactedStatus, + this.wOTaskAlertJobAcknowledgment, + this.wOGasRefillType, + this.wORecurrentTaskTaskType, + this.wORecurrentTaskPlanNo, + this.wORecurrentTaskPlanName, + this.wORecurrentTaskStatus, + }); + + SystemAuditWorkOrderDetailModel.fromJson(Map json) { + createdBy = json['createdBy']; + createdDate = json['createdDate'] != null ? DateTime.tryParse(json['createdDate']) : null; + modifiedBy = json['modifiedBy']; + modifiedDate = json['modifiedDate'] != null ? DateTime.tryParse(json['modifiedDate']) : null; + id = json['id']; + workOrderNo = json['workOrderNo']; + woAssignedEngineer = json['woAssignedEngineer']; + woAssetNo = json['woAssetNo']; + wosn = json['wosn']; + woAssetName = json['woAssetName']; + woModel = json['woModel']; + woManufacturer = json['woManufacturer']; + woSite = json['woSite']; + woDepartment = json['woDepartment']; + wOPMScheduleDate = json['wO_PM_ScheduleDate']; + wOPMActualVisitDate = json['wO_PM_ActualVisitDate']; + wOAssetTransferDestinationSite = json['wO_AssetTransfer_DestinationSite']; + wOAssetTransferSenderEngineer = json['wO_AssetTransfer_SenderEngineer']; + wOAssetTransferReceiverEngineer = json['wO_AssetTransfer_ReceiverEngineer']; + wOTaskAlertJobImpactedStatus = json['wO_TaskAlertJob_ImpactedStatus']; + wOTaskAlertJobAcknowledgment = json['wO_TaskAlertJob_Acknowledgment']; + wOGasRefillType = json['wO_GasRefill_Type']; + wORecurrentTaskTaskType = json['wO_RecurrentTask_TaskType']; + wORecurrentTaskPlanNo = json['wO_RecurrentTask_PlanNo']; + wORecurrentTaskPlanName = json['wO_RecurrentTask_PlanName']; + wORecurrentTaskStatus = json['wO_RecurrentTask_Status']; + } + + Map toJson() { + return { + 'createdBy': createdBy, + 'createdDate': createdDate?.toIso8601String(), + 'modifiedBy': modifiedBy, + 'modifiedDate': modifiedDate?.toIso8601String(), + 'id': id, + 'workOrderNo': workOrderNo, + 'woAssignedEngineer': woAssignedEngineer, + 'woAssetNo': woAssetNo, + 'wosn': wosn, + 'woAssetName': woAssetName, + 'woModel': woModel, + 'woManufacturer': woManufacturer, + 'woSite': woSite, + 'woDepartment': woDepartment, + 'wO_PM_ScheduleDate': wOPMScheduleDate, + 'wO_PM_ActualVisitDate': wOPMActualVisitDate, + 'wO_AssetTransfer_DestinationSite': wOAssetTransferDestinationSite, + 'wO_AssetTransfer_SenderEngineer': wOAssetTransferSenderEngineer, + 'wO_AssetTransfer_ReceiverEngineer': wOAssetTransferReceiverEngineer, + 'wO_TaskAlertJob_ImpactedStatus': wOTaskAlertJobImpactedStatus, + 'wO_TaskAlertJob_Acknowledgment': wOTaskAlertJobAcknowledgment, + 'wO_GasRefill_Type': wOGasRefillType, + 'wO_RecurrentTask_TaskType': wORecurrentTaskTaskType, + 'wO_RecurrentTask_PlanNo': wORecurrentTaskPlanNo, + 'wO_RecurrentTask_PlanName': wORecurrentTaskPlanName, + 'wO_RecurrentTask_Status': wORecurrentTaskStatus, + }; + } +} diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart index 6d842b29..5d788a6f 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart @@ -9,13 +9,13 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; -import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class EquipmentInternalAuditDetailPage extends StatefulWidget { static const String id = "/details-internal-audit"; @@ -62,7 +62,8 @@ class _EquipmentInternalAuditDetailPageState extends State provider.isLoading, builder: (_, isLoading, __) { if (isLoading) return const ALoading(); - return Column( + if (model==null) return NoDataFound(message: context.translation.noDataFound).center; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SingleChildScrollView( @@ -74,25 +75,24 @@ class _EquipmentInternalAuditDetailPageState extends State URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + //TODO need to check for attachments backend need to fix the name they are sending wrong string + // if (model!.attachments!.isNotEmpty) ...[ + // const Divider().defaultStyle(context), + // Text( + // "Attachments".addTranslation, + // style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + // ), + // 8.height, + // FilesList(images: model!.attachments!.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), // ], ], ).paddingAll(0).toShadowContainer(context), @@ -104,7 +104,7 @@ class _EquipmentInternalAuditDetailPageState extends State UpdateEquipmentInternalAuditPage(model: model))); }), ), ], diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart index 4c4bbb57..a17407a2 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart @@ -22,7 +22,6 @@ class EquipmentInternalAuditItemView extends StatelessWidget { @override Widget build(BuildContext context) { //TODO need to refactor this code repetation @waseem - log('request details ${requestDetails?.toJson()}'); if (requestData != null) { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart new file mode 100644 index 00000000..02115d62 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart @@ -0,0 +1,342 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; +import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart'; + +class UpdateEquipmentInternalAuditPage extends StatefulWidget { + static const String id = "update-equipment-internal-audit"; + EquipmentInternalAuditDataModel? model; + + UpdateEquipmentInternalAuditPage({Key? key,this.model}) : super(key: key); + + @override + State createState() => _UpdateEquipmentInternalAuditPageState(); +} + +class _UpdateEquipmentInternalAuditPageState extends State { + final bool _isLoading = false; + double totalWorkingHours = 0.0; + AuditFormModel formModel = AuditFormModel(); + final TextEditingController _workingHoursController = TextEditingController(); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + List _attachments = []; + //TODO need to check if it's needed or not.. + List timerList = []; + + @override + void initState() { + populateForm(); + super.initState(); + } + void populateForm(){ + formModel.requestId = widget.model?.id; + formModel.id = widget.model?.id; + _attachments = widget.model?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt()??0, name: e.name!)).toList() ?? []; + + } + void calculateWorkingTime() { + // final timers = _formModel.gasRefillTimers ?? []; + // totalWorkingHours = timers.fold(0.0, (sum, item) { + // if (item.startDate == null || item.endDate == null) return sum; + // try { + // final start = DateTime.parse(item.startDate!); + // final end = DateTime.parse(item.endDate!); + // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + // return sum + diffInHours; + // } catch (_) { + // return sum; + // } + // }); + // + // timerList = timers.map((e) { + // return TimerHistoryModel( + // id: e.id, + // startTime: e.startDate, + // endTime: e.endDate, + // workingHours: e.workingHours, + // ); + // }).toList(); + } + + + _onSubmit(BuildContext context) async { + bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + InternalAuditProvider provider = Provider.of(context,listen: false); + + _formKey.currentState!.save(); + formModel.attachments = []; + for (var item in _attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') + ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") + : item.name ?? ''; + formModel.attachments!.add( + InternalAuditAttachments( + id: item.id, + originalName: fileName, + // name: fileName, + ), + ); + } + provider.updateEquipmentInternalAudit(model: formModel); + + log('payload ${formModel.toJson()}'); + + + + // if (isTimerPickerEnable) { + // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.gasRefillTimePicker == null) { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // } else { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // + // if (_currentDetails.deliverdQty == null) { + // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); + // return false; + // } + // _formModel.gasRefillDetails = []; + // _formModel.gasRefillDetails?.add(_currentDetails); + // + // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; + // if (_formModel.gasRefillTimePicker != null) { + // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null + // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // } + // _formModel.timerModelList?.forEach((timer) { + // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: timer.startAt!.toIso8601String(), // Handle potential null + // endDate: timer.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // }); + // _formModel.gasRefillAttachments = []; + // for (var item in _attachments) { + // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; + // _formModel.gasRefillAttachments?.add(GasRefillAttachments( + // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); + // } + + // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { + // Navigator.pop(context); + // if (success) { + // if (status == 1) { + // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + // // when click complete then this request remove from the list and status changes to closed.. + // _gasRefillProvider?.reset(); + // allRequestsProvider.getAllRequests(context, typeTransaction: 2); + // } + // Navigator.pop(context); + // } + // }); + } + + @override + void dispose() { + _workingHoursController.dispose(); + super.dispose(); + } + + void updateTimer({TimerModel? timer}) { + if (timer?.startAt != null && timer?.endAt != null) { + final start = timer!.startAt!; + final end = timer.endAt!; + + final difference = end.difference(start); + final totalHours = difference.inSeconds / 3600.0; + formModel.startTime = start; + formModel.endTime = end; + formModel.totalHours = totalHours; + } + } + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: DefaultAppBar( + title: 'Update Information'.addTranslation, + onWillPopScope: () { + formModel.isComplete = false; + _onSubmit(context); + }, + ), + key: _scaffoldKey, + body: Form( + key: _formKey, + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + AppTextFormField( + labelText: 'Debrief'.addTranslation, + textInputType: TextInputType.multiline, + hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + alignLabelWithHint: true, + initialValue: formModel.debrief, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + onSaved: (value) { + formModel.debrief = value; + }, + ), + 8.height, + _timerWidget(context, totalWorkingHours), + 16.height, + AttachmentPicker( + label: context.translation.attachFiles, + attachment: _attachments, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset( + color: AppColor.primary10, + ), + ), + 8.height, + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + AppFilledButton( + label: context.translation.save, + buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, + textColor: context.isDark ? AppColor.white10 : AppColor.black10, + onPressed: (){ + formModel.isComplete = false; + _onSubmit(context); + } + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: (){ + formModel.isComplete = true; + _onSubmit(context); + } + ).expanded, + ], + ), + ), + ], + )), + ), + ).handlePopScope( + cxt: context, + onSave: () { + formModel.isComplete=false; + _onSubmit(context); + }); + } + + Widget _timerWidget(BuildContext context, double totalWorkingHours) { + TimerModel? timer = TimerModel(); + TimerModel? timerPicker; + List? timerModelList = []; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + AppTimer( + label: context.translation.workingHours, + timer: timer, + pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + pickerTimer: timerPicker, + onPick: (time) { + updateTimer(timer: timer); + + }, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(10), + ), + timerProgress: (isRunning) {}, + onChange: (timer) async { + updateTimer(timer: timer); + log('here onChange ${timer.startAt}'); + + return true; + }, + ), + if (totalWorkingHours > 0.0) ...[ + 12.height, + WorkingTimeTile( + timerList: timerList, + totalWorkingTime: totalWorkingHours, + ), + ], + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart index 64e8408b..a443588d 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart @@ -91,7 +91,8 @@ class _CreateSystemInternalAuditFormState extends State(context, listen: false); + setState(() { + showLoading = true; + }); + _model.workOrderDetailModel = await provider.loadAllWorkOrderDetailsByID(workOrderId: wo.id!, workOrderTypeId: _model.workOrderType!.value!); + updateWorkOrderReference(woTypeId: _model.workOrderType?.value, selectedId: wo.id); + + setState(() { + showLoading = false; + }); }, ), 12.height, @@ -166,14 +175,16 @@ class _CreateSystemInternalAuditFormState extends State _submit() async { + InternalAuditProvider internalAuditProvider = Provider.of(context, listen: false); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); - List attachement = []; - for (var item in _deviceImages) { - String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + _model.auditorId = context.userProvider.user?.userID; + bool status = await internalAuditProvider.addSystemInternalAudit(context: context, request: _model); + Navigator.pop(context); + if (status) { + Navigator.pop(context); } - // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); } } @@ -193,7 +204,7 @@ class _CreateSystemInternalAuditFormState extends State { bool isWoType = true; + // EquipmentInternalAuditDataModel? model; + late InternalAuditProvider _internalAuditProvider; @override void initState() { super.initState(); - //TODO need to get and assign data . - // Provider.of(context, listen: false).getInternalAuditById(widget.auditId); + _internalAuditProvider = Provider.of(context, listen: false); + WidgetsBinding.instance.addPostFrameCallback((_) { + getAuditData(); + }); + } + + Future getAuditData() async { + await _internalAuditProvider.getInternalSystemAuditById(widget.auditId); } @override @@ -69,7 +77,7 @@ class _SystemInternalAuditDetailPageState extends State URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), @@ -94,7 +102,7 @@ class _SystemInternalAuditDetailPageState extends State { final bool _isLoading = false; double totalWorkingHours = 0.0; late UserProvider _userProvider; - - // GasRefillDetails _currentDetails = GasRefillDetails(); final TextEditingController _commentController = TextEditingController(); final TextEditingController _workingHoursController = TextEditingController(); - - // final GasRefillModel _formModel = GasRefillModel(gasRefillDetails: []); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); bool _firstTime = true; @@ -51,18 +49,6 @@ class _UpdateInternalAuditPageState extends State { @override void initState() { super.initState(); - // if (widget.gasRefillModel != null) { - // _formModel.fromGasRefillModel(widget.gasRefillModel!); - // _commentController.text = _formModel.techComment ?? ""; - // calculateWorkingTime(); - // try { - // _deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty); - // _currentDetails.deliverdQty = _deliveredQuantity!.value; - // } catch (ex) {} - // } - // if (_formModel.gasRefillAttachments != null && _formModel.gasRefillAttachments!.isNotEmpty) { - // _attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.attachmentName!)).toList()); - // } } void calculateWorkingTime() { @@ -194,16 +180,6 @@ class _UpdateInternalAuditPageState extends State { @override Widget build(BuildContext context) { _userProvider = Provider.of(context); - if (_firstTime) { - String? clientName; - // if (widget.gasRefillModel != null) { - // _gasRefillProvider!.expectedDateTime = DateTime.tryParse(_formModel.expectedDate ?? ""); - // _formModel.timer = TimerModel(startAt: DateTime.tryParse(widget.gasRefillModel?.startDate ?? ""), endAt: DateTime.tryParse(widget.gasRefillModel?.endDate ?? "")); - // } else { - // _formModel.timer = null; - // } - } - return Scaffold( appBar: DefaultAppBar( title: 'Update Information'.addTranslation, diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart index 6f2a9b9d..314fb2d9 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -10,6 +10,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset_search.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; @@ -71,6 +72,47 @@ class InternalAuditProvider extends ChangeNotifier { return -1; } } + Future loadAllWorkOrderDetailsByID({required int workOrderTypeId,required int workOrderId}) async { + try { + isLoading = true; + notifyListeners(); + Response response = await ApiManager.instance.get("${URLs.loadAllWorkOrderDetailsByID}?workOrderTypeId=$workOrderTypeId&workOrderId=$workOrderId"); + if (response.statusCode >= 200 && response.statusCode < 300) { + final decodedBody = jsonDecode(response.body); + SystemAuditWorkOrderDetailModel model = SystemAuditWorkOrderDetailModel.fromJson(decodedBody["data"]); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return null; + } + } + Future updateEquipmentInternalAudit({required AuditFormModel model}) async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.put(URLs.updateAuditEquipmentsEngineer, body: model.toJson()); + stateCode = response.statusCode; + isLoading = false; + notifyListeners(); + if (stateCode == 200) { + return true; + } + return false; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; + } + } Future addEquipmentInternalAudit({ required BuildContext context, @@ -95,6 +137,29 @@ class InternalAuditProvider extends ChangeNotifier { return status; } } + Future addSystemInternalAudit({ + required BuildContext context, + required SystemInternalAuditFormModel request, + }) async { + bool status = false; + Response response; + try { + response = await ApiManager.instance.post(URLs.addOrUpdateInternalAuditSystem, body: request.toJson()); + if (response.statusCode >= 200 && response.statusCode < 300) { + status = true; + notifyListeners(); + } else { + Fluttertoast.showToast(msg: "${context.translation.failedRequestMessage} :${json.decode(response.body)['message']}"); + status = false; + } + return status; + } catch (error) { + print(error); + status = false; + notifyListeners(); + return status; + } + } Future> getWorkOrderByWoType({String? text, required int? woId}) async { late Response response; diff --git a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart index d25049df..40871d70 100644 --- a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart +++ b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart @@ -271,7 +271,7 @@ class _UpdateTaskRequestState extends State { taskModel?.timerModelList?.forEach((timer) { int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; taskModel.taskJobActivityEngineerTimers?.add( - TaskJobActivityEngineerTimer( + TaskJobActivityEngineerTimer ( id: 0, startDate: timer.startAt!.toIso8601String(), endDate: timer.endAt?.toIso8601String(), totalWorkingHour: ((durationInSecond) / 60 / 60), comment: timer.comments ?? comments), ); }); diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index ec9b9d31..54639c40 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -33,14 +33,14 @@ class RequestItemViewList extends StatelessWidget { shrinkWrap: true, itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); - if (list[index].transactionType == null) { - return EquipmentInternalAuditItemView(requestDetails: list[index]); - // return Container( - // height: 100, - // width: double.infinity, - // color: AppColor.neutral40, - // ); - } + // if (list[index].transactionType == null) { + // return EquipmentInternalAuditItemView(requestDetails: list[index]); + // // return Container( + // // height: 100, + // // width: double.infinity, + // // color: AppColor.neutral40, + // // ); + // } switch (list[index].transactionType) { case 1: return ServiceRequestItemView(requestDetails: list[index]); From ec28f8992cd4def911b7080ad5629e425bcf1167 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 12 Nov 2025 07:49:54 +0300 Subject: [PATCH 10/31] chat cont. --- lib/controllers/api_routes/urls.dart | 2 + .../cx_module/chat/chat_api_client.dart | 548 +-- lib/modules/cx_module/chat/chat_provider.dart | 3887 +++++++++-------- .../model/get_search_user_chat_model.dart | 137 + .../get_single_user_chat_list_model.dart | 206 + .../model/get_user_login_token_model.dart | 97 + pubspec.lock | 80 + pubspec.yaml | 2 + 8 files changed, 2752 insertions(+), 2207 deletions(-) create mode 100644 lib/modules/cx_module/chat/model/get_search_user_chat_model.dart create mode 100644 lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart create mode 100644 lib/modules/cx_module/chat/model/get_user_login_token_model.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 7f8a61e9..6749e87f 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -15,6 +15,8 @@ class URLs { // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation + static const String chatHubUrl = "https://apiderichat.hmg.com/chathub/api"; // new V2 apis + static String _host = host1; set host(String value) => _host = value; diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 5af7d273..fc473329 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -1,10 +1,16 @@ -// import 'dart:convert'; -// import 'dart:io'; -// import 'dart:typed_data'; -// -// import 'package:flutter/foundation.dart'; -// import 'package:flutter/material.dart'; -// import 'package:http/http.dart'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; + +import 'model/get_search_user_chat_model.dart'; +import 'model/get_user_login_token_model.dart'; + // 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'; @@ -19,102 +25,108 @@ // import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; // import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user; // import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; -// -// class ChatApiClient { -// static final ChatApiClient _instance = ChatApiClient._internal(); -// -// ChatApiClient._internal(); -// -// factory ChatApiClient() => _instance; -// -// Future getUserLoginToken() async { -// user.UserAutoLoginModel userLoginResponse = user.UserAutoLoginModel(); -// String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken; -// Response response = await ApiClient().postJsonForResponse( -// "${ApiConsts.chatLoginTokenUrl}externaluserlogin", -// { -// "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), -// "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", -// "isMobile": true, -// "platform": Platform.isIOS ? "ios" : "android", -// "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, -// "isHuaweiDevice": AppState().getIsHuawei, -// "voipToken": Platform.isIOS ? "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba" : "", -// }, -// ); -// -// if (!kReleaseMode) { -// logger.i("login-res: " + response.body); -// } -// if (response.statusCode == 200) { -// userLoginResponse = user.userAutoLoginModelFromJson(response.body); -// } else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) { -// getUserLoginToken(); -// } else { -// userLoginResponse = user.userAutoLoginModelFromJson(response.body); -// Utils.showToast(userLoginResponse.errorResponses!.first.message!); -// } -// return userLoginResponse; -// } -// -// Future getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { -// ChatUserModel chatUserModel; -// Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo}, -// token: AppState().chatDetails!.response!.token); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// chatUserModel = chatUserModelFromJson(response.body); -// return chatUserModel; -// } -// -// //Get User Recent Chats -// Future getRecentChats() async { -// try { -// Response response = await ApiClient().getJsonForResponse( -// "${ApiConsts.chatRecentUrl}getchathistorybyuserid", -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// return ChatUserModel.fromJson( -// json.decode(response.body), -// ); -// } catch (e) { -// throw e; -// } -// } -// -// // Get Favorite Users -// Future getFavUsers() async { -// Response favRes = await ApiClient().getJsonForResponse( -// "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}", -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + favRes.body); -// } -// return ChatUserModel.fromJson(json.decode(favRes.body)); -// } -// -// //Get User Chat History -// Future getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { -// try { -// Response response = await ApiClient().getJsonForResponse( -// "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// return response; -// } catch (e) { -// getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); -// throw e; -// } -// } -// + +class ChatApiClient { + static final ChatApiClient _instance = ChatApiClient._internal(); + + ChatApiClient._internal(); + + factory ChatApiClient() => _instance; + + Future getUserLoginToken() async { + UserAutoLoginModel userLoginResponse = UserAutoLoginModel(); + String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken; + Response response = await ApiClient().postJsonForResponse( + "${ApiConsts.chatLoginTokenUrl}externaluserlogin", + { + "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", + "isMobile": true, + "platform": Platform.isIOS ? "ios" : "android", + "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, + "isHuaweiDevice": AppState().getIsHuawei, + "voipToken": Platform.isIOS ? "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba" : "", + }, + ); + + if (!kReleaseMode) { + // logger.i("login-res: " + response.body); + } + if (response.statusCode == 200) { + userLoginResponse = user.userAutoLoginModelFromJson(response.body); + } else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) { + getUserLoginToken(); + } else { + userLoginResponse = user.userAutoLoginModelFromJson(response.body); + userLoginResponse.errorResponses!.first.message!.showToast; + } + return userLoginResponse; + } + + Future getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { + ChatUserModel chatUserModel; + Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo}, + token: AppState().chatDetails!.response!.token); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + chatUserModel = chatUserModelFromJson(response.body); + return chatUserModel; + } + + //Get User Recent Chats + Future getRecentChats() async { + try { + Response response = + + + // await ApiManager.instance.get(URLs.getAllRequestsAndCount,h); + + + await ApiClient().getJsonForResponse( + "${ApiConsts.chatRecentUrl}getchathistorybyuserid", + token: AppState().chatDetails!.response!.token, + ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + return ChatUserModel.fromJson( + json.decode(response.body), + ); + } catch (e) { + throw e; + } + } + + // // Get Favorite Users + // Future getFavUsers() async { + // Response favRes = await ApiClient().getJsonForResponse( + // "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}", + // token: AppState().chatDetails!.response!.token, + // ); + // if (!kReleaseMode) { + // logger.i("res: " + favRes.body); + // } + // return ChatUserModel.fromJson(json.decode(favRes.body)); + // } + + //Get User Chat History + Future getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { + try { + Response response = await ApiClient().getJsonForResponse( + "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", + token: AppState().chatDetails!.response!.token, + ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + return response; + } catch (e) { + getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); + throw e; + } + } + // //Favorite Users // Future favUser({required int userID, required int targetUserID}) async { // Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); @@ -124,193 +136,193 @@ // fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); // return favoriteChatUser; // } -// -// //UnFavorite Users -// Future unFavUser({required int userID, required int targetUserID}) async { -// try { -// Response response = await ApiClient().postJsonForResponse( -// "${ApiConsts.chatFavUser}deleteFavUser", -// {"targetUserId": targetUserID, "userId": userID}, -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); -// return favoriteChatUser; -// } catch (e) { -// e as APIException; -// throw e; -// } + + // //UnFavorite Users + // Future unFavUser({required int userID, required int targetUserID}) async { + // try { + // Response response = await ApiClient().postJsonForResponse( + // "${ApiConsts.chatFavUser}deleteFavUser", + // {"targetUserId": targetUserID, "userId": userID}, + // token: AppState().chatDetails!.response!.token, + // ); + // if (!kReleaseMode) { + // logger.i("res: " + response.body); + // } + // fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); + // return favoriteChatUser; + // } catch (e) { + // e as APIException; + // throw e; + // } + // } + +// Upload Chat Media + Future uploadMedia(String userId, File file, String fileSource) async { + if (kDebugMode) { + print("${ApiConsts.chatMediaImageUploadUrl}upload"); + print(AppState().chatDetails!.response!.token); + } + + dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); + request.fields.addAll({'userId': userId, 'fileSource': fileSource}); + request.files.add(await MultipartFile.fromPath('files', file.path)); + request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); + StreamedResponse response = await request.send(); + String data = await response.stream.bytesToString(); + if (!kReleaseMode) { + logger.i("res: " + data); + } + return jsonDecode(data); + } + + // Download File For Chat + Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { + Response response = await ApiClient().postJsonForResponse( + "${ApiConsts.chatMediaImageUploadUrl}download", + {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, + token: AppState().chatDetails!.response!.token, + ); + Uint8List data = Uint8List.fromList(response.bodyBytes); + return data; + } + +// //Get Chat Users & Favorite Images +// Future> getUsersImages({required List encryptedEmails}) async { +// List imagesData = []; +// Response response = await ApiClient().postJsonForResponse( +// "${ApiConsts.chatUserImages}images", +// {"encryptedEmails": encryptedEmails, "fromClient": false}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); // } +// if (response.statusCode == 200) { +// imagesData = chatUserImageModelFromJson(response.body); +// } else if (response.statusCode == 500 || response.statusCode == 504) { +// getUsersImages(encryptedEmails: encryptedEmails); +// } else { +// Utils.showToast("Something went wrong while loading images"); +// imagesData = []; +// } +// return imagesData; +// } // -// // Upload Chat Media -// Future uploadMedia(String userId, File file, String fileSource) async { -// if (kDebugMode) { -// print("${ApiConsts.chatMediaImageUploadUrl}upload"); -// print(AppState().chatDetails!.response!.token); -// } -// -// dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); -// request.fields.addAll({'userId': userId, 'fileSource': fileSource}); -// request.files.add(await MultipartFile.fromPath('files', file.path)); -// request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); -// StreamedResponse response = await request.send(); -// String data = await response.stream.bytesToString(); +// //group chat apis start here. +// Future getGroupsByUserId() async { +// try { +// Response response = await ApiClient().getJsonForResponse( +// "${ApiConsts.getGroupByUserId}${AppState().chatDetails!.response!.id}", +// token: AppState().chatDetails!.response!.token, +// ); // if (!kReleaseMode) { -// logger.i("res: " + data); +// logger.i("res: " + response.body); // } -// return jsonDecode(data); +// return groups.GetUserGroups.fromRawJson(response.body); +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; // } -// -// // Download File For Chat -// Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { +// } + +// Future deleteGroup(int? groupId) async { +// try { // Response response = await ApiClient().postJsonForResponse( -// "${ApiConsts.chatMediaImageUploadUrl}download", -// {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, +// ApiConsts.deleteGroup, +// {"groupId": groupId}, // token: AppState().chatDetails!.response!.token, // ); -// Uint8List data = Uint8List.fromList(response.bodyBytes); -// return data; +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return response; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; // } -// -// //Get Chat Users & Favorite Images -// Future> getUsersImages({required List encryptedEmails}) async { -// List imagesData = []; +// } + +// Future updateGroupAdmin(int? groupId, List groupList) async { +// try { // Response response = await ApiClient().postJsonForResponse( -// "${ApiConsts.chatUserImages}images", -// {"encryptedEmails": encryptedEmails, "fromClient": false}, +// ApiConsts.updateGroupAdmin, +// {"groupId": groupId, "groupUserList": groupList}, // token: AppState().chatDetails!.response!.token, // ); // if (!kReleaseMode) { // logger.i("res: " + response.body); // } -// if (response.statusCode == 200) { -// imagesData = chatUserImageModelFromJson(response.body); -// } else if (response.statusCode == 500 || response.statusCode == 504) { -// getUsersImages(encryptedEmails: encryptedEmails); -// } else { -// Utils.showToast("Something went wrong while loading images"); -// imagesData = []; -// } -// return imagesData; +// return response; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; // } -// -// //group chat apis start here. -// Future getGroupsByUserId() async { -// try { -// Response response = await ApiClient().getJsonForResponse( -// "${ApiConsts.getGroupByUserId}${AppState().chatDetails!.response!.id}", -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// return groups.GetUserGroups.fromRawJson(response.body); -// } catch (e) { -// //if fail api returning 500 hence just printing here -// print(e); -// throw e; -// } -// } -// -// Future deleteGroup(int? groupId) async { -// try { -// Response response = await ApiClient().postJsonForResponse( -// ApiConsts.deleteGroup, -// {"groupId": groupId}, -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// return response; -// } catch (e) { -// //if fail api returning 500 hence just printing here -// print(e); -// throw e; +// } + +// Future> getGroupChatHistory(int? groupId, List groupList) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.getGroupChatHistoryAsync, +// {"groupId": groupId, "targetUserList": groupList, "CurrentId": AppState().chatDetails!.response!.id}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); // } -// } -// -// Future updateGroupAdmin(int? groupId, List groupList) async { -// try { -// Response response = await ApiClient().postJsonForResponse( -// ApiConsts.updateGroupAdmin, -// {"groupId": groupId, "groupUserList": groupList}, -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// return response; -// } catch (e) { -// //if fail api returning 500 hence just printing here -// print(e); -// throw e; +// List groupChat = []; +// List groupChatData = json.decode(response.body); +// for (var i in groupChatData) { +// groupChat.add(GetGroupChatHistoryAsync.fromJson(i)); // } -// } // -// Future> getGroupChatHistory(int? groupId, List groupList) async { -// try { -// Response response = await ApiClient().postJsonForResponse( -// ApiConsts.getGroupChatHistoryAsync, -// {"groupId": groupId, "targetUserList": groupList, "CurrentId": AppState().chatDetails!.response!.id}, -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// List groupChat = []; -// List groupChatData = json.decode(response.body); -// for (var i in groupChatData) { -// groupChat.add(GetGroupChatHistoryAsync.fromJson(i)); -// } -// -// groupChat.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); -// return groupChat; -// // for(GetGroupChatHistoryAsync i in groupChat) { -// // return GetGroupChatHistoryAsync.fromJson(jsonEncode(i)); -// // } -// } catch (e) { -// //if fail api returning 500 hence just printing here -// print(e); -// throw e; -// } +// groupChat.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); +// return groupChat; +// // for(GetGroupChatHistoryAsync i in groupChat) { +// // return GetGroupChatHistoryAsync.fromJson(jsonEncode(i)); +// // } +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; // } -// -// Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { -// try { -// Response response = await ApiClient().postJsonForResponse( -// ApiConsts.addGroupsAndUsers, -// request, -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// return response.body; -// } catch (e) { -// //if fail api returning 500 hence just printing here -// print(e); -// throw e; +// } + +// Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.addGroupsAndUsers, +// request, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); // } +// return response.body; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; // } -// -// Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { -// try { -// Response response = await ApiClient().postJsonForResponse( -// ApiConsts.updateGroupsAndUsers, -// request, -// token: AppState().chatDetails!.response!.token, -// ); -// if (!kReleaseMode) { -// logger.i("res: " + response.body); -// } -// return response.body; -// } catch (e) { -// //if fail api returning 500 hence just printing here -// print(e); -// throw e; +// } + +// Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// ApiConsts.updateGroupsAndUsers, +// request, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); // } +// return response.body; +// } catch (e) { +// //if fail api returning 500 hence just printing here +// print(e); +// throw e; // } // } +} diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index b8668078..a22545ae 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -1,15 +1,16 @@ -// import 'dart:async'; -// import 'dart:convert'; -// import 'dart:io'; -// import 'dart:typed_data'; -// import 'package:audio_waveforms/audio_waveforms.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; +import 'package:audio_waveforms/audio_waveforms.dart'; // import 'package:easy_localization/easy_localization.dart'; -// import 'package:flutter/cupertino.dart'; -// import 'package:flutter/foundation.dart'; -// import 'package:flutter/services.dart'; -// import 'package:http/http.dart'; -// import 'package:just_audio/just_audio.dart' as JustAudio; -// import 'package:just_audio/just_audio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:http/http.dart'; +import 'package:just_audio/just_audio.dart' as JustAudio; +import 'package:just_audio/just_audio.dart'; + // import 'package:mohem_flutter_app/api/chat/chat_api_client.dart'; // import 'package:mohem_flutter_app/api/my_team/my_team_api_client.dart'; // import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -33,1931 +34,1939 @@ // import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; // import 'package:mohem_flutter_app/widgets/image_picker.dart'; // import 'package:open_filex/open_filex.dart'; -// import 'package:path_provider/path_provider.dart'; -// import 'package:permission_handler/permission_handler.dart'; -// import 'package:signalr_netcore/hub_connection.dart'; -// import 'package:signalr_netcore/signalr_client.dart'; -// import 'package:uuid/uuid.dart'; -// import 'package:flutter/material.dart' as Material; -// -// class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { -// ScrollController scrollController = ScrollController(); -// -// TextEditingController message = TextEditingController(); -// TextEditingController search = TextEditingController(); -// TextEditingController searchGroup = TextEditingController(); -// -// List userChatHistory = [], repliedMsg = []; -// List? pChatHistory, searchedChats; -// String chatCID = ''; -// bool isLoading = true; -// bool isChatScreenActive = false; -// int receiverID = 0; -// late File selectedFile; -// String sFileType = ""; -// -// List favUsersList = []; -// int paginationVal = 0; -// int? cTypingUserId = 0; -// bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; -// -// // Audio Recoding Work -// Timer? _timer; -// int _recodeDuration = 0; -// bool isRecoding = false; -// bool isPause = false; -// bool isPlaying = false; -// String? path; -// String? musicFile; -// late Directory appDirectory; -// late RecorderController recorderController; -// late PlayerController playerController; -// List getEmployeeSubordinatesList = []; -// List teamMembersList = []; -// groups.GetUserGroups userGroups = groups.GetUserGroups(); -// Material.TextDirection textDirection = Material.TextDirection.ltr; -// bool isRTL = false; -// String msgText = ""; -// -// //Chat Home Page Counter -// int chatUConvCounter = 0; -// -// late List groupChatHistory, groupChatReplyData; -// -// /// Search Provider -// List? chatUsersList = []; -// int pageNo = 1; -// -// bool disbaleChatForThisUser = false; -// List? uGroups = [], searchGroups = []; -// -// Future getUserAutoLoginToken() async { -// userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); -// -// if (userLoginResponse.StatusCode == 500) { -// disbaleChatForThisUser = true; -// notifyListeners(); -// } -// -// if (userLoginResponse.response != null) { -// AppState().setchatUserDetails = userLoginResponse; -// } else { -// AppState().setchatUserDetails = userLoginResponse; -// Utils.showToast( -// userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", -// ); -// disbaleChatForThisUser = true; -// notifyListeners(); -// } -// } -// -// Future buildHubConnection() async { -// chatHubConnection = await getHubConnection(); -// await chatHubConnection.start(); -// if (kDebugMode) { -// logger.i("Hub Conn: Startedddddddd"); -// } -// chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); -// chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); -// -// //group On message -// -// chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived); -// } -// -// Future getHubConnection() async { -// HubConnection hub; -// HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); -// hub = HubConnectionBuilder() -// .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) -// .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); -// return hub; -// } -// -// void registerEvents() { -// chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); -// // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); -// -// chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); -// chatHubConnection.on("OnUserTypingAsync", onUserTyping); -// chatHubConnection.on("OnUserCountAsync", userCountAsync); -// // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); -// chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); -// chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); -// chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); -// -// // -// // {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]} -// -// if (kDebugMode) { -// logger.i("All listeners registered"); -// } -// } -// -// Future getUserRecentChats() async { -// ChatUserModel recentChat = await ChatApiClient().getRecentChats(); -// ChatUserModel favUList = await ChatApiClient().getFavUsers(); -// // userGroups = await ChatApiClient().getGroupsByUserId(); -// if (favUList.response != null && recentChat.response != null) { -// favUsersList = favUList.response!; -// 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) { -// user.isFav = favUser.isFav; -// } -// } -// } -// } -// pChatHistory = recentChat.response ?? []; -// uGroups = userGroups.groupresponse ?? []; -// 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())); -// sort(); -// notifyListeners(); -// if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { -// getUserImages(); -// } -// } -// -// Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { -// await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); -// return ""; -// } -// -// void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { -// isLoading = true; -// if (isNewChat) userChatHistory = []; -// if (!loadMore) paginationVal = 0; -// isChatScreenActive = true; -// receiverID = receiverUID; -// Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); -// if (response.statusCode == 204) { -// if (isNewChat) { -// userChatHistory = []; -// } else if (loadMore) {} -// } else { -// if (loadMore) { -// List temp = getSingleUserChatModel(response.body).reversed.toList(); -// userChatHistory.addAll(temp); -// } else { -// userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); -// } -// } -// isLoading = false; -// notifyListeners(); -// -// if (isChatScreenActive && receiverUID == receiverID) { -// markRead(userChatHistory, receiverUID); -// } -// -// generateConvId(); -// } -// -// void generateConvId() async { -// Uuid uuid = const Uuid(); -// chatCID = uuid.v4(); -// } -// -// void markRead(List data, int receiverID) { -// for (SingleUserChatModel element in data!) { -// if (AppState().chatDetails!.response!.id! == element.targetUserId) { -// if (element.isSeen != null) { -// if (!element.isSeen!) { -// element.isSeen = true; -// dynamic data = [ -// { -// "userChatHistoryId": element.userChatHistoryId, -// "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, -// "isDelivered": true, -// "isSeen": true, -// } -// ]; -// updateUserChatHistoryStatusAsync(data); -// notifyListeners(); -// } -// } -// for (ChatUser element in searchedChats!) { -// if (element.id == receiverID) { -// element.unreadMessageCount = 0; -// chatUConvCounter = 0; -// } -// } -// } -// } -// notifyListeners(); -// } -// -// void updateUserChatHistoryStatusAsync(List data) { -// try { -// chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); -// } catch (e) { -// throw e; -// } -// } -// -// void updateUserChatHistoryOnMsg(List data) { -// try { -// chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); -// } catch (e) { -// throw e; -// } -// } -// -// List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); -// -// List getGroupChatHistoryAsync(String str) => -// List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); -// -// Future uploadAttachments(String userId, File file, String fileSource) async { -// dynamic result; -// try { -// Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); -// if (response != null) { -// result = response; -// } else { -// result = []; -// } -// } catch (e) { -// throw e; -// } -// return result; -// } -// -// void updateUserChatStatus(List? args) { -// dynamic items = args!.toList(); -// for (var cItem in items[0]) { -// for (SingleUserChatModel chat in userChatHistory) { -// if (cItem["contantNo"].toString() == chat.contantNo.toString()) { -// chat.isSeen = cItem["isSeen"]; -// chat.isDelivered = cItem["isDelivered"]; -// } -// } -// } -// notifyListeners(); -// } -// -// void getGroupUserStatus(List? args) { -// //note: need to implement this function... -// print(args); -// } -// -// void onChatSeen(List? args) { -// dynamic items = args!.toList(); -// // for (var user in searchedChats!) { -// // if (user.id == items.first["id"]) { -// // user.userStatus = items.first["userStatus"]; -// // } -// // } -// // notifyListeners(); -// } -// -// void userCountAsync(List? args) { -// dynamic items = args!.toList(); -// // logger.d(items); -// //logger.d("---------------------------------User Count Async -------------------------------------"); -// //logger.d(items); -// // for (var user in searchedChats!) { -// // if (user.id == items.first["id"]) { -// // user.userStatus = items.first["userStatus"]; -// // } -// // } -// // notifyListeners(); -// } -// -// void updateChatHistoryWindow(List? args) { -// dynamic items = args!.toList(); -// if (kDebugMode) { -// logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); -// } -// logger.d(items); -// // for (var user in searchedChats!) { -// // if (user.id == items.first["id"]) { -// // user.userStatus = items.first["userStatus"]; -// // } -// // } -// // notifyListeners(); -// } -// -// void chatNotDelivered(List? args) { -// dynamic items = args!.toList(); -// for (dynamic item in items[0]) { -// for (ChatUser element in searchedChats!) { -// if (element.id == item["currentUserId"]) { -// int? val = element.unreadMessageCount ?? 0; -// element.unreadMessageCount = val! + 1; -// } -// } -// } -// notifyListeners(); -// } -// -// void changeStatus(List? args) { -// dynamic items = args!.toList(); -// for (ChatUser user in searchedChats!) { -// 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"]; -// } -// } -// } -// -// notifyListeners(); -// } -// -// void filter(String value) async { -// List? tmp = []; -// if (value.isEmpty || value == "") { -// tmp = pChatHistory; -// } else { -// for (ChatUser element in pChatHistory!) { -// if (element.userName!.toLowerCase().contains(value.toLowerCase())) { -// tmp.add(element); -// } -// } -// } -// searchedChats = tmp; -// notifyListeners(); -// } -// -// Future onMsgReceived(List? parameters) async { -// List data = [], temp = []; -// for (dynamic msg in parameters!) { -// data = getSingleUserChatModel(jsonEncode(msg)); -// temp = getSingleUserChatModel(jsonEncode(msg)); -// data.first.targetUserId = temp.first.currentUserId; -// data.first.targetUserName = temp.first.currentUserName; -// data.first.targetUserEmail = temp.first.currentUserEmail; -// data.first.currentUserId = temp.first.targetUserId; -// data.first.currentUserName = temp.first.targetUserName; -// data.first.currentUserEmail = temp.first.targetUserEmail; -// -// if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { -// data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); -// } -// if (data.first.userChatReplyResponse != null) { -// if (data.first.fileTypeResponse != null) { -// if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { -// data.first.userChatReplyResponse!.image = await ChatApiClient() -// .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); -// data.first.userChatReplyResponse!.isImageLoaded = true; -// } -// } -// } -// } -// -// if (searchedChats != null) { -// dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); -// if (contain.isEmpty) { -// List emails = []; -// emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); -// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); -// searchedChats!.add( -// ChatUser( -// id: data.first.currentUserId, -// userName: data.first.currentUserName, -// email: data.first.currentUserEmail, -// unreadMessageCount: 0, -// isImageLoading: false, -// image: chatImages!.first.profilePicture ?? "", -// isImageLoaded: true, -// userStatus: 1, -// isTyping: false, -// userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), -// ), -// ); -// } -// } -// setMsgTune(); -// if (isChatScreenActive && data.first.currentUserId == receiverID) { -// userChatHistory.insert(0, data.first); -// } else { -// if (searchedChats != null) { -// for (ChatUser user in searchedChats!) { -// if (user.id == data.first.currentUserId) { -// int tempCount = user.unreadMessageCount ?? 0; -// user.unreadMessageCount = tempCount + 1; -// } -// } -// sort(); -// } -// } -// -// List list = [ -// { -// "userChatHistoryId": data.first.userChatHistoryId, -// "TargetUserId": temp.first.targetUserId, -// "isDelivered": true, -// "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false -// } -// ]; -// updateUserChatHistoryOnMsg(list); -// invokeChatCounter(userId: AppState().chatDetails!.response!.id!); -// notifyListeners(); -// } -// -// Future onGroupMsgReceived(List? parameters) async { -// List data = [], temp = []; -// -// for (dynamic msg in parameters!) { -// // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); -// data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); -// temp = data; -// // data.first.currentUserId = temp.first.currentUserId; -// // data.first.currentUserName = temp.first.currentUserName; -// // -// // data.first.currentUserId = temp.first.currentUserId; -// // data.first.currentUserName = temp.first.currentUserName; -// -// if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { -// data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); -// } -// if (data.first.groupChatReplyResponse != null) { -// if (data.first.fileTypeResponse != null) { -// if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { -// data.first.groupChatReplyResponse!.image = await ChatApiClient() -// .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); -// data.first.groupChatReplyResponse!.isImageLoaded = true; -// } -// } -// } -// } -// -// // if (searchedChats != null) { -// // dynamic contain = searchedChats! -// // .where((ChatUser element) => element.id == data.first.currentUserId); -// // if (contain.isEmpty) { -// // List emails = []; -// // emails.add(await EmailImageEncryption() -// // .encrypt(val: data.first.currentUserEmail!)); -// // List chatImages = -// // await ChatApiClient().getUsersImages(encryptedEmails: emails); -// // searchedChats!.add( -// // ChatUser( -// // id: data.first.currentUserId, -// // userName: data.first.currentUserName, -// // email: data.first.currentUserEmail, -// // unreadMessageCount: 0, -// // isImageLoading: false, -// // image: chatImages!.first.profilePicture ?? "", -// // isImageLoaded: true, -// // userStatus: 1, -// // isTyping: false, -// // userLocalDownlaodedImage: await downloadImageLocal( -// // chatImages.first.profilePicture, -// // data.first.currentUserId.toString()), -// // ), -// // ); -// // } -// // } -// groupChatHistory.insert(0, data.first); -// setMsgTune(); -// // if (isChatScreenActive && data.first.currentUserId == receiverID) { -// -// // } else { -// // if (searchedChats != null) { -// // for (ChatUser user in searchedChats!) { -// // if (user.id == data.first.currentUserId) { -// // int tempCount = user.unreadMessageCount ?? 0; -// // user.unreadMessageCount = tempCount + 1; -// // } -// // } -// sort(); -// //} -// //} -// // -// // List list = [ -// // { -// // "userChatHistoryId": data.first.groupId, -// // "TargetUserId": temp.first.currentUserId, -// // "isDelivered": true, -// // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID -// // ? true -// // : false -// // } -// // ]; -// // updateUserChatHistoryOnMsg(list); -// // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); -// notifyListeners(); -// } -// -// void OnSubmitChatAsync(List? parameters) { -// print(isChatScreenActive); -// print(receiverID); -// print(isChatScreenActive); -// logger.i(parameters); -// List data = [], temp = []; -// for (dynamic msg in parameters!) { -// data = getSingleUserChatModel(jsonEncode(msg)); -// temp = getSingleUserChatModel(jsonEncode(msg)); -// data.first.targetUserId = temp.first.currentUserId; -// data.first.targetUserName = temp.first.currentUserName; -// data.first.targetUserEmail = temp.first.currentUserEmail; -// data.first.currentUserId = temp.first.targetUserId; -// data.first.currentUserName = temp.first.targetUserName; -// data.first.currentUserEmail = temp.first.targetUserEmail; -// } -// if (isChatScreenActive && data.first.currentUserId == receiverID) { -// int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); -// logger.d(index); -// userChatHistory[index] = data.first; -// } -// -// notifyListeners(); -// } -// -// void sort() { -// searchedChats!.sort( -// (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), -// ); -// } -// -// void onUserTyping(List? parameters) { -// for (ChatUser user in searchedChats!) { -// if (user.id == parameters![1] && parameters[0] == true) { -// user.isTyping = parameters[0] as bool?; -// Future.delayed( -// const Duration(seconds: 2), -// () { -// user.isTyping = false; -// notifyListeners(); -// }, -// ); -// } -// } -// notifyListeners(); -// } -// -// int getFileType(String value) { -// switch (value) { -// case ".pdf": -// return 1; -// case ".png": -// return 3; -// case ".txt": -// return 5; -// case ".jpg": -// return 12; -// case ".jpeg": -// return 4; -// case ".xls": -// return 7; -// case ".xlsx": -// return 7; -// case ".doc": -// return 6; -// case ".docx": -// return 6; -// case ".ppt": -// return 8; -// case ".pptx": -// return 8; -// case ".zip": -// return 2; -// case ".rar": -// return 2; -// case ".aac": -// return 13; -// case ".mp3": -// return 14; -// case ".mp4": -// return 16; -// case ".mov": -// return 16; -// case ".avi": -// return 16; -// case ".flv": -// return 16; -// -// default: -// return 0; -// } -// } -// -// String getFileTypeDescription(String value) { -// switch (value) { -// case ".pdf": -// return "application/pdf"; -// case ".png": -// return "image/png"; -// case ".txt": -// return "text/plain"; -// case ".jpg": -// return "image/jpg"; -// case ".jpeg": -// return "image/jpeg"; -// case ".ppt": -// return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; -// case ".pptx": -// return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; -// case ".doc": -// return "application/vnd.openxmlformats-officedocument.wordprocessingm"; -// case ".docx": -// return "application/vnd.openxmlformats-officedocument.wordprocessingm"; -// case ".xls": -// return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; -// case ".xlsx": -// return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; -// case ".zip": -// return "application/octet-stream"; -// case ".rar": -// return "application/octet-stream"; -// case ".aac": -// return "audio/aac"; -// case ".mp3": -// return "audio/mp3"; -// case ".mp4": -// return "video/mp4"; -// case ".avi": -// return "video/avi"; -// case ".flv": -// return "video/flv"; -// case ".mov": -// return "video/mov"; -// -// default: -// return ""; -// } -// } -// -// Future sendChatToServer( -// {required int chatEventId, -// required fileTypeId, -// required int targetUserId, -// required String targetUserName, -// required chatReplyId, -// required bool isAttachment, -// required bool isReply, -// Uint8List? image, -// required bool isImageLoaded, -// String? userEmail, -// int? userStatus, -// File? voiceFile, -// required bool isVoiceAttached}) async { -// Uuid uuid = const Uuid(); -// String contentNo = uuid.v4(); -// String msg; -// if (isVoiceAttached) { -// msg = voiceFile!.path.split("/").last; -// } else { -// msg = message.text; -// logger.w(msg); -// } -// SingleUserChatModel data = SingleUserChatModel( -// userChatHistoryId: 0, -// chatEventId: chatEventId, -// chatSource: 1, -// contant: msg, -// contantNo: contentNo, -// conversationId: chatCID, -// createdDate: DateTime.now(), -// currentUserId: AppState().chatDetails!.response!.id, -// currentUserName: AppState().chatDetails!.response!.userName, -// targetUserId: targetUserId, -// targetUserName: targetUserName, -// isReplied: false, -// fileTypeId: fileTypeId, -// userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, -// fileTypeResponse: isAttachment -// ? FileTypeResponse( -// fileTypeId: fileTypeId, -// fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), -// fileKind: "file", -// fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, -// fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), -// ) -// : null, -// image: image, -// isImageLoaded: isImageLoaded, -// voice: isVoiceMsg ? voiceFile! : null, -// voiceController: isVoiceMsg ? AudioPlayer() : null); -// if (kDebugMode) { -// logger.i("model data: " + jsonEncode(data)); -// } -// userChatHistory.insert(0, data); -// isTextMsg = false; -// isReplyMsg = false; -// isAttachmentMsg = false; -// isVoiceMsg = false; -// sFileType = ""; -// message.clear(); -// notifyListeners(); -// -// String chatData = -// '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; -// -// await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); -// } -// -// //groupChatMessage -// -// Future sendGroupChatToServer( -// {required int chatEventId, -// required fileTypeId, -// required int targetGroupId, -// required String targetUserName, -// required chatReplyId, -// required bool isAttachment, -// required bool isReply, -// Uint8List? image, -// required bool isImageLoaded, -// String? userEmail, -// int? userStatus, -// File? voiceFile, -// required bool isVoiceAttached, -// required List userList}) async { -// Uuid uuid = const Uuid(); -// String contentNo = uuid.v4(); -// String msg; -// if (isVoiceAttached) { -// msg = voiceFile!.path.split("/").last; -// } else { -// msg = message.text; -// logger.w(msg); -// } -// groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( -// //userChatHistoryId: 0, -// chatEventId: chatEventId, -// chatSource: 1, -// contant: msg, -// contantNo: contentNo, -// conversationId: chatCID, -// createdDate: DateTime.now().toString(), -// currentUserId: AppState().chatDetails!.response!.id, -// currentUserName: AppState().chatDetails!.response!.userName, -// groupId: targetGroupId, -// groupName: targetUserName, -// isReplied: false, -// fileTypeId: fileTypeId, -// fileTypeResponse: isAttachment -// ? groupchathistory.FileTypeResponse( -// fileTypeId: fileTypeId, -// fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), -// fileKind: "file", -// fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, -// fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) -// : null, -// image: image, -// isImageLoaded: isImageLoaded, -// voice: isVoiceMsg ? voiceFile! : null, -// voiceController: isVoiceMsg ? AudioPlayer() : null); -// if (kDebugMode) { -// logger.i("model data: " + jsonEncode(data)); -// } -// groupChatHistory.insert(0, data); -// isTextMsg = false; -// isReplyMsg = false; -// isAttachmentMsg = false; -// isVoiceMsg = false; -// sFileType = ""; -// message.clear(); -// notifyListeners(); -// -// List targetUsers = []; -// -// for (GroupUserList element in userList) { -// targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); -// } -// -// String chatData = -// '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; -// -// await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); -// } -// -// void sendGroupChatMessage( -// BuildContext context, { -// required int targetUserId, -// required int userStatus, -// required String userEmail, -// required String targetUserName, -// required List userList, -// }) async { -// if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { -// logger.d("// Normal Text Message"); -// if (message.text.isEmpty) { -// return; -// } -// sendGroupChatToServer( -// chatEventId: 1, -// fileTypeId: null, -// targetGroupId: targetUserId, -// targetUserName: targetUserName, -// isAttachment: false, -// chatReplyId: null, -// isReply: false, -// isImageLoaded: false, -// image: null, -// isVoiceAttached: false, -// userEmail: userEmail, -// userStatus: userStatus, -// userList: userList); -// } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { -// logger.d("// Text Message as Reply"); -// if (message.text.isEmpty) { -// return; -// } -// sendGroupChatToServer( -// chatEventId: 1, -// fileTypeId: null, -// targetGroupId: targetUserId, -// targetUserName: targetUserName, -// chatReplyId: groupChatReplyData.first.groupChatHistoryId, -// isAttachment: false, -// isReply: true, -// isImageLoaded: groupChatReplyData.first.isImageLoaded!, -// image: groupChatReplyData.first.image, -// isVoiceAttached: false, -// voiceFile: null, -// userEmail: userEmail, -// userStatus: userStatus, -// userList: userList); -// } -// // Attachment -// else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { -// logger.d("// Normal Image Message"); -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); -// String? ext = getFileExtension(selectedFile.path); -// Utils.hideLoading(context); -// sendGroupChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// targetGroupId: targetUserId, -// targetUserName: targetUserName, -// isAttachment: true, -// chatReplyId: null, -// isReply: false, -// isImageLoaded: true, -// image: selectedFile.readAsBytesSync(), -// isVoiceAttached: false, -// userEmail: userEmail, -// userStatus: userStatus, -// userList: userList); -// } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { -// logger.d("// Image as Reply Msg"); -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); -// String? ext = getFileExtension(selectedFile.path); -// Utils.hideLoading(context); -// sendGroupChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// targetGroupId: targetUserId, -// targetUserName: targetUserName, -// isAttachment: true, -// chatReplyId: repliedMsg.first.userChatHistoryId, -// isReply: true, -// isImageLoaded: true, -// image: selectedFile.readAsBytesSync(), -// isVoiceAttached: false, -// userEmail: userEmail, -// userStatus: userStatus, -// userList: userList); -// } -// //Voice -// -// else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { -// logger.d("// Normal Voice Message"); -// -// if (!isPause) { -// path = await recorderController.stop(false); -// } -// if (kDebugMode) { -// logger.i("path:" + path!); -// } -// File voiceFile = File(path!); -// voiceFile.readAsBytesSync(); -// _timer?.cancel(); -// isPause = false; -// isPlaying = false; -// isRecoding = false; -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); -// String? ext = getFileExtension(voiceFile.path); -// Utils.hideLoading(context); -// sendGroupChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// //, -// targetGroupId: targetUserId, -// targetUserName: targetUserName, -// chatReplyId: null, -// isAttachment: true, -// isReply: isReplyMsg, -// isImageLoaded: false, -// voiceFile: voiceFile, -// isVoiceAttached: true, -// userEmail: userEmail, -// userStatus: userStatus, -// userList: userList); -// notifyListeners(); -// } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { -// logger.d("// Voice as Reply Msg"); -// -// if (!isPause) { -// path = await recorderController.stop(false); -// } -// if (kDebugMode) { -// logger.i("path:" + path!); -// } -// File voiceFile = File(path!); -// voiceFile.readAsBytesSync(); -// _timer?.cancel(); -// isPause = false; -// isPlaying = false; -// isRecoding = false; -// -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); -// String? ext = getFileExtension(voiceFile.path); -// Utils.hideLoading(context); -// sendGroupChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// targetGroupId: targetUserId, -// targetUserName: targetUserName, -// chatReplyId: null, -// isAttachment: true, -// isReply: isReplyMsg, -// isImageLoaded: false, -// voiceFile: voiceFile, -// isVoiceAttached: true, -// userEmail: userEmail, -// userStatus: userStatus, -// userList: userList); -// notifyListeners(); -// } -// if (searchedChats != null) { -// dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); -// if (contain.isEmpty) { -// List emails = []; -// emails.add(await EmailImageEncryption().encrypt(val: userEmail)); -// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); -// searchedChats!.add( -// ChatUser( -// id: targetUserId, -// userName: targetUserName, -// unreadMessageCount: 0, -// email: userEmail, -// isImageLoading: false, -// image: chatImages.first.profilePicture ?? "", -// isImageLoaded: true, -// isTyping: false, -// isFav: false, -// userStatus: userStatus, -// // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), -// ), -// ); -// notifyListeners(); -// } -// } -// } -// -// void sendChatMessage( -// BuildContext context, { -// required int targetUserId, -// required int userStatus, -// required String userEmail, -// required String targetUserName, -// }) async { -// if (kDebugMode) { -// print("====================== Values ============================"); -// print("Is Text " + isTextMsg.toString()); -// print("isReply " + isReplyMsg.toString()); -// print("isAttachment " + isAttachmentMsg.toString()); -// print("isVoice " + isVoiceMsg.toString()); -// } -// //Text -// if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { -// logger.d("// Normal Text Message"); -// if (message.text.isEmpty) { -// return; -// } -// sendChatToServer( -// chatEventId: 1, -// fileTypeId: null, -// targetUserId: targetUserId, -// targetUserName: targetUserName, -// isAttachment: false, -// chatReplyId: null, -// isReply: false, -// isImageLoaded: false, -// image: null, -// isVoiceAttached: false, -// userEmail: userEmail, -// userStatus: userStatus); -// } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { -// logger.d("// Text Message as Reply"); -// if (message.text.isEmpty) { -// return; -// } -// sendChatToServer( -// chatEventId: 1, -// fileTypeId: null, -// targetUserId: targetUserId, -// targetUserName: targetUserName, -// chatReplyId: repliedMsg.first.userChatHistoryId, -// isAttachment: false, -// isReply: true, -// isImageLoaded: repliedMsg.first.isImageLoaded!, -// image: repliedMsg.first.image, -// isVoiceAttached: false, -// voiceFile: null, -// userEmail: userEmail, -// userStatus: userStatus); -// } -// // Attachment -// else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { -// logger.d("// Normal Image Message"); -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); -// String? ext = getFileExtension(selectedFile.path); -// Utils.hideLoading(context); -// sendChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// targetUserId: targetUserId, -// targetUserName: targetUserName, -// isAttachment: true, -// chatReplyId: null, -// isReply: false, -// isImageLoaded: true, -// image: selectedFile.readAsBytesSync(), -// isVoiceAttached: false, -// userEmail: userEmail, -// userStatus: userStatus); -// } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { -// logger.d("// Image as Reply Msg"); -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); -// String? ext = getFileExtension(selectedFile.path); -// Utils.hideLoading(context); -// sendChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// targetUserId: targetUserId, -// targetUserName: targetUserName, -// isAttachment: true, -// chatReplyId: repliedMsg.first.userChatHistoryId, -// isReply: true, -// isImageLoaded: true, -// image: selectedFile.readAsBytesSync(), -// isVoiceAttached: false, -// userEmail: userEmail, -// userStatus: userStatus); -// } -// //Voice -// -// else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { -// logger.d("// Normal Voice Message"); -// -// if (!isPause) { -// path = await recorderController.stop(false); -// } -// if (kDebugMode) { -// logger.i("path:" + path!); -// } -// File voiceFile = File(path!); -// voiceFile.readAsBytesSync(); -// _timer?.cancel(); -// isPause = false; -// isPlaying = false; -// isRecoding = false; -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); -// String? ext = getFileExtension(voiceFile.path); -// Utils.hideLoading(context); -// sendChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// targetUserId: targetUserId, -// targetUserName: targetUserName, -// chatReplyId: null, -// isAttachment: true, -// isReply: isReplyMsg, -// isImageLoaded: false, -// voiceFile: voiceFile, -// isVoiceAttached: true, -// userEmail: userEmail, -// userStatus: userStatus); -// notifyListeners(); -// } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { -// logger.d("// Voice as Reply Msg"); -// -// if (!isPause) { -// path = await recorderController.stop(false); -// } -// if (kDebugMode) { -// logger.i("path:" + path!); -// } -// File voiceFile = File(path!); -// voiceFile.readAsBytesSync(); -// _timer?.cancel(); -// isPause = false; -// isPlaying = false; -// isRecoding = false; -// -// Utils.showLoading(context); -// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); -// String? ext = getFileExtension(voiceFile.path); -// Utils.hideLoading(context); -// sendChatToServer( -// chatEventId: 2, -// fileTypeId: getFileType(ext.toString()), -// targetUserId: targetUserId, -// targetUserName: targetUserName, -// chatReplyId: null, -// isAttachment: true, -// isReply: isReplyMsg, -// isImageLoaded: false, -// voiceFile: voiceFile, -// isVoiceAttached: true, -// userEmail: userEmail, -// userStatus: userStatus); -// notifyListeners(); -// } -// if (searchedChats != null) { -// dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); -// if (contain.isEmpty) { -// List emails = []; -// emails.add(await EmailImageEncryption().encrypt(val: userEmail)); -// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); -// searchedChats!.add( -// ChatUser( -// id: targetUserId, -// userName: targetUserName, -// unreadMessageCount: 0, -// email: userEmail, -// isImageLoading: false, -// image: chatImages.first.profilePicture ?? "", -// isImageLoaded: true, -// isTyping: false, -// isFav: false, -// userStatus: userStatus, -// userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), -// ), -// ); -// notifyListeners(); -// } -// } -// // else { -// // List emails = []; -// // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); -// // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); -// // searchedChats!.add( -// // ChatUser( -// // id: targetUserId, -// // userName: targetUserName, -// // unreadMessageCount: 0, -// // email: userEmail, -// // isImageLoading: false, -// // image: chatImages.first.profilePicture ?? "", -// // isImageLoaded: true, -// // isTyping: false, -// // isFav: false, -// // userStatus: userStatus, -// // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), -// // ), -// // ); -// // notifyListeners(); -// // } -// } -// -// void selectImageToUpload(BuildContext context) { -// ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { -// if (checkFileSize(file.path)) { -// selectedFile = file; -// isAttachmentMsg = true; -// isTextMsg = false; -// sFileType = getFileExtension(file.path)!; -// message.text = file.path.split("/").last; -// Navigator.of(context).pop(); -// } else { -// Utils.showToast("Max 1 mb size is allowed to upload"); -// } -// notifyListeners(); -// }); -// } -// -// void removeAttachment() { -// isAttachmentMsg = false; -// sFileType = ""; -// message.text = ''; -// notifyListeners(); -// } -// -// String? getFileExtension(String fileName) { -// try { -// if (kDebugMode) { -// logger.i("ext: " + "." + fileName.split('.').last); -// } -// return "." + fileName.split('.').last; -// } catch (e) { -// return null; -// } -// } -// -// bool checkFileSize(String path) { -// int fileSizeLimit = 5120; -// File f = File(path); -// double fileSizeInKB = f.lengthSync() / 5000; -// double fileSizeInMB = fileSizeInKB / 5000; -// if (fileSizeInKB > fileSizeLimit) { -// return false; -// } else { -// return true; -// } -// } -// -// String getType(String type) { -// switch (type) { -// case ".pdf": -// return "assets/images/pdf.svg"; -// case ".png": -// return "assets/images/png.svg"; -// case ".txt": -// return "assets/icons/chat/txt.svg"; -// case ".jpg": -// return "assets/images/jpg.svg"; -// case ".jpeg": -// return "assets/images/jpg.svg"; -// case ".xls": -// return "assets/icons/chat/xls.svg"; -// case ".xlsx": -// return "assets/icons/chat/xls.svg"; -// case ".doc": -// return "assets/icons/chat/doc.svg"; -// case ".docx": -// return "assets/icons/chat/doc.svg"; -// case ".ppt": -// return "assets/icons/chat/ppt.svg"; -// case ".pptx": -// return "assets/icons/chat/ppt.svg"; -// case ".zip": -// return "assets/icons/chat/zip.svg"; -// case ".rar": -// return "assets/icons/chat/zip.svg"; -// case ".aac": -// return "assets/icons/chat/aac.svg"; -// case ".mp3": -// return "assets/icons/chat/zip.mp3"; -// default: -// return "assets/images/thumb.svg"; -// } -// } -// -// void chatReply(SingleUserChatModel data) { -// repliedMsg = []; -// data.isReplied = true; -// isReplyMsg = true; -// repliedMsg.add(data); -// notifyListeners(); -// } -// -// void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { -// groupChatReplyData = []; -// data.isReplied = true; -// isReplyMsg = true; -// groupChatReplyData.add(data); -// notifyListeners(); -// } -// -// void closeMe() { -// repliedMsg = []; -// isReplyMsg = false; -// notifyListeners(); -// } -// -// String dateFormte(DateTime data) { -// DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); -// f.format(data); -// return f.format(data); -// } -// -// Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { -// fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); -// if (favoriteChatUser.response != null) { -// for (ChatUser user in searchedChats!) { -// if (user.id == favoriteChatUser.response!.targetUserId!) { -// user.isFav = favoriteChatUser.response!.isFav; -// dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); -// if (contain.isEmpty) { -// favUsersList.add(user); -// } -// } -// } -// -// for (ChatUser user in chatUsersList!) { -// if (user.id == favoriteChatUser.response!.targetUserId!) { -// user.isFav = favoriteChatUser.response!.isFav; -// dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); -// if (contain.isEmpty) { -// favUsersList.add(user); -// } -// } -// } -// } -// if (fromSearch) { -// for (ChatUser user in favUsersList) { -// if (user.id == targetUserID) { -// user.userLocalDownlaodedImage = null; -// user.isImageLoading = false; -// user.isImageLoaded = false; -// } -// } -// } -// notifyListeners(); -// } -// -// Future unFavoriteUser({required int userID, required int targetUserID}) async { -// fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); -// -// if (favoriteChatUser.response != null) { -// for (ChatUser user in searchedChats!) { -// if (user.id == favoriteChatUser.response!.targetUserId!) { -// user.isFav = favoriteChatUser.response!.isFav; -// } -// } -// favUsersList.removeWhere( -// (ChatUser element) => element.id == targetUserID, -// ); -// } -// -// for (ChatUser user in chatUsersList!) { -// if (user.id == favoriteChatUser.response!.targetUserId!) { -// user.isFav = favoriteChatUser.response!.isFav; -// } -// } -// -// notifyListeners(); -// } -// -// void clearSelections() { -// searchedChats = pChatHistory; -// search.clear(); -// isChatScreenActive = false; -// receiverID = 0; -// paginationVal = 0; -// message.text = ''; -// isAttachmentMsg = false; -// repliedMsg = []; -// sFileType = ""; -// isReplyMsg = false; -// isTextMsg = false; -// isVoiceMsg = false; -// notifyListeners(); -// } -// -// void clearAll() { -// searchedChats = pChatHistory; -// search.clear(); -// isChatScreenActive = false; -// receiverID = 0; -// paginationVal = 0; -// message.text = ''; -// isTextMsg = false; -// isAttachmentMsg = false; -// isVoiceMsg = false; -// isReplyMsg = false; -// repliedMsg = []; -// sFileType = ""; -// } -// -// void disposeData() { -// if (!disbaleChatForThisUser) { -// search.clear(); -// isChatScreenActive = false; -// receiverID = 0; -// paginationVal = 0; -// message.text = ''; -// isTextMsg = false; -// isAttachmentMsg = false; -// isVoiceMsg = false; -// isReplyMsg = false; -// repliedMsg = []; -// sFileType = ""; -// deleteData(); -// favUsersList.clear(); -// searchedChats?.clear(); -// pChatHistory?.clear(); -// uGroups?.clear(); -// searchGroup?.clear(); -// chatHubConnection.stop(); -// AppState().chatDetails = null; -// } -// } -// -// void deleteData() { -// List exists = [], unique = []; -// if (searchedChats != null) exists.addAll(searchedChats!); -// exists.addAll(favUsersList!); -// Map profileMap = {}; -// for (ChatUser item in exists) { -// profileMap[item.email!] = item; -// } -// unique = profileMap.values.toList(); -// for (ChatUser element in unique!) { -// deleteFile(element.id.toString()); -// } -// } -// -// void getUserImages() async { -// List emails = []; -// List exists = [], unique = []; -// exists.addAll(searchedChats!); -// exists.addAll(favUsersList!); -// Map profileMap = {}; -// for (ChatUser item in exists) { -// profileMap[item.email!] = item; -// } -// unique = profileMap.values.toList(); -// for (ChatUser element in unique!) { -// emails.add(await EmailImageEncryption().encrypt(val: element.email!)); -// } -// -// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); -// for (ChatUser user in searchedChats!) { -// for (ChatUserImageModel uImage in chatImages) { -// if (user.email == uImage.email) { -// user.image = uImage.profilePicture ?? ""; -// user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); -// user.isImageLoading = false; -// user.isImageLoaded = true; -// } -// } -// } -// for (ChatUser favUser in favUsersList) { -// for (ChatUserImageModel uImage in chatImages) { -// if (favUser.email == uImage.email) { -// favUser.image = uImage.profilePicture ?? ""; -// favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); -// favUser.isImageLoading = false; -// favUser.isImageLoaded = true; -// } -// } -// } -// -// notifyListeners(); -// } -// -// Future downloadImageLocal(String? encodedBytes, String userID) async { -// File? myfile; -// if (encodedBytes == null) { -// return myfile; -// } else { -// await deleteFile(userID); -// Uint8List decodedBytes = base64Decode(encodedBytes); -// Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); -// String dirPath = '${appDocumentsDirectory.path}/chat_images'; -// if (!await Directory(dirPath).exists()) { -// await Directory(dirPath).create(); -// await File('$dirPath/.nomedia').create(); -// } -// late File imageFile = File("$dirPath/$userID.jpg"); -// imageFile.writeAsBytesSync(decodedBytes); -// return imageFile; -// } -// } -// -// Future deleteFile(String userID) async { -// Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); -// String dirPath = '${appDocumentsDirectory.path}/chat_images'; -// late File imageFile = File('$dirPath/$userID.jpg'); -// if (await imageFile.exists()) { -// await imageFile.delete(); -// } -// } -// -// Future downChatMedia(Uint8List bytes, String ext) async { -// String dir = (await getApplicationDocumentsDirectory()).path; -// File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); -// await file.writeAsBytes(bytes); -// return file.path; -// } -// -// void setMsgTune() async { -// JustAudio.AudioPlayer player = JustAudio.AudioPlayer(); -// await player.setVolume(1.0); -// String audioAsset = ""; -// if (Platform.isAndroid) { -// audioAsset = "assets/audio/pulse_tone_android.mp3"; -// } else { -// audioAsset = "assets/audio/pulse_tune_ios.caf"; -// } -// try { -// await player.setAsset(audioAsset); -// await player.load(); -// player.play(); -// } catch (e) { -// print("Error: $e"); -// } -// } -// -// Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { -// Utils.showLoading(context); -// if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { -// Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); -// try { -// String path = await downChatMedia(encodedString, fileTypeName ?? ""); -// Utils.hideLoading(context); -// OpenFilex.open(path); -// } catch (e) { -// Utils.showToast("Cannot open file."); -// } -// } -// } -// -// void onNewChatConversion(List? params) { -// dynamic items = params!.toList(); -// chatUConvCounter = items[0]["singleChatCount"] ?? 0; -// notifyListeners(); -// } -// -// Future invokeChatCounter({required int userId}) async { -// await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); -// return ""; -// } -// -// void userTypingInvoke({required int currentUser, required int reciptUser}) async { -// await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); -// } -// -// void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { -// var data = json.decode(json.encode(groupDetails.groupUserList)); -// await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); -// } -// -// //////// Audio Recoding Work //////////////////// -// -// Future initAudio({required int receiverId}) async { -// // final dir = Directory((Platform.isAndroid -// // ? await getExternalStorageDirectory() //FOR ANDROID -// // : await getApplicationSupportDirectory() //FOR IOS -// // )! -// appDirectory = await getApplicationDocumentsDirectory(); -// String dirPath = '${appDirectory.path}/chat_audios'; -// if (!await Directory(dirPath).exists()) { -// await Directory(dirPath).create(); -// await File('$dirPath/.nomedia').create(); -// } -// path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; -// recorderController = RecorderController() -// ..androidEncoder = AndroidEncoder.aac -// ..androidOutputFormat = AndroidOutputFormat.mpeg4 -// ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC -// ..sampleRate = 6000 -// ..updateFrequency = const Duration(milliseconds: 100) -// ..bitRate = 18000; -// playerController = PlayerController(); -// } -// -// void disposeAudio() { -// isRecoding = false; -// isPlaying = false; -// isPause = false; -// isVoiceMsg = false; -// recorderController.dispose(); -// playerController.dispose(); -// } -// -// void startRecoding(BuildContext context) async { -// await Permission.microphone.request().then((PermissionStatus status) { -// if (status.isPermanentlyDenied) { -// Utils.confirmDialog( -// context, -// "The app needs microphone access to be able to record audio.", -// onTap: () { -// Navigator.of(context).pop(); -// openAppSettings(); -// }, -// ); -// } else if (status.isDenied) { -// Utils.confirmDialog( -// context, -// "The app needs microphone access to be able to record audio.", -// onTap: () { -// Navigator.of(context).pop(); -// openAppSettings(); -// }, -// ); -// } else if (status.isGranted) { -// sRecoding(); -// } else { -// startRecoding(context); -// } -// }); -// } -// -// void sRecoding() async { -// isVoiceMsg = true; -// recorderController.reset(); -// await recorderController.record(path: path); -// _recodeDuration = 0; -// _startTimer(); -// isRecoding = !isRecoding; -// notifyListeners(); -// } -// -// Future _startTimer() async { -// _timer?.cancel(); -// _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { -// _recodeDuration++; -// if (_recodeDuration <= 59) { -// applyCounter(); -// } else { -// pauseRecoding(); -// } -// }); -// } -// -// void applyCounter() { -// buildTimer(); -// notifyListeners(); -// } -// -// Future pauseRecoding() async { -// isPause = true; -// isPlaying = true; -// recorderController.pause(); -// path = await recorderController.stop(false); -// File file = File(path!); -// file.readAsBytesSync(); -// path = file.path; -// await playerController.preparePlayer(path:file.path, volume: 1.0); -// _timer?.cancel(); -// notifyListeners(); -// } -// -// Future deleteRecoding() async { -// _recodeDuration = 0; -// _timer?.cancel(); -// if (path == null) { -// path = await recorderController.stop(true); -// } else { -// await recorderController.stop(true); -// } -// if (path != null && path!.isNotEmpty) { -// File delFile = File(path!); -// double fileSizeInKB = delFile.lengthSync() / 1024; -// double fileSizeInMB = fileSizeInKB / 1024; -// if (kDebugMode) { -// debugPrint("Deleted file size: ${delFile.lengthSync()}"); -// debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); -// debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); -// } -// if (await delFile.exists()) { -// delFile.delete(); -// } -// isPause = false; -// isRecoding = false; -// isPlaying = false; -// isVoiceMsg = false; -// notifyListeners(); -// } -// } -// -// String buildTimer() { -// String minutes = _formatNum(_recodeDuration ~/ 60); -// String seconds = _formatNum(_recodeDuration % 60); -// return '$minutes : $seconds'; -// } -// -// String _formatNum(int number) { -// String numberStr = number.toString(); -// if (number < 10) { -// numberStr = '0' + numberStr; -// } -// return numberStr; -// } -// -// Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { -// File file; -// try { -// String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; -// if (!await Directory(dirPath).exists()) { -// await Directory(dirPath).create(); -// await File('$dirPath/.nomedia').create(); -// } -// file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); -// await file.writeAsBytes(bytes); -// } catch (e) { -// if (kDebugMode) { -// print(e); -// } -// file = File(""); -// } -// return file; -// } -// -// void scrollToMsg(SingleUserChatModel data) { -// if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { -// int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); -// if (index >= 1) { -// double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; -// double target = contentSize * index / userChatHistory.length; -// scrollController.position.animateTo( -// target, -// duration: const Duration(seconds: 1), -// curve: Curves.easeInOut, -// ); -// } -// } -// } -// -// Future getTeamMembers() async { -// teamMembersList = []; -// isLoading = true; -// if (AppState().getemployeeSubordinatesList.isNotEmpty) { -// getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; -// for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { -// if (element.eMPLOYEEEMAILADDRESS != null) { -// if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { -// teamMembersList.add( -// ChatUser( -// id: int.parse(element.eMPLOYEENUMBER!), -// email: element.eMPLOYEEEMAILADDRESS, -// userName: element.eMPLOYEENAME, -// phone: element.eMPLOYEEMOBILENUMBER, -// userStatus: 0, -// unreadMessageCount: 0, -// isFav: false, -// isTyping: false, -// isImageLoading: false, -// image: element.eMPLOYEEIMAGE ?? "", -// isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, -// userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), -// ), -// ); -// } -// } -// } -// } else { -// getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); -// AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; -// for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { -// if (element.eMPLOYEEEMAILADDRESS != null) { -// if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { -// teamMembersList.add( -// ChatUser( -// id: int.parse(element.eMPLOYEENUMBER!), -// email: element.eMPLOYEEEMAILADDRESS, -// userName: element.eMPLOYEENAME, -// phone: element.eMPLOYEEMOBILENUMBER, -// userStatus: 0, -// unreadMessageCount: 0, -// isFav: false, -// isTyping: false, -// isImageLoading: false, -// image: element.eMPLOYEEIMAGE ?? "", -// isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, -// userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), -// ), -// ); -// } -// } -// } -// } -// -// for (ChatUser user in searchedChats!) { -// for (ChatUser teamUser in teamMembersList!) { -// if (user.id == teamUser.id) { -// teamUser.userStatus = user.userStatus; -// } -// } -// } -// -// isLoading = false; -// notifyListeners(); -// } -// -// void inputBoxDirection(String val) { -// if (val.isNotEmpty) { -// isTextMsg = true; -// } else { -// isTextMsg = false; -// } -// msgText = val; -// notifyListeners(); -// } -// -// void onDirectionChange(bool val) { -// isRTL = val; -// notifyListeners(); -// } -// -// Material.TextDirection getTextDirection(String v) { -// String str = v.trim(); -// if (str.isEmpty) return Material.TextDirection.ltr; -// int firstUnit = str.codeUnitAt(0); -// if (firstUnit > 0x0600 && firstUnit < 0x06FF || -// firstUnit > 0x0750 && firstUnit < 0x077F || -// firstUnit > 0x07C0 && firstUnit < 0x07EA || -// firstUnit > 0x0840 && firstUnit < 0x085B || -// firstUnit > 0x08A0 && firstUnit < 0x08B4 || -// firstUnit > 0x08E3 && firstUnit < 0x08FF || -// firstUnit > 0xFB50 && firstUnit < 0xFBB1 || -// firstUnit > 0xFBD3 && firstUnit < 0xFD3D || -// firstUnit > 0xFD50 && firstUnit < 0xFD8F || -// firstUnit > 0xFD92 && firstUnit < 0xFDC7 || -// firstUnit > 0xFDF0 && firstUnit < 0xFDFC || -// firstUnit > 0xFE70 && firstUnit < 0xFE74 || -// firstUnit > 0xFE76 && firstUnit < 0xFEFC || -// firstUnit > 0x10800 && firstUnit < 0x10805 || -// firstUnit > 0x1B000 && firstUnit < 0x1B0FF || -// firstUnit > 0x1D165 && firstUnit < 0x1D169 || -// firstUnit > 0x1D16D && firstUnit < 0x1D172 || -// firstUnit > 0x1D17B && firstUnit < 0x1D182 || -// firstUnit > 0x1D185 && firstUnit < 0x1D18B || -// firstUnit > 0x1D1AA && firstUnit < 0x1D1AD || -// firstUnit > 0x1D242 && firstUnit < 0x1D244) { -// return Material.TextDirection.rtl; -// } -// return Material.TextDirection.ltr; -// } -// -// void openChatByNoti(BuildContext context) async { -// SingleUserChatModel nUser = SingleUserChatModel(); -// Utils.saveStringFromPrefs("isAppOpendByChat", "false"); -// if (await Utils.getStringFromPrefs("notificationData") != "null") { -// nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); -// Utils.saveStringFromPrefs("notificationData", "null"); -// Future.delayed(const Duration(seconds: 2)); -// for (ChatUser user in searchedChats!) { -// if (user.id == nUser.targetUserId) { -// Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); -// return; -// } -// } -// } -// Utils.saveStringFromPrefs("notificationData", "null"); -// } -// -// //group chat functions added here -// -// void filterGroups(String value) async { -// // filter function added here. -// List tmp = []; -// if (value.isEmpty || value == "") { -// tmp = userGroups.groupresponse!; -// } else { -// for (groups.GroupResponse element in uGroups!) { -// if (element.groupName!.toLowerCase().contains(value.toLowerCase())) { -// tmp.add(element); -// } -// } -// } -// uGroups = tmp; -// notifyListeners(); -// } -// -// Future deleteGroup(GroupResponse groupDetails) async { -// isLoading = true; -// await ChatApiClient().deleteGroup(groupDetails.groupId); -// userGroups = await ChatApiClient().getGroupsByUserId(); -// uGroups = userGroups.groupresponse; -// isLoading = false; -// notifyListeners(); -// } -// -// Future getGroupChatHistory(groups.GroupResponse groupDetails) async { -// isLoading = true; -// groupChatHistory = await ChatApiClient().getGroupChatHistory(groupDetails.groupId, groupDetails.groupUserList as List); -// -// isLoading = false; -// -// notifyListeners(); -// } -// -// void updateGroupAdmin(int? groupId, List groupUserList) async { -// isLoading = true; -// await ChatApiClient().updateGroupAdmin(groupId, groupUserList); -// isLoading = false; -// notifyListeners(); -// } -// -// Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { -// isLoading = true; -// var groups = await ChatApiClient().addGroupAndUsers(request); -// userGroups.groupresponse!.add(GroupResponse.fromJson(json.decode(groups)['response'])); -// -// isLoading = false; -// notifyListeners(); -// } -// -// Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { -// isLoading = true; -// await ChatApiClient().updateGroupAndUsers(request); -// userGroups = await ChatApiClient().getGroupsByUserId(); -// uGroups = userGroups.groupresponse; -// isLoading = false; -// notifyListeners(); -// } -// } +import 'package:path_provider/path_provider.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:signalr_netcore/hub_connection.dart'; +import 'package:signalr_netcore/signalr_client.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:uuid/uuid.dart'; +import 'package:flutter/material.dart' as Material; + +import 'model/get_search_user_chat_model.dart'; +import 'get_single_user_chat_list_model.dart'; + +late HubConnection chatHubConnection; + +class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { + ScrollController scrollController = ScrollController(); + + TextEditingController message = TextEditingController(); + TextEditingController search = TextEditingController(); + TextEditingController searchGroup = TextEditingController(); + + List userChatHistory = [], repliedMsg = []; + List? pChatHistory, searchedChats; + String chatCID = ''; + bool isLoading = true; + bool isChatScreenActive = false; + int receiverID = 0; + late File selectedFile; + String sFileType = ""; + + List favUsersList = []; + int paginationVal = 0; + int? cTypingUserId = 0; + bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; + + // Audio Recoding Work + Timer? _timer; + int _recodeDuration = 0; + bool isRecoding = false; + bool isPause = false; + bool isPlaying = false; + String? path; + String? musicFile; + late Directory appDirectory; + late RecorderController recorderController; + late PlayerController playerController; + + // List getEmployeeSubordinatesList = []; + List teamMembersList = []; + + // groups.GetUserGroups userGroups = groups.GetUserGroups(); + Material.TextDirection textDirection = Material.TextDirection.ltr; + bool isRTL = false; + String msgText = ""; + + //Chat Home Page Counter + int chatUConvCounter = 0; + + // late List groupChatHistory, groupChatReplyData; + + /// Search Provider + List? chatUsersList = []; + int pageNo = 1; + + bool disbaleChatForThisUser = false; + + // List? uGroups = [], searchGroups = []; + + Future getUserAutoLoginToken() async { + userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + + if (userLoginResponse.StatusCode == 500) { + disbaleChatForThisUser = true; + notifyListeners(); + } + + if (userLoginResponse.response != null) { + // AppState().setchatUserDetails = userLoginResponse; + } else { + // AppState().setchatUserDetails = userLoginResponse; + userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr".showToast; + disbaleChatForThisUser = true; + notifyListeners(); + } + } + + Future buildHubConnection() async { + chatHubConnection = await getHubConnection(); + await chatHubConnection.start(); + if (kDebugMode) { + // logger.i("Hub Conn: Startedddddddd"); + } + chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); + chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); + + //group On message + + chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived); + } + + Future getHubConnection() async { + HubConnection hub; + HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); + hub = HubConnectionBuilder() + .withUrl(URLs.chatHubUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) + .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); + return hub; + } + + void registerEvents() { + chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); + // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); + + chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); + chatHubConnection.on("OnUserTypingAsync", onUserTyping); + chatHubConnection.on("OnUserCountAsync", userCountAsync); + // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); + chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); + chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); + chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); + + // + // {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]} + + if (kDebugMode) { + logger.i("All listeners registered"); + } + } + + Future getUserRecentChats() async { + ChatUserModel recentChat = await ChatApiClient().getRecentChats(); + ChatUserModel favUList = await ChatApiClient().getFavUsers(); + // userGroups = await ChatApiClient().getGroupsByUserId(); + if (favUList.response != null && recentChat.response != null) { + favUsersList = favUList.response!; + 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) { + user.isFav = favUser.isFav; + } + } + } + } + pChatHistory = recentChat.response ?? []; + uGroups = userGroups.groupresponse ?? []; + 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())); + sort(); + notifyListeners(); + if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { + getUserImages(); + } + } + + Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { + await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); + return ""; + } + + void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { + isLoading = true; + if (isNewChat) userChatHistory = []; + if (!loadMore) paginationVal = 0; + isChatScreenActive = true; + receiverID = receiverUID; + Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); + if (response.statusCode == 204) { + if (isNewChat) { + userChatHistory = []; + } else if (loadMore) {} + } else { + if (loadMore) { + List temp = getSingleUserChatModel(response.body).reversed.toList(); + userChatHistory.addAll(temp); + } else { + userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); + } + } + isLoading = false; + notifyListeners(); + + if (isChatScreenActive && receiverUID == receiverID) { + markRead(userChatHistory, receiverUID); + } + + generateConvId(); + } + + void generateConvId() async { + Uuid uuid = const Uuid(); + chatCID = uuid.v4(); + } + + void markRead(List data, int receiverID) { + for (SingleUserChatModel element in data!) { + if (AppState().chatDetails!.response!.id! == element.targetUserId) { + if (element.isSeen != null) { + if (!element.isSeen!) { + element.isSeen = true; + dynamic data = [ + { + "userChatHistoryId": element.userChatHistoryId, + "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, + "isDelivered": true, + "isSeen": true, + } + ]; + updateUserChatHistoryStatusAsync(data); + notifyListeners(); + } + } + for (ChatUser element in searchedChats!) { + if (element.id == receiverID) { + element.unreadMessageCount = 0; + chatUConvCounter = 0; + } + } + } + } + notifyListeners(); + } + + void updateUserChatHistoryStatusAsync(List data) { + try { + chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + } catch (e) { + throw e; + } + } + + void updateUserChatHistoryOnMsg(List data) { + try { + chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + } catch (e) { + throw e; + } + } + + List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); + + List getGroupChatHistoryAsync(String str) => + List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); + + Future uploadAttachments(String userId, File file, String fileSource) async { + dynamic result; + try { + Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); + if (response != null) { + result = response; + } else { + result = []; + } + } catch (e) { + throw e; + } + return result; + } + + void updateUserChatStatus(List? args) { + dynamic items = args!.toList(); + for (var cItem in items[0]) { + for (SingleUserChatModel chat in userChatHistory) { + if (cItem["contantNo"].toString() == chat.contantNo.toString()) { + chat.isSeen = cItem["isSeen"]; + chat.isDelivered = cItem["isDelivered"]; + } + } + } + notifyListeners(); + } + + void getGroupUserStatus(List? args) { + //note: need to implement this function... + print(args); + } + + void onChatSeen(List? args) { + dynamic items = args!.toList(); + // for (var user in searchedChats!) { + // if (user.id == items.first["id"]) { + // user.userStatus = items.first["userStatus"]; + // } + // } + // notifyListeners(); + } + + void userCountAsync(List? args) { + dynamic items = args!.toList(); + // logger.d(items); + //logger.d("---------------------------------User Count Async -------------------------------------"); + //logger.d(items); + // for (var user in searchedChats!) { + // if (user.id == items.first["id"]) { + // user.userStatus = items.first["userStatus"]; + // } + // } + // notifyListeners(); + } + + void updateChatHistoryWindow(List? args) { + dynamic items = args!.toList(); + if (kDebugMode) { + logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); + } + logger.d(items); + // for (var user in searchedChats!) { + // if (user.id == items.first["id"]) { + // user.userStatus = items.first["userStatus"]; + // } + // } + // notifyListeners(); + } + + void chatNotDelivered(List? args) { + dynamic items = args!.toList(); + for (dynamic item in items[0]) { + for (ChatUser element in searchedChats!) { + if (element.id == item["currentUserId"]) { + int? val = element.unreadMessageCount ?? 0; + element.unreadMessageCount = val! + 1; + } + } + } + notifyListeners(); + } + + void changeStatus(List? args) { + dynamic items = args!.toList(); + for (ChatUser user in searchedChats!) { + 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"]; + } + } + } + + notifyListeners(); + } + + void filter(String value) async { + List? tmp = []; + if (value.isEmpty || value == "") { + tmp = pChatHistory; + } else { + for (ChatUser element in pChatHistory!) { + if (element.userName!.toLowerCase().contains(value.toLowerCase())) { + tmp.add(element); + } + } + } + searchedChats = tmp; + notifyListeners(); + } + + Future onMsgReceived(List? parameters) async { + List data = [], temp = []; + for (dynamic msg in parameters!) { + data = getSingleUserChatModel(jsonEncode(msg)); + temp = getSingleUserChatModel(jsonEncode(msg)); + data.first.targetUserId = temp.first.currentUserId; + data.first.targetUserName = temp.first.currentUserName; + data.first.targetUserEmail = temp.first.currentUserEmail; + data.first.currentUserId = temp.first.targetUserId; + data.first.currentUserName = temp.first.targetUserName; + data.first.currentUserEmail = temp.first.targetUserEmail; + + if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { + data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); + } + if (data.first.userChatReplyResponse != null) { + if (data.first.fileTypeResponse != null) { + if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { + data.first.userChatReplyResponse!.image = await ChatApiClient() + .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); + data.first.userChatReplyResponse!.isImageLoaded = true; + } + } + } + } + + if (searchedChats != null) { + dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); + if (contain.isEmpty) { + List emails = []; + emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + searchedChats!.add( + ChatUser( + id: data.first.currentUserId, + userName: data.first.currentUserName, + email: data.first.currentUserEmail, + unreadMessageCount: 0, + isImageLoading: false, + image: chatImages!.first.profilePicture ?? "", + isImageLoaded: true, + userStatus: 1, + isTyping: false, + userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), + ), + ); + } + } + setMsgTune(); + if (isChatScreenActive && data.first.currentUserId == receiverID) { + userChatHistory.insert(0, data.first); + } else { + if (searchedChats != null) { + for (ChatUser user in searchedChats!) { + if (user.id == data.first.currentUserId) { + int tempCount = user.unreadMessageCount ?? 0; + user.unreadMessageCount = tempCount + 1; + } + } + sort(); + } + } + + List list = [ + { + "userChatHistoryId": data.first.userChatHistoryId, + "TargetUserId": temp.first.targetUserId, + "isDelivered": true, + "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false + } + ]; + updateUserChatHistoryOnMsg(list); + invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + notifyListeners(); + } + + Future onGroupMsgReceived(List? parameters) async { + List data = [], temp = []; + + for (dynamic msg in parameters!) { + // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); + data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); + temp = data; + // data.first.currentUserId = temp.first.currentUserId; + // data.first.currentUserName = temp.first.currentUserName; + // + // data.first.currentUserId = temp.first.currentUserId; + // data.first.currentUserName = temp.first.currentUserName; + + if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { + data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); + } + if (data.first.groupChatReplyResponse != null) { + if (data.first.fileTypeResponse != null) { + if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { + data.first.groupChatReplyResponse!.image = await ChatApiClient() + .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); + data.first.groupChatReplyResponse!.isImageLoaded = true; + } + } + } + } + + // if (searchedChats != null) { + // dynamic contain = searchedChats! + // .where((ChatUser element) => element.id == data.first.currentUserId); + // if (contain.isEmpty) { + // List emails = []; + // emails.add(await EmailImageEncryption() + // .encrypt(val: data.first.currentUserEmail!)); + // List chatImages = + // await ChatApiClient().getUsersImages(encryptedEmails: emails); + // searchedChats!.add( + // ChatUser( + // id: data.first.currentUserId, + // userName: data.first.currentUserName, + // email: data.first.currentUserEmail, + // unreadMessageCount: 0, + // isImageLoading: false, + // image: chatImages!.first.profilePicture ?? "", + // isImageLoaded: true, + // userStatus: 1, + // isTyping: false, + // userLocalDownlaodedImage: await downloadImageLocal( + // chatImages.first.profilePicture, + // data.first.currentUserId.toString()), + // ), + // ); + // } + // } + groupChatHistory.insert(0, data.first); + setMsgTune(); + // if (isChatScreenActive && data.first.currentUserId == receiverID) { + + // } else { + // if (searchedChats != null) { + // for (ChatUser user in searchedChats!) { + // if (user.id == data.first.currentUserId) { + // int tempCount = user.unreadMessageCount ?? 0; + // user.unreadMessageCount = tempCount + 1; + // } + // } + sort(); + //} + //} + // + // List list = [ + // { + // "userChatHistoryId": data.first.groupId, + // "TargetUserId": temp.first.currentUserId, + // "isDelivered": true, + // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID + // ? true + // : false + // } + // ]; + // updateUserChatHistoryOnMsg(list); + // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + notifyListeners(); + } + + void OnSubmitChatAsync(List? parameters) { + print(isChatScreenActive); + print(receiverID); + print(isChatScreenActive); + logger.i(parameters); + List data = [], temp = []; + for (dynamic msg in parameters!) { + data = getSingleUserChatModel(jsonEncode(msg)); + temp = getSingleUserChatModel(jsonEncode(msg)); + data.first.targetUserId = temp.first.currentUserId; + data.first.targetUserName = temp.first.currentUserName; + data.first.targetUserEmail = temp.first.currentUserEmail; + data.first.currentUserId = temp.first.targetUserId; + data.first.currentUserName = temp.first.targetUserName; + data.first.currentUserEmail = temp.first.targetUserEmail; + } + if (isChatScreenActive && data.first.currentUserId == receiverID) { + int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); + logger.d(index); + userChatHistory[index] = data.first; + } + + notifyListeners(); + } + + void sort() { + searchedChats!.sort( + (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), + ); + } + + void onUserTyping(List? parameters) { + for (ChatUser user in searchedChats!) { + if (user.id == parameters![1] && parameters[0] == true) { + user.isTyping = parameters[0] as bool?; + Future.delayed( + const Duration(seconds: 2), + () { + user.isTyping = false; + notifyListeners(); + }, + ); + } + } + notifyListeners(); + } + + int getFileType(String value) { + switch (value) { + case ".pdf": + return 1; + case ".png": + return 3; + case ".txt": + return 5; + case ".jpg": + return 12; + case ".jpeg": + return 4; + case ".xls": + return 7; + case ".xlsx": + return 7; + case ".doc": + return 6; + case ".docx": + return 6; + case ".ppt": + return 8; + case ".pptx": + return 8; + case ".zip": + return 2; + case ".rar": + return 2; + case ".aac": + return 13; + case ".mp3": + return 14; + case ".mp4": + return 16; + case ".mov": + return 16; + case ".avi": + return 16; + case ".flv": + return 16; + + default: + return 0; + } + } + + String getFileTypeDescription(String value) { + switch (value) { + case ".pdf": + return "application/pdf"; + case ".png": + return "image/png"; + case ".txt": + return "text/plain"; + case ".jpg": + return "image/jpg"; + case ".jpeg": + return "image/jpeg"; + case ".ppt": + return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + case ".pptx": + return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + case ".doc": + return "application/vnd.openxmlformats-officedocument.wordprocessingm"; + case ".docx": + return "application/vnd.openxmlformats-officedocument.wordprocessingm"; + case ".xls": + return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + case ".xlsx": + return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + case ".zip": + return "application/octet-stream"; + case ".rar": + return "application/octet-stream"; + case ".aac": + return "audio/aac"; + case ".mp3": + return "audio/mp3"; + case ".mp4": + return "video/mp4"; + case ".avi": + return "video/avi"; + case ".flv": + return "video/flv"; + case ".mov": + return "video/mov"; + + default: + return ""; + } + } + + Future sendChatToServer( + {required int chatEventId, + required fileTypeId, + required int targetUserId, + required String targetUserName, + required chatReplyId, + required bool isAttachment, + required bool isReply, + Uint8List? image, + required bool isImageLoaded, + String? userEmail, + int? userStatus, + File? voiceFile, + required bool isVoiceAttached}) async { + Uuid uuid = const Uuid(); + String contentNo = uuid.v4(); + String msg; + if (isVoiceAttached) { + msg = voiceFile!.path.split("/").last; + } else { + msg = message.text; + logger.w(msg); + } + SingleUserChatModel data = SingleUserChatModel( + userChatHistoryId: 0, + chatEventId: chatEventId, + chatSource: 1, + contant: msg, + contantNo: contentNo, + conversationId: chatCID, + createdDate: DateTime.now(), + currentUserId: AppState().chatDetails!.response!.id, + currentUserName: AppState().chatDetails!.response!.userName, + targetUserId: targetUserId, + targetUserName: targetUserName, + isReplied: false, + fileTypeId: fileTypeId, + userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, + fileTypeResponse: isAttachment + ? FileTypeResponse( + fileTypeId: fileTypeId, + fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), + fileKind: "file", + fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, + fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), + ) + : null, + image: image, + isImageLoaded: isImageLoaded, + voice: isVoiceMsg ? voiceFile! : null, + voiceController: isVoiceMsg ? AudioPlayer() : null); + if (kDebugMode) { + logger.i("model data: " + jsonEncode(data)); + } + userChatHistory.insert(0, data); + isTextMsg = false; + isReplyMsg = false; + isAttachmentMsg = false; + isVoiceMsg = false; + sFileType = ""; + message.clear(); + notifyListeners(); + + String chatData = + '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; + + await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); + } + + //groupChatMessage + + Future sendGroupChatToServer( + {required int chatEventId, + required fileTypeId, + required int targetGroupId, + required String targetUserName, + required chatReplyId, + required bool isAttachment, + required bool isReply, + Uint8List? image, + required bool isImageLoaded, + String? userEmail, + int? userStatus, + File? voiceFile, + required bool isVoiceAttached, + required List userList}) async { + Uuid uuid = const Uuid(); + String contentNo = uuid.v4(); + String msg; + if (isVoiceAttached) { + msg = voiceFile!.path.split("/").last; + } else { + msg = message.text; + logger.w(msg); + } + groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( + //userChatHistoryId: 0, + chatEventId: chatEventId, + chatSource: 1, + contant: msg, + contantNo: contentNo, + conversationId: chatCID, + createdDate: DateTime.now().toString(), + currentUserId: AppState().chatDetails!.response!.id, + currentUserName: AppState().chatDetails!.response!.userName, + groupId: targetGroupId, + groupName: targetUserName, + isReplied: false, + fileTypeId: fileTypeId, + fileTypeResponse: isAttachment + ? groupchathistory.FileTypeResponse( + fileTypeId: fileTypeId, + fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), + fileKind: "file", + fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, + fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) + : null, + image: image, + isImageLoaded: isImageLoaded, + voice: isVoiceMsg ? voiceFile! : null, + voiceController: isVoiceMsg ? AudioPlayer() : null); + if (kDebugMode) { + logger.i("model data: " + jsonEncode(data)); + } + groupChatHistory.insert(0, data); + isTextMsg = false; + isReplyMsg = false; + isAttachmentMsg = false; + isVoiceMsg = false; + sFileType = ""; + message.clear(); + notifyListeners(); + + List targetUsers = []; + + for (GroupUserList element in userList) { + targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); + } + + String chatData = + '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; + + await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); + } + + void sendGroupChatMessage( + BuildContext context, { + required int targetUserId, + required int userStatus, + required String userEmail, + required String targetUserName, + required List userList, + }) async { + if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Text Message"); + if (message.text.isEmpty) { + return; + } + sendGroupChatToServer( + chatEventId: 1, + fileTypeId: null, + targetGroupId: targetUserId, + targetUserName: targetUserName, + isAttachment: false, + chatReplyId: null, + isReply: false, + isImageLoaded: false, + image: null, + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus, + userList: userList); + } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + logger.d("// Text Message as Reply"); + if (message.text.isEmpty) { + return; + } + sendGroupChatToServer( + chatEventId: 1, + fileTypeId: null, + targetGroupId: targetUserId, + targetUserName: targetUserName, + chatReplyId: groupChatReplyData.first.groupChatHistoryId, + isAttachment: false, + isReply: true, + isImageLoaded: groupChatReplyData.first.isImageLoaded!, + image: groupChatReplyData.first.image, + isVoiceAttached: false, + voiceFile: null, + userEmail: userEmail, + userStatus: userStatus, + userList: userList); + } + // Attachment + else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Image Message"); + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); + String? ext = getFileExtension(selectedFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetGroupId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: null, + isReply: false, + isImageLoaded: true, + image: selectedFile.readAsBytesSync(), + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus, + userList: userList); + } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + logger.d("// Image as Reply Msg"); + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); + String? ext = getFileExtension(selectedFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetGroupId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: repliedMsg.first.userChatHistoryId, + isReply: true, + isImageLoaded: true, + image: selectedFile.readAsBytesSync(), + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus, + userList: userList); + } + //Voice + + else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Voice Message"); + + if (!isPause) { + path = await recorderController.stop(false); + } + if (kDebugMode) { + logger.i("path:" + path!); + } + File voiceFile = File(path!); + voiceFile.readAsBytesSync(); + _timer?.cancel(); + isPause = false; + isPlaying = false; + isRecoding = false; + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); + String? ext = getFileExtension(voiceFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + //, + targetGroupId: targetUserId, + targetUserName: targetUserName, + chatReplyId: null, + isAttachment: true, + isReply: isReplyMsg, + isImageLoaded: false, + voiceFile: voiceFile, + isVoiceAttached: true, + userEmail: userEmail, + userStatus: userStatus, + userList: userList); + notifyListeners(); + } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { + logger.d("// Voice as Reply Msg"); + + if (!isPause) { + path = await recorderController.stop(false); + } + if (kDebugMode) { + logger.i("path:" + path!); + } + File voiceFile = File(path!); + voiceFile.readAsBytesSync(); + _timer?.cancel(); + isPause = false; + isPlaying = false; + isRecoding = false; + + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); + String? ext = getFileExtension(voiceFile.path); + Utils.hideLoading(context); + sendGroupChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetGroupId: targetUserId, + targetUserName: targetUserName, + chatReplyId: null, + isAttachment: true, + isReply: isReplyMsg, + isImageLoaded: false, + voiceFile: voiceFile, + isVoiceAttached: true, + userEmail: userEmail, + userStatus: userStatus, + userList: userList); + notifyListeners(); + } + if (searchedChats != null) { + dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); + if (contain.isEmpty) { + List emails = []; + emails.add(await EmailImageEncryption().encrypt(val: userEmail)); + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + searchedChats!.add( + ChatUser( + id: targetUserId, + userName: targetUserName, + unreadMessageCount: 0, + email: userEmail, + isImageLoading: false, + image: chatImages.first.profilePicture ?? "", + isImageLoaded: true, + isTyping: false, + isFav: false, + userStatus: userStatus, + // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + ), + ); + notifyListeners(); + } + } + } + + void sendChatMessage( + BuildContext context, { + required int targetUserId, + required int userStatus, + required String userEmail, + required String targetUserName, + }) async { + if (kDebugMode) { + print("====================== Values ============================"); + print("Is Text " + isTextMsg.toString()); + print("isReply " + isReplyMsg.toString()); + print("isAttachment " + isAttachmentMsg.toString()); + print("isVoice " + isVoiceMsg.toString()); + } + //Text + if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Text Message"); + if (message.text.isEmpty) { + return; + } + sendChatToServer( + chatEventId: 1, + fileTypeId: null, + targetUserId: targetUserId, + targetUserName: targetUserName, + isAttachment: false, + chatReplyId: null, + isReply: false, + isImageLoaded: false, + image: null, + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus); + } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + logger.d("// Text Message as Reply"); + if (message.text.isEmpty) { + return; + } + sendChatToServer( + chatEventId: 1, + fileTypeId: null, + targetUserId: targetUserId, + targetUserName: targetUserName, + chatReplyId: repliedMsg.first.userChatHistoryId, + isAttachment: false, + isReply: true, + isImageLoaded: repliedMsg.first.isImageLoaded!, + image: repliedMsg.first.image, + isVoiceAttached: false, + voiceFile: null, + userEmail: userEmail, + userStatus: userStatus); + } + // Attachment + else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Image Message"); + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); + String? ext = getFileExtension(selectedFile.path); + Utils.hideLoading(context); + sendChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetUserId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: null, + isReply: false, + isImageLoaded: true, + image: selectedFile.readAsBytesSync(), + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus); + } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + logger.d("// Image as Reply Msg"); + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); + String? ext = getFileExtension(selectedFile.path); + Utils.hideLoading(context); + sendChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetUserId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: repliedMsg.first.userChatHistoryId, + isReply: true, + isImageLoaded: true, + image: selectedFile.readAsBytesSync(), + isVoiceAttached: false, + userEmail: userEmail, + userStatus: userStatus); + } + //Voice + + else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { + logger.d("// Normal Voice Message"); + + if (!isPause) { + path = await recorderController.stop(false); + } + if (kDebugMode) { + logger.i("path:" + path!); + } + File voiceFile = File(path!); + voiceFile.readAsBytesSync(); + _timer?.cancel(); + isPause = false; + isPlaying = false; + isRecoding = false; + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); + String? ext = getFileExtension(voiceFile.path); + Utils.hideLoading(context); + sendChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetUserId: targetUserId, + targetUserName: targetUserName, + chatReplyId: null, + isAttachment: true, + isReply: isReplyMsg, + isImageLoaded: false, + voiceFile: voiceFile, + isVoiceAttached: true, + userEmail: userEmail, + userStatus: userStatus); + notifyListeners(); + } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { + logger.d("// Voice as Reply Msg"); + + if (!isPause) { + path = await recorderController.stop(false); + } + if (kDebugMode) { + logger.i("path:" + path!); + } + File voiceFile = File(path!); + voiceFile.readAsBytesSync(); + _timer?.cancel(); + isPause = false; + isPlaying = false; + isRecoding = false; + + Utils.showLoading(context); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); + String? ext = getFileExtension(voiceFile.path); + Utils.hideLoading(context); + sendChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetUserId: targetUserId, + targetUserName: targetUserName, + chatReplyId: null, + isAttachment: true, + isReply: isReplyMsg, + isImageLoaded: false, + voiceFile: voiceFile, + isVoiceAttached: true, + userEmail: userEmail, + userStatus: userStatus); + notifyListeners(); + } + if (searchedChats != null) { + dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); + if (contain.isEmpty) { + List emails = []; + emails.add(await EmailImageEncryption().encrypt(val: userEmail)); + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + searchedChats!.add( + ChatUser( + id: targetUserId, + userName: targetUserName, + unreadMessageCount: 0, + email: userEmail, + isImageLoading: false, + image: chatImages.first.profilePicture ?? "", + isImageLoaded: true, + isTyping: false, + isFav: false, + userStatus: userStatus, + userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + ), + ); + notifyListeners(); + } + } + // else { + // List emails = []; + // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); + // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + // searchedChats!.add( + // ChatUser( + // id: targetUserId, + // userName: targetUserName, + // unreadMessageCount: 0, + // email: userEmail, + // isImageLoading: false, + // image: chatImages.first.profilePicture ?? "", + // isImageLoaded: true, + // isTyping: false, + // isFav: false, + // userStatus: userStatus, + // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + // ), + // ); + // notifyListeners(); + // } + } + + void selectImageToUpload(BuildContext context) { + ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { + if (checkFileSize(file.path)) { + selectedFile = file; + isAttachmentMsg = true; + isTextMsg = false; + sFileType = getFileExtension(file.path)!; + message.text = file.path.split("/").last; + Navigator.of(context).pop(); + } else { + Utils.showToast("Max 1 mb size is allowed to upload"); + } + notifyListeners(); + }); + } + + void removeAttachment() { + isAttachmentMsg = false; + sFileType = ""; + message.text = ''; + notifyListeners(); + } + + String? getFileExtension(String fileName) { + try { + if (kDebugMode) { + logger.i("ext: " + "." + fileName.split('.').last); + } + return "." + fileName.split('.').last; + } catch (e) { + return null; + } + } + + bool checkFileSize(String path) { + int fileSizeLimit = 5120; + File f = File(path); + double fileSizeInKB = f.lengthSync() / 5000; + double fileSizeInMB = fileSizeInKB / 5000; + if (fileSizeInKB > fileSizeLimit) { + return false; + } else { + return true; + } + } + + String getType(String type) { + switch (type) { + case ".pdf": + return "assets/images/pdf.svg"; + case ".png": + return "assets/images/png.svg"; + case ".txt": + return "assets/icons/chat/txt.svg"; + case ".jpg": + return "assets/images/jpg.svg"; + case ".jpeg": + return "assets/images/jpg.svg"; + case ".xls": + return "assets/icons/chat/xls.svg"; + case ".xlsx": + return "assets/icons/chat/xls.svg"; + case ".doc": + return "assets/icons/chat/doc.svg"; + case ".docx": + return "assets/icons/chat/doc.svg"; + case ".ppt": + return "assets/icons/chat/ppt.svg"; + case ".pptx": + return "assets/icons/chat/ppt.svg"; + case ".zip": + return "assets/icons/chat/zip.svg"; + case ".rar": + return "assets/icons/chat/zip.svg"; + case ".aac": + return "assets/icons/chat/aac.svg"; + case ".mp3": + return "assets/icons/chat/zip.mp3"; + default: + return "assets/images/thumb.svg"; + } + } + + void chatReply(SingleUserChatModel data) { + repliedMsg = []; + data.isReplied = true; + isReplyMsg = true; + repliedMsg.add(data); + notifyListeners(); + } + + void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { + groupChatReplyData = []; + data.isReplied = true; + isReplyMsg = true; + groupChatReplyData.add(data); + notifyListeners(); + } + + void closeMe() { + repliedMsg = []; + isReplyMsg = false; + notifyListeners(); + } + + String dateFormte(DateTime data) { + DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); + f.format(data); + return f.format(data); + } + + Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { + fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); + if (favoriteChatUser.response != null) { + for (ChatUser user in searchedChats!) { + if (user.id == favoriteChatUser.response!.targetUserId!) { + user.isFav = favoriteChatUser.response!.isFav; + dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); + if (contain.isEmpty) { + favUsersList.add(user); + } + } + } + + for (ChatUser user in chatUsersList!) { + if (user.id == favoriteChatUser.response!.targetUserId!) { + user.isFav = favoriteChatUser.response!.isFav; + dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); + if (contain.isEmpty) { + favUsersList.add(user); + } + } + } + } + if (fromSearch) { + for (ChatUser user in favUsersList) { + if (user.id == targetUserID) { + user.userLocalDownlaodedImage = null; + user.isImageLoading = false; + user.isImageLoaded = false; + } + } + } + notifyListeners(); + } + + Future unFavoriteUser({required int userID, required int targetUserID}) async { + fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); + + if (favoriteChatUser.response != null) { + for (ChatUser user in searchedChats!) { + if (user.id == favoriteChatUser.response!.targetUserId!) { + user.isFav = favoriteChatUser.response!.isFav; + } + } + favUsersList.removeWhere( + (ChatUser element) => element.id == targetUserID, + ); + } + + for (ChatUser user in chatUsersList!) { + if (user.id == favoriteChatUser.response!.targetUserId!) { + user.isFav = favoriteChatUser.response!.isFav; + } + } + + notifyListeners(); + } + + void clearSelections() { + searchedChats = pChatHistory; + search.clear(); + isChatScreenActive = false; + receiverID = 0; + paginationVal = 0; + message.text = ''; + isAttachmentMsg = false; + repliedMsg = []; + sFileType = ""; + isReplyMsg = false; + isTextMsg = false; + isVoiceMsg = false; + notifyListeners(); + } + + void clearAll() { + searchedChats = pChatHistory; + search.clear(); + isChatScreenActive = false; + receiverID = 0; + paginationVal = 0; + message.text = ''; + isTextMsg = false; + isAttachmentMsg = false; + isVoiceMsg = false; + isReplyMsg = false; + repliedMsg = []; + sFileType = ""; + } + + void disposeData() { + if (!disbaleChatForThisUser) { + search.clear(); + isChatScreenActive = false; + receiverID = 0; + paginationVal = 0; + message.text = ''; + isTextMsg = false; + isAttachmentMsg = false; + isVoiceMsg = false; + isReplyMsg = false; + repliedMsg = []; + sFileType = ""; + deleteData(); + favUsersList.clear(); + searchedChats?.clear(); + pChatHistory?.clear(); + uGroups?.clear(); + searchGroup?.clear(); + chatHubConnection.stop(); + AppState().chatDetails = null; + } + } + + void deleteData() { + List exists = [], unique = []; + if (searchedChats != null) exists.addAll(searchedChats!); + exists.addAll(favUsersList!); + Map profileMap = {}; + for (ChatUser item in exists) { + profileMap[item.email!] = item; + } + unique = profileMap.values.toList(); + for (ChatUser element in unique!) { + deleteFile(element.id.toString()); + } + } + + void getUserImages() async { + List emails = []; + List exists = [], unique = []; + exists.addAll(searchedChats!); + exists.addAll(favUsersList!); + Map profileMap = {}; + for (ChatUser item in exists) { + profileMap[item.email!] = item; + } + unique = profileMap.values.toList(); + for (ChatUser element in unique!) { + emails.add(await EmailImageEncryption().encrypt(val: element.email!)); + } + + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + for (ChatUser user in searchedChats!) { + for (ChatUserImageModel uImage in chatImages) { + if (user.email == uImage.email) { + user.image = uImage.profilePicture ?? ""; + user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); + user.isImageLoading = false; + user.isImageLoaded = true; + } + } + } + for (ChatUser favUser in favUsersList) { + for (ChatUserImageModel uImage in chatImages) { + if (favUser.email == uImage.email) { + favUser.image = uImage.profilePicture ?? ""; + favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); + favUser.isImageLoading = false; + favUser.isImageLoaded = true; + } + } + } + + notifyListeners(); + } + + Future downloadImageLocal(String? encodedBytes, String userID) async { + File? myfile; + if (encodedBytes == null) { + return myfile; + } else { + await deleteFile(userID); + Uint8List decodedBytes = base64Decode(encodedBytes); + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); + String dirPath = '${appDocumentsDirectory.path}/chat_images'; + if (!await Directory(dirPath).exists()) { + await Directory(dirPath).create(); + await File('$dirPath/.nomedia').create(); + } + late File imageFile = File("$dirPath/$userID.jpg"); + imageFile.writeAsBytesSync(decodedBytes); + return imageFile; + } + } + + Future deleteFile(String userID) async { + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); + String dirPath = '${appDocumentsDirectory.path}/chat_images'; + late File imageFile = File('$dirPath/$userID.jpg'); + if (await imageFile.exists()) { + await imageFile.delete(); + } + } + + Future downChatMedia(Uint8List bytes, String ext) async { + String dir = (await getApplicationDocumentsDirectory()).path; + File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + await file.writeAsBytes(bytes); + return file.path; + } + + void setMsgTune() async { + JustAudio.AudioPlayer player = JustAudio.AudioPlayer(); + await player.setVolume(1.0); + String audioAsset = ""; + if (Platform.isAndroid) { + audioAsset = "assets/audio/pulse_tone_android.mp3"; + } else { + audioAsset = "assets/audio/pulse_tune_ios.caf"; + } + try { + await player.setAsset(audioAsset); + await player.load(); + player.play(); + } catch (e) { + print("Error: $e"); + } + } + + Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { + Utils.showLoading(context); + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { + Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); + try { + String path = await downChatMedia(encodedString, fileTypeName ?? ""); + Utils.hideLoading(context); + OpenFilex.open(path); + } catch (e) { + Utils.showToast("Cannot open file."); + } + } + } + + void onNewChatConversion(List? params) { + dynamic items = params!.toList(); + chatUConvCounter = items[0]["singleChatCount"] ?? 0; + notifyListeners(); + } + + Future invokeChatCounter({required int userId}) async { + await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); + return ""; + } + + void userTypingInvoke({required int currentUser, required int reciptUser}) async { + await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); + } + + void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { + var data = json.decode(json.encode(groupDetails.groupUserList)); + await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); + } + +//////// Audio Recoding Work //////////////////// + + Future initAudio({required int receiverId}) async { + // final dir = Directory((Platform.isAndroid + // ? await getExternalStorageDirectory() //FOR ANDROID + // : await getApplicationSupportDirectory() //FOR IOS + // )! + appDirectory = await getApplicationDocumentsDirectory(); + String dirPath = '${appDirectory.path}/chat_audios'; + if (!await Directory(dirPath).exists()) { + await Directory(dirPath).create(); + await File('$dirPath/.nomedia').create(); + } + path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; + recorderController = RecorderController() + ..androidEncoder = AndroidEncoder.aac + ..androidOutputFormat = AndroidOutputFormat.mpeg4 + ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC + ..sampleRate = 6000 + ..updateFrequency = const Duration(milliseconds: 100) + ..bitRate = 18000; + playerController = PlayerController(); + } + + void disposeAudio() { + isRecoding = false; + isPlaying = false; + isPause = false; + isVoiceMsg = false; + recorderController.dispose(); + playerController.dispose(); + } + + void startRecoding(BuildContext context) async { + await Permission.microphone.request().then((PermissionStatus status) { + if (status.isPermanentlyDenied) { + Utils.confirmDialog( + context, + "The app needs microphone access to be able to record audio.", + onTap: () { + Navigator.of(context).pop(); + openAppSettings(); + }, + ); + } else if (status.isDenied) { + Utils.confirmDialog( + context, + "The app needs microphone access to be able to record audio.", + onTap: () { + Navigator.of(context).pop(); + openAppSettings(); + }, + ); + } else if (status.isGranted) { + sRecoding(); + } else { + startRecoding(context); + } + }); + } + + void sRecoding() async { + isVoiceMsg = true; + recorderController.reset(); + await recorderController.record(path: path); + _recodeDuration = 0; + _startTimer(); + isRecoding = !isRecoding; + notifyListeners(); + } + + Future _startTimer() async { + _timer?.cancel(); + _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { + _recodeDuration++; + if (_recodeDuration <= 59) { + applyCounter(); + } else { + pauseRecoding(); + } + }); + } + + void applyCounter() { + buildTimer(); + notifyListeners(); + } + + Future pauseRecoding() async { + isPause = true; + isPlaying = true; + recorderController.pause(); + path = await recorderController.stop(false); + File file = File(path!); + file.readAsBytesSync(); + path = file.path; + await playerController.preparePlayer(path: file.path, volume: 1.0); + _timer?.cancel(); + notifyListeners(); + } + + Future deleteRecoding() async { + _recodeDuration = 0; + _timer?.cancel(); + if (path == null) { + path = await recorderController.stop(true); + } else { + await recorderController.stop(true); + } + if (path != null && path!.isNotEmpty) { + File delFile = File(path!); + double fileSizeInKB = delFile.lengthSync() / 1024; + double fileSizeInMB = fileSizeInKB / 1024; + if (kDebugMode) { + debugPrint("Deleted file size: ${delFile.lengthSync()}"); + debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); + debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); + } + if (await delFile.exists()) { + delFile.delete(); + } + isPause = false; + isRecoding = false; + isPlaying = false; + isVoiceMsg = false; + notifyListeners(); + } + } + + String buildTimer() { + String minutes = _formatNum(_recodeDuration ~/ 60); + String seconds = _formatNum(_recodeDuration % 60); + return '$minutes : $seconds'; + } + + String _formatNum(int number) { + String numberStr = number.toString(); + if (number < 10) { + numberStr = '0' + numberStr; + } + return numberStr; + } + + Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { + File file; + try { + String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; + if (!await Directory(dirPath).exists()) { + await Directory(dirPath).create(); + await File('$dirPath/.nomedia').create(); + } + file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); + await file.writeAsBytes(bytes); + } catch (e) { + if (kDebugMode) { + print(e); + } + file = File(""); + } + return file; + } + + void scrollToMsg(SingleUserChatModel data) { + if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { + int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); + if (index >= 1) { + double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; + double target = contentSize * index / userChatHistory.length; + scrollController.position.animateTo( + target, + duration: const Duration(seconds: 1), + curve: Curves.easeInOut, + ); + } + } + } + + Future getTeamMembers() async { + teamMembersList = []; + isLoading = true; + if (AppState().getemployeeSubordinatesList.isNotEmpty) { + getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; + for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { + if (element.eMPLOYEEEMAILADDRESS != null) { + if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { + teamMembersList.add( + ChatUser( + id: int.parse(element.eMPLOYEENUMBER!), + email: element.eMPLOYEEEMAILADDRESS, + userName: element.eMPLOYEENAME, + phone: element.eMPLOYEEMOBILENUMBER, + userStatus: 0, + unreadMessageCount: 0, + isFav: false, + isTyping: false, + isImageLoading: false, + image: element.eMPLOYEEIMAGE ?? "", + isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, + userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + ), + ); + } + } + } + } else { + getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); + AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; + for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { + if (element.eMPLOYEEEMAILADDRESS != null) { + if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { + teamMembersList.add( + ChatUser( + id: int.parse(element.eMPLOYEENUMBER!), + email: element.eMPLOYEEEMAILADDRESS, + userName: element.eMPLOYEENAME, + phone: element.eMPLOYEEMOBILENUMBER, + userStatus: 0, + unreadMessageCount: 0, + isFav: false, + isTyping: false, + isImageLoading: false, + image: element.eMPLOYEEIMAGE ?? "", + isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, + userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + ), + ); + } + } + } + } + + for (ChatUser user in searchedChats!) { + for (ChatUser teamUser in teamMembersList!) { + if (user.id == teamUser.id) { + teamUser.userStatus = user.userStatus; + } + } + } + + isLoading = false; + notifyListeners(); + } + + void inputBoxDirection(String val) { + if (val.isNotEmpty) { + isTextMsg = true; + } else { + isTextMsg = false; + } + msgText = val; + notifyListeners(); + } + + void onDirectionChange(bool val) { + isRTL = val; + notifyListeners(); + } + + Material.TextDirection getTextDirection(String v) { + String str = v.trim(); + if (str.isEmpty) return Material.TextDirection.ltr; + int firstUnit = str.codeUnitAt(0); + if (firstUnit > 0x0600 && firstUnit < 0x06FF || + firstUnit > 0x0750 && firstUnit < 0x077F || + firstUnit > 0x07C0 && firstUnit < 0x07EA || + firstUnit > 0x0840 && firstUnit < 0x085B || + firstUnit > 0x08A0 && firstUnit < 0x08B4 || + firstUnit > 0x08E3 && firstUnit < 0x08FF || + firstUnit > 0xFB50 && firstUnit < 0xFBB1 || + firstUnit > 0xFBD3 && firstUnit < 0xFD3D || + firstUnit > 0xFD50 && firstUnit < 0xFD8F || + firstUnit > 0xFD92 && firstUnit < 0xFDC7 || + firstUnit > 0xFDF0 && firstUnit < 0xFDFC || + firstUnit > 0xFE70 && firstUnit < 0xFE74 || + firstUnit > 0xFE76 && firstUnit < 0xFEFC || + firstUnit > 0x10800 && firstUnit < 0x10805 || + firstUnit > 0x1B000 && firstUnit < 0x1B0FF || + firstUnit > 0x1D165 && firstUnit < 0x1D169 || + firstUnit > 0x1D16D && firstUnit < 0x1D172 || + firstUnit > 0x1D17B && firstUnit < 0x1D182 || + firstUnit > 0x1D185 && firstUnit < 0x1D18B || + firstUnit > 0x1D1AA && firstUnit < 0x1D1AD || + firstUnit > 0x1D242 && firstUnit < 0x1D244) { + return Material.TextDirection.rtl; + } + return Material.TextDirection.ltr; + } + + void openChatByNoti(BuildContext context) async { + SingleUserChatModel nUser = SingleUserChatModel(); + Utils.saveStringFromPrefs("isAppOpendByChat", "false"); + if (await Utils.getStringFromPrefs("notificationData") != "null") { + nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); + Utils.saveStringFromPrefs("notificationData", "null"); + Future.delayed(const Duration(seconds: 2)); + for (ChatUser user in searchedChats!) { + if (user.id == nUser.targetUserId) { + Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); + return; + } + } + } + Utils.saveStringFromPrefs("notificationData", "null"); + } + + //group chat functions added here + + void filterGroups(String value) async { + // filter function added here. + List tmp = []; + if (value.isEmpty || value == "") { + tmp = userGroups.groupresponse!; + } else { + for (groups.GroupResponse element in uGroups!) { + if (element.groupName!.toLowerCase().contains(value.toLowerCase())) { + tmp.add(element); + } + } + } + uGroups = tmp; + notifyListeners(); + } + + Future deleteGroup(GroupResponse groupDetails) async { + isLoading = true; + await ChatApiClient().deleteGroup(groupDetails.groupId); + userGroups = await ChatApiClient().getGroupsByUserId(); + uGroups = userGroups.groupresponse; + isLoading = false; + notifyListeners(); + } + + Future getGroupChatHistory(groups.GroupResponse groupDetails) async { + isLoading = true; + groupChatHistory = await ChatApiClient().getGroupChatHistory(groupDetails.groupId, groupDetails.groupUserList as List); + + isLoading = false; + + notifyListeners(); + } + + void updateGroupAdmin(int? groupId, List groupUserList) async { + isLoading = true; + await ChatApiClient().updateGroupAdmin(groupId, groupUserList); + isLoading = false; + notifyListeners(); + } + + Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { + isLoading = true; + var groups = await ChatApiClient().addGroupAndUsers(request); + userGroups.groupresponse!.add(GroupResponse.fromJson(json.decode(groups)['response'])); + + isLoading = false; + notifyListeners(); + } + + Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { + isLoading = true; + await ChatApiClient().updateGroupAndUsers(request); + userGroups = await ChatApiClient().getGroupsByUserId(); + uGroups = userGroups.groupresponse; + isLoading = false; + notifyListeners(); + } +} diff --git a/lib/modules/cx_module/chat/model/get_search_user_chat_model.dart b/lib/modules/cx_module/chat/model/get_search_user_chat_model.dart new file mode 100644 index 00000000..7c638e9e --- /dev/null +++ b/lib/modules/cx_module/chat/model/get_search_user_chat_model.dart @@ -0,0 +1,137 @@ +import 'dart:convert'; +import 'dart:io'; + +ChatUserModel chatUserModelFromJson(String str) => ChatUserModel.fromJson(json.decode(str)); + +String chatUserModelToJson(ChatUserModel data) => json.encode(data.toJson()); + +class ChatUserModel { + ChatUserModel({ + this.response, + this.errorResponses, + }); + + List? response; + List? errorResponses; + + factory ChatUserModel.fromJson(Map json) => ChatUserModel( + response: json["response"] == null ? null : List.from(json["response"].map((x) => ChatUser.fromJson(x))), + errorResponses: json["errorResponses"] == null ? null : List.from(json["errorResponses"].map((x) => ErrorResponse.fromJson(x))), + ); + + Map toJson() => { + "response": response == null ? null : List.from(response!.map((x) => x.toJson())), + "errorResponses": errorResponses == null ? null : List.from(errorResponses!.map((x) => x.toJson())), + }; +} + +class ErrorResponse { + ErrorResponse({ + this.fieldName, + this.message, + }); + + dynamic? fieldName; + String? message; + + factory ErrorResponse.fromRawJson(String str) => ErrorResponse.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ErrorResponse.fromJson(Map json) => ErrorResponse( + fieldName: json["fieldName"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "fieldName": fieldName, + "message": message == null ? null : message, + }; +} + +class ChatUser { + ChatUser({ + this.id, + this.userName, + this.email, + this.phone, + this.title, + this.userStatus, + this.image, + this.unreadMessageCount, + this.userAction, + this.isPin, + this.isFav, + this.isAdmin, + this.rKey, + this.totalCount, + this.isTyping, + this.isImageLoaded, + this.isImageLoading, + this.userLocalDownlaodedImage, + this.isChecked + }); + + int? id; + String? userName; + String? email; + dynamic? phone; + String? title; + int? userStatus; + dynamic? image; + int? unreadMessageCount; + dynamic? userAction; + bool? isPin; + bool? isFav; + bool? isAdmin; + dynamic? rKey; + int? totalCount; + bool? isTyping; + bool? isImageLoaded; + bool? isImageLoading; + File? userLocalDownlaodedImage; + bool? isChecked; + factory ChatUser.fromRawJson(String str) => ChatUser.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ChatUser.fromJson(Map json) => ChatUser( + id: json["id"] == null ? null : json["id"], + userName: json["userName"] == null ? null : json["userName"], + email: json["email"] == null ? null : json["email"], + phone: json["phone"], + title: json["title"] == null ? null : json["title"], + userStatus: json["userStatus"] == null ? null : json["userStatus"], + image: json["image"], + unreadMessageCount: json["unreadMessageCount"] == null ? null : json["unreadMessageCount"], + userAction: json["userAction"], + isPin: json["isPin"] == null ? null : json["isPin"], + isFav: json["isFav"] == null ? null : json["isFav"], + isAdmin: json["isAdmin"] == null ? null : json["isAdmin"], + rKey: json["rKey"], + totalCount: json["totalCount"] == null ? null : json["totalCount"], + isTyping: false, + isImageLoaded: false, + isImageLoading: true, + userLocalDownlaodedImage: null, + isChecked: false + ); + + Map toJson() => { + "id": id == null ? null : id, + "userName": userName == null ? null : userName, + "email": email == null ? null : email, + "phone": phone, + "title": title == null ? null : title, + "userStatus": userStatus == null ? null : userStatus, + "image": image, + "unreadMessageCount": unreadMessageCount == null ? null : unreadMessageCount, + "userAction": userAction, + "isPin": isPin == null ? null : isPin, + "isFav": isFav == null ? null : isFav, + "isAdmin": isAdmin == null ? null : isAdmin, + "rKey": rKey, + "totalCount": totalCount == null ? null : totalCount, + "isChecked":isChecked + }; +} diff --git a/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart b/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart new file mode 100644 index 00000000..3722c093 --- /dev/null +++ b/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart @@ -0,0 +1,206 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; +import 'package:just_audio/just_audio.dart'; + +List singleUserChatModelFromJson(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); + +String singleUserChatModelToJson(List data) => json.encode(List.from(data.map((x) => x.toJson()))); + +class SingleUserChatModel { + SingleUserChatModel( + {this.userChatHistoryId, + this.userChatHistoryLineId, + this.contant, + this.contantNo, + this.currentUserId, + this.currentUserName, + this.targetUserId, + this.targetUserName, + this.encryptedTargetUserId, + this.encryptedTargetUserName, + this.currentUserEmail, + this.targetUserEmail, + this.chatEventId, + this.fileTypeId, + this.isSeen, + this.isDelivered, + this.createdDate, + this.chatSource, + this.conversationId, + this.fileTypeResponse, + this.userChatReplyResponse, + this.isReplied, + this.isImageLoaded, + this.image, + this.voice, + this.voiceController}); + + int? userChatHistoryId; + int? userChatHistoryLineId; + String? contant; + String? contantNo; + int? currentUserId; + String? currentUserName; + String? currentUserEmail; + int? targetUserId; + String? targetUserName; + String? targetUserEmail; + String? encryptedTargetUserId; + String? encryptedTargetUserName; + int? chatEventId; + dynamic? fileTypeId; + bool? isSeen; + bool? isDelivered; + DateTime? createdDate; + int? chatSource; + String? conversationId; + FileTypeResponse? fileTypeResponse; + UserChatReplyResponse? userChatReplyResponse; + bool? isReplied; + bool? isImageLoaded; + Uint8List? image; + File? voice; + AudioPlayer? voiceController; + + factory SingleUserChatModel.fromJson(Map json) => SingleUserChatModel( + userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], + userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"], + contant: json["contant"] == null ? null : json["contant"], + contantNo: json["contantNo"] == null ? null : json["contantNo"], + currentUserId: json["currentUserId"] == null ? null : json["currentUserId"], + currentUserName: json["currentUserName"] == null ? null : json["currentUserName"], + targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], + targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], + targetUserEmail: json["targetUserEmail"] == null ? null : json["targetUserEmail"], + currentUserEmail: json["currentUserEmail"] == null ? null : json["currentUserEmail"], + encryptedTargetUserId: json["encryptedTargetUserId"] == null ? null : json["encryptedTargetUserId"], + encryptedTargetUserName: json["encryptedTargetUserName"] == null ? null : json["encryptedTargetUserName"], + chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], + fileTypeId: json["fileTypeId"], + isSeen: json["isSeen"] == null ? null : json["isSeen"], + isDelivered: json["isDelivered"] == null ? null : json["isDelivered"], + createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), + chatSource: json["chatSource"] == null ? null : json["chatSource"], + conversationId: json["conversationId"] == null ? null : json["conversationId"], + fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), + userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]), + isReplied: false, + isImageLoaded: false, + image: null, + voice: null, + voiceController: json["fileTypeId"] == 13 ? AudioPlayer() : null); + + Map toJson() => { + "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, + "userChatHistoryLineId": userChatHistoryLineId == null ? null : userChatHistoryLineId, + "contant": contant == null ? null : contant, + "contantNo": contantNo == null ? null : contantNo, + "currentUserId": currentUserId == null ? null : currentUserId, + "currentUserName": currentUserName == null ? null : currentUserName, + "targetUserId": targetUserId == null ? null : targetUserId, + "targetUserName": targetUserName == null ? null : targetUserName, + "encryptedTargetUserId": encryptedTargetUserId == null ? null : encryptedTargetUserId, + "encryptedTargetUserName": encryptedTargetUserName == null ? null : encryptedTargetUserName, + "currentUserEmail": currentUserEmail == null ? null : currentUserEmail, + "targetUserEmail": targetUserEmail == null ? null : targetUserEmail, + "chatEventId": chatEventId == null ? null : chatEventId, + "fileTypeId": fileTypeId, + "isSeen": isSeen == null ? null : isSeen, + "isDelivered": isDelivered == null ? null : isDelivered, + "createdDate": createdDate == null ? null : createdDate!.toIso8601String(), + "chatSource": chatSource == null ? null : chatSource, + "conversationId": conversationId == null ? null : conversationId, + "fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(), + "userChatReplyResponse": userChatReplyResponse == null ? null : userChatReplyResponse!.toJson(), + }; +} + +class FileTypeResponse { + FileTypeResponse({ + this.fileTypeId, + this.fileTypeName, + this.fileTypeDescription, + this.fileKind, + this.fileName, + }); + + int? fileTypeId; + dynamic fileTypeName; + dynamic fileTypeDescription; + dynamic fileKind; + dynamic fileName; + + factory FileTypeResponse.fromJson(Map json) => FileTypeResponse( + fileTypeId: json["fileTypeId"] == null ? null : json["fileTypeId"], + fileTypeName: json["fileTypeName"], + fileTypeDescription: json["fileTypeDescription"], + fileKind: json["fileKind"], + fileName: json["fileName"], + ); + + Map toJson() => { + "fileTypeId": fileTypeId == null ? null : fileTypeId, + "fileTypeName": fileTypeName, + "fileTypeDescription": fileTypeDescription, + "fileKind": fileKind, + "fileName": fileName, + }; +} + +class UserChatReplyResponse { + UserChatReplyResponse( + {this.userChatHistoryId, + this.chatEventId, + this.contant, + this.contantNo, + this.fileTypeId, + this.createdDate, + this.targetUserId, + this.targetUserName, + this.fileTypeResponse, + this.isImageLoaded, + this.image, + this.voice}); + + int? userChatHistoryId; + int? chatEventId; + String? contant; + String? contantNo; + dynamic? fileTypeId; + DateTime? createdDate; + int? targetUserId; + String? targetUserName; + FileTypeResponse? fileTypeResponse; + bool? isImageLoaded; + Uint8List? image; + Uint8List? voice; + + factory UserChatReplyResponse.fromJson(Map json) => UserChatReplyResponse( + userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], + chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], + contant: json["contant"] == null ? null : json["contant"], + contantNo: json["contantNo"] == null ? null : json["contantNo"], + fileTypeId: json["fileTypeId"], + createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), + targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], + targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], + fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), + isImageLoaded: false, + image: null, + voice: null, + ); + + Map toJson() => { + "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, + "chatEventId": chatEventId == null ? null : chatEventId, + "contant": contant == null ? null : contant, + "contantNo": contantNo == null ? null : contantNo, + "fileTypeId": fileTypeId, + "createdDate": createdDate == null ? null : createdDate!.toIso8601String(), + "targetUserId": targetUserId == null ? null : targetUserId, + "targetUserName": targetUserName == null ? null : targetUserName, + "fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(), + }; +} diff --git a/lib/modules/cx_module/chat/model/get_user_login_token_model.dart b/lib/modules/cx_module/chat/model/get_user_login_token_model.dart new file mode 100644 index 00000000..f0620c3b --- /dev/null +++ b/lib/modules/cx_module/chat/model/get_user_login_token_model.dart @@ -0,0 +1,97 @@ +import 'dart:convert'; + +UserAutoLoginModel userAutoLoginModelFromJson(String str) => UserAutoLoginModel.fromJson(json.decode(str)); + +String userAutoLoginModelToJson(UserAutoLoginModel data) => json.encode(data.toJson()); + +class UserAutoLoginModel { + UserAutoLoginModel({this.response, this.errorResponses, this.StatusCode}); + + Response? response; + List? errorResponses; + int? StatusCode; + + factory UserAutoLoginModel.fromJson(Map json) => UserAutoLoginModel( + response: json["response"] == null ? null : Response.fromJson(json["response"]), + StatusCode: json["StatusCode"], + errorResponses: json["errorResponses"] == null ? null : List.from(json["errorResponses"].map((x) => ErrorResponse.fromJson(x))), + ); + + Map toJson() => { + "response": response == null ? null : response!.toJson(), + "StatusCode": StatusCode, + "errorResponses": errorResponses == null ? null : List.from(errorResponses!.map((x) => x.toJson())), + }; +} + +class Response { + Response({ + this.id, + this.userName, + this.email, + this.phone, + this.title, + this.token, + this.isDomainUser, + this.isActiveCode, + this.encryptedUserId, + this.encryptedUserName, + }); + + int? id; + String? userName; + String? email; + String? phone; + String? title; + String? token; + bool? isDomainUser; + bool? isActiveCode; + String? encryptedUserId; + String? encryptedUserName; + + factory Response.fromJson(Map json) => Response( + id: json["id"] == null ? null : json["id"], + userName: json["userName"] == null ? null : json["userName"], + email: json["email"] == null ? null : json["email"], + phone: json["phone"] == null ? null : json["phone"], + title: json["title"] == null ? null : json["title"], + token: json["token"] == null ? null : json["token"], + isDomainUser: json["isDomainUser"] == null ? null : json["isDomainUser"], + isActiveCode: json["isActiveCode"] == null ? null : json["isActiveCode"], + encryptedUserId: json["encryptedUserId"] == null ? null : json["encryptedUserId"], + encryptedUserName: json["encryptedUserName"] == null ? null : json["encryptedUserName"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "userName": userName == null ? null : userName, + "email": email == null ? null : email, + "phone": phone == null ? null : phone, + "title": title == null ? null : title, + "token": token == null ? null : token, + "isDomainUser": isDomainUser == null ? null : isDomainUser, + "isActiveCode": isActiveCode == null ? null : isActiveCode, + "encryptedUserId": encryptedUserId == null ? null : encryptedUserId, + "encryptedUserName": encryptedUserName == null ? null : encryptedUserName, + }; +} + +class ErrorResponse { + ErrorResponse({ + this.fieldName, + this.message, + }); + + String? fieldName; + String? message; + + factory ErrorResponse.fromJson(Map json) => ErrorResponse( + fieldName: json["fieldName"] == null ? null : json["fieldName"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "fieldName": fieldName == null ? null : fieldName, + "message": message == null ? null : message, + }; +} diff --git a/pubspec.lock b/pubspec.lock index 7d69171a..1693c075 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -949,6 +949,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" lottie: dependency: "direct main" description: @@ -973,6 +981,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.11.1" + message_pack_dart: + dependency: transitive + description: + name: message_pack_dart + sha256: "71b9f0ff60e5896e60b337960bb535380d7dba3297b457ac763ccae807385b59" + url: "https://pub.dev" + source: hosted + version: "2.0.1" meta: dependency: transitive description: @@ -1293,6 +1309,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.2+1" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" provider: dependency: "direct main" description: @@ -1429,6 +1453,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" shimmer: dependency: "direct main" description: @@ -1437,6 +1469,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + signalr_netcore: + dependency: "direct main" + description: + name: signalr_netcore + sha256: "8d59dc61284c5ff8aa27c4e3e802fcf782367f06cf42b39d5ded81680b72f8b8" + url: "https://pub.dev" + source: hosted + version: "1.4.4" signature: dependency: "direct main" description: @@ -1506,6 +1546,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.5.4+4" + sse: + dependency: transitive + description: + name: sse + sha256: fcc97470240bb37377f298e2bd816f09fd7216c07928641c0560719f50603643 + url: "https://pub.dev" + source: hosted + version: "4.1.8" + sse_channel: + dependency: transitive + description: + name: sse_channel + sha256: "9aad5d4eef63faf6ecdefb636c0f857bd6f74146d2196087dcf4b17ab5b49b1b" + url: "https://pub.dev" + source: hosted + version: "0.1.1" stack_trace: dependency: transitive description: @@ -1578,6 +1634,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" typed_data: dependency: transitive description: @@ -1714,6 +1778,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" wifi_iot: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index f766ebde..424aecc3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -97,6 +97,8 @@ dependencies: clipboard: ^2.0.2 audio_waveforms: ^1.3.0 + signalr_netcore: ^1.4.4 + local_auth_darwin: any dev_dependencies: flutter_test: From 01f004cecc5ce265f2e2035cdfaecfcdd6a614e1 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 13 Nov 2025 10:42:03 +0300 Subject: [PATCH 11/31] chat development cont. --- lib/controllers/api_routes/urls.dart | 11 +- lib/main.dart | 9 +- lib/models/user.dart | 1 - .../service_request_detail_main_view.dart | 15 + lib/modules/cx_module/chat/api_client.dart | 295 ++ .../cx_module/chat/chat_api_client.dart | 280 +- lib/modules/cx_module/chat/chat_page.dart | 736 ++-- lib/modules/cx_module/chat/chat_provider.dart | 3151 +++++++++-------- .../cx_module/chat/chat_rooms_page.dart | 2 +- .../chat/model/chat_login_response_model.dart | 30 + .../chat/model/chat_participant_model.dart | 65 + .../chat/model/user_chat_history_model.dart | 65 + .../cx_module/{ => survey}/survey_page.dart | 10 +- .../cx_module/survey/survey_provider.dart | 34 + lib/new_views/pages/login_page.dart | 9 +- 15 files changed, 2713 insertions(+), 2000 deletions(-) create mode 100644 lib/modules/cx_module/chat/api_client.dart create mode 100644 lib/modules/cx_module/chat/model/chat_login_response_model.dart create mode 100644 lib/modules/cx_module/chat/model/chat_participant_model.dart create mode 100644 lib/modules/cx_module/chat/model/user_chat_history_model.dart rename lib/modules/cx_module/{ => survey}/survey_page.dart (97%) create mode 100644 lib/modules/cx_module/survey/survey_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 6749e87f..6bb88970 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -15,7 +15,10 @@ class URLs { // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation - static const String chatHubUrl = "https://apiderichat.hmg.com/chathub/api"; // new V2 apis + static const String chatHubUrl = "https://apiderichat.hmg.com/chathub"; + static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis + static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis + static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis static String _host = host1; @@ -341,4 +344,10 @@ class URLs { static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete'; static get getClassification => '$_baseUrl/AssetInventory/Classification'; + + //chat + static get chatSdkToken => '$chatHubUrlApi/auth/sdk-token'; + + //survey + static get getQuestionnaire => '$_baseUrl/SurveyQuestionnaire/GetQuestionnaire'; } diff --git a/lib/main.dart b/lib/main.dart index 59cb86ee..6b47386e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -30,6 +30,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/modules/traf_module/traf_request_provider.dart'; @@ -99,6 +100,7 @@ import 'controllers/providers/api/gas_refill_comments.dart'; import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/settings/setting_provider.dart'; import 'dashboard_latest/dashboard_provider.dart'; +import 'modules/cx_module/survey/survey_provider.dart'; import 'new_views/pages/gas_refill_request_form.dart'; import 'providers/lookups/classification_lookup_provider.dart'; import 'providers/lookups/department_lookup_provider.dart'; @@ -238,8 +240,11 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => ServiceReportRepairLocationProvider()), ChangeNotifierProvider(create: (_) => ServiceRequestFaultDescriptionProvider()), - ///todo deleted - //ChangeNotifierProvider(create: (_) => ServiceReportVisitOperatorProvider()), + //chat + ChangeNotifierProvider(create: (_) => ChatProvider()), + //chat + ChangeNotifierProvider(create: (_) => SurveyProvider()), + ///todo deleted //ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()), //ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()), diff --git a/lib/models/user.dart b/lib/models/user.dart index 0bb4ab23..20158748 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -112,7 +112,6 @@ class User { } } - Map toUpdateProfileJson() { Map jsonObject = {}; // if (departmentId != null) jsonObject["department"] = departmentId; diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index bd89910c..aeed58a1 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; @@ -10,6 +11,8 @@ import 'package:test_sa/models/enums/work_order_next_step.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; +import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -81,6 +84,18 @@ class _ServiceRequestDetailMainState extends State { Navigator.pop(context); }, actions: [ + IconButton( + icon: const Icon(Icons.feedback_rounded), + onPressed: () { + Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId))); + }, + ), + IconButton( + icon: const Icon(Icons.chat_bubble), + onPressed: () { + Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: widget.requestId))); + }, + ), isNurse ? IconButton( icon: 'qr'.toSvgAsset( diff --git a/lib/modules/cx_module/chat/api_client.dart b/lib/modules/cx_module/chat/api_client.dart new file mode 100644 index 00000000..63e57b93 --- /dev/null +++ b/lib/modules/cx_module/chat/api_client.dart @@ -0,0 +1,295 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart'; +import 'package:http/io_client.dart'; +// ignore_for_file: avoid_annotating_with_dynamic + +typedef FactoryConstructor = U Function(dynamic); + +class APIError { + dynamic errorCode; + int? errorType; + String? errorMessage; + int? errorStatusCode; + + APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode); + + Map toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType, 'ErrorStatusCode': errorStatusCode}; + + @override + String toString() { + return jsonEncode(this); + } +} + +APIException _throwAPIException(Response response) { + switch (response.statusCode) { + case 200: + APIError? apiError; + if (response.body != null && response.body.isNotEmpty) { + var jsonError = jsonDecode(response.body); + print(jsonError); + apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']); + } + 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'], jsonError['ErrorType'], jsonError['ErrorStatusCode']); + } + return APIException(APIException.BAD_REQUEST, error: apiError); + case 401: + return APIException(APIException.UNAUTHORIZED); + case 403: + return APIException(APIException.FORBIDDEN); + case 404: + return APIException(APIException.NOT_FOUND); + case 500: + return APIException(APIException.INTERNAL_SERVER_ERROR); + case 444: + var downloadUrl = response.headers["location"]; + return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl); + default: + return APIException(APIException.OTHER); + } +} + +class ApiClient { + static final ApiClient _instance = ApiClient._internal(); + + ApiClient._internal(); + + factory ApiClient() => _instance; + + Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { + var _headers = {'Accept': 'application/json'}; + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + if (!kReleaseMode) { + print("Url:$url"); + var bodyJson = json.encode(jsonObject); + print("body:$bodyJson"); + } + var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData); + try { + if (!kReleaseMode) { + // logger.i("Url: " + url); + // logger.i("res: " + response.body); + } + + var jsonData = jsonDecode(response.body); + if (jsonData["IsAuthenticated"] != null) { + // AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; + } + + // if(url.contains("GetOfferDiscountsConfigData")) { + // jsonData["ErrorMessage"] = "Service Not Available"; + // jsonData["ErrorEndUserMessage"] = "Service Not Available"; + // } + + if (jsonData["ErrorMessage"] == null) { + return factoryConstructor(jsonData); + } else if (jsonData["MessageStatus"] == 2 && jsonData["IsOTPMaxLimitExceed"] == true) { + // await Utils.performLogout(AppRoutes.navigatorKey.currentContext, null); + throw const APIException(APIException.UNAUTHORIZED, error: null); + } else { + APIError? apiError; + apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType'] ?? 0, jsonData['ErrorStatusCode']); + throw APIException(APIException.BAD_REQUEST, error: apiError); + } + } catch (ex) { + if (ex is APIException) { + rethrow; + } else { + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + } + } + } + + Future postJsonForResponse(String url, T jsonObject, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { + String? requestBody; + late Map stringObj; + if (jsonObject != null) { + requestBody = jsonEncode(jsonObject); + if (headers == null) { + headers = {'Content-Type': 'application/json'}; + } else { + headers['Content-Type'] = 'application/json'; + } + } + + if (isFormData) { + headers = {'Content-Type': 'application/x-www-form-urlencoded'}; + stringObj = ((jsonObject ?? {}) as Map).map((key, value) => MapEntry(key, value?.toString() ?? "")); + } + + return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + + Future _postForResponse(String url, requestBody, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + try { + var _headers = {}; + if (token != null) { + _headers['Authorization'] = 'Bearer $token'; + } + + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + + if (queryParameters != null) { + var queryString = new Uri(queryParameters: queryParameters).query; + url = url + '?' + queryString; + } + var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120)); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return response; + } else { + throw _throwAPIException(response); + } + } on SocketException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on HttpException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } + } + + Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + if (headers == null) { + headers = {'Content-Type': 'application/json'}; + } else { + headers['Content-Type'] = 'application/json'; + } + + if (!kReleaseMode) { + print("Url:$url"); + // var bodyJson = json.encode(jsonObject); + // print("body:$bodyJson"); + } + + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + + Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + try { + var _headers = {}; + if (token != null) { + _headers['Authorization'] = 'Bearer $token'; + } + + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + + if (queryParameters != null) { + var queryString = new Uri(queryParameters: queryParameters).query; + url = url + '?' + queryString; + } + var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60)); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return response; + } else { + throw _throwAPIException(response); + } + } on SocketException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on HttpException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } + } + + Future _get(url, {Map? headers}) => _withClient((client) => client.get(url, headers: headers)); + + bool _certificateCheck(X509Certificate cert, String host, int port) => true; + + Future _withClient(Future Function(Client) fn) async { + var httpClient = HttpClient()..badCertificateCallback = _certificateCheck; + var client = IOClient(httpClient); + try { + return await fn(client); + } finally { + client.close(); + } + } + + Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); +} + +class APIException implements Exception { + static const String BAD_REQUEST = 'api_common_bad_request'; + static const String UNAUTHORIZED = 'api_common_unauthorized'; + static const String FORBIDDEN = 'api_common_forbidden'; + static const String NOT_FOUND = 'api_common_not_found'; + static const String INTERNAL_SERVER_ERROR = 'api_common_internal_server_error'; + static const String UPGRADE_REQUIRED = 'api_common_upgrade_required'; + static const String BAD_RESPONSE_FORMAT = 'api_common_bad_response_format'; + static const String OTHER = 'api_common_http_error'; + static const String TIMEOUT = 'api_common_http_timeout'; + static const String UNKNOWN = 'unexpected_error'; + + final String message; + final APIError? error; + final arguments; + + const APIException(this.message, {this.arguments, this.error}); + + Map toJson() => {'message': message, 'error': error, 'arguments': '$arguments'}; + + @override + String toString() { + return jsonEncode(this); + } +} diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index fc473329..985666c0 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -6,10 +6,15 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/string_extensions.dart'; - +import 'package:http/http.dart' as http; +import 'api_client.dart'; +import 'model/chat_login_response_model.dart'; +import 'model/chat_participant_model.dart'; import 'model/get_search_user_chat_model.dart'; -import 'model/get_user_login_token_model.dart'; +import 'model/get_user_login_token_model.dart' as userLoginTokenModel; +import 'model/user_chat_history_model.dart'; // import 'package:mohem_flutter_app/api/api_client.dart'; // import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -33,100 +38,137 @@ class ChatApiClient { factory ChatApiClient() => _instance; - Future getUserLoginToken() async { - UserAutoLoginModel userLoginResponse = UserAutoLoginModel(); - String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken; - Response response = await ApiClient().postJsonForResponse( - "${ApiConsts.chatLoginTokenUrl}externaluserlogin", - { - "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), - "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", - "isMobile": true, - "platform": Platform.isIOS ? "ios" : "android", - "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, - "isHuaweiDevice": AppState().getIsHuawei, - "voipToken": Platform.isIOS ? "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba" : "", - }, - ); + ChatLoginResponse? chatLoginResponse; + + Future getChatLoginToken(int moduleId, int requestId, String title, String employeeNumber) async { + Response response = await ApiClient().postJsonForResponse(URLs.chatSdkToken, { + "apiKey": URLs.chatApiKey, + "employeeNumber": employeeNumber, + "userDetails": {"userName": ApiManager.instance.user?.username, "email": ApiManager.instance.user?.email}, + "contextEnabled": true, + "moduleCode": moduleId.toString(), + "referenceId": requestId.toString(), + "referenceType": "ticket", + "title": title + }); if (!kReleaseMode) { // logger.i("login-res: " + response.body); } if (response.statusCode == 200) { - userLoginResponse = user.userAutoLoginModelFromJson(response.body); - } else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) { - getUserLoginToken(); - } else { - userLoginResponse = user.userAutoLoginModelFromJson(response.body); - userLoginResponse.errorResponses!.first.message!.showToast; + chatLoginResponse = ChatLoginResponse.fromJson(jsonDecode(response.body)); } - return userLoginResponse; + return chatLoginResponse; } - Future getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { - ChatUserModel chatUserModel; - Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo}, - token: AppState().chatDetails!.response!.token); + Future loadParticipants(int moduleId, int referenceId,String? assigneeEmployeeNumber) async { + Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); + if (!kReleaseMode) { - logger.i("res: " + response.body); + // logger.i("login-res: " + response.body); + } + if (response.statusCode == 200) { + return ChatParticipantModel.fromJson(jsonDecode(response.body)); + } else { + return null; } - chatUserModel = chatUserModelFromJson(response.body); - return chatUserModel; } - //Get User Recent Chats - Future getRecentChats() async { + Future loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async { + Response response = await ApiClient().postJsonForResponse( + "${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()}, + token: chatLoginResponse!.token); try { - Response response = - - - // await ApiManager.instance.get(URLs.getAllRequestsAndCount,h); - - - await ApiClient().getJsonForResponse( - "${ApiConsts.chatRecentUrl}getchathistorybyuserid", - token: AppState().chatDetails!.response!.token, - ); - if (!kReleaseMode) { - logger.i("res: " + response.body); + if (response.statusCode == 200) { + return UserChatHistoryModel.fromJson(jsonDecode(response.body)); + } else { + return null; } - return ChatUserModel.fromJson( - json.decode(response.body), - ); - } catch (e) { - throw e; + } catch (ex) { + return null; } } - // // Get Favorite Users - // Future getFavUsers() async { - // Response favRes = await ApiClient().getJsonForResponse( - // "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}", - // token: AppState().chatDetails!.response!.token, - // ); - // if (!kReleaseMode) { - // logger.i("res: " + favRes.body); - // } - // return ChatUserModel.fromJson(json.decode(favRes.body)); - // } - - //Get User Chat History - Future getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { + Future sendTextMessage(String message, int conversationId) async { try { - Response response = await ApiClient().getJsonForResponse( - "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", - token: AppState().chatDetails!.response!.token, - ); - if (!kReleaseMode) { - logger.i("res: " + response.body); + Response response = + await ApiClient().postJsonForResponse("${URLs.chatHubUrlApi}/chat/conversations/$conversationId/messages", {"content": message, "messageType": "Text"}, token: chatLoginResponse!.token); + + if (response.statusCode == 200) { + return ChatResponse.fromJson(jsonDecode(response.body)); + } else { + return null; } - return response; - } catch (e) { - getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); - throw e; + } catch (ex) { + print(ex); + return null; } } +// Future getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { +// ChatUserModel chatUserModel; +// Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo}, +// token: AppState().chatDetails!.response!.token); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// chatUserModel = chatUserModelFromJson(response.body); +// return chatUserModel; +// } + +// //Get User Recent Chats +// Future getRecentChats() async { +// try { +// Response response = +// +// +// // await ApiManager.instance.get(URLs.getAllRequestsAndCount,h); +// +// +// await ApiClient().getJsonForResponse( +// "${ApiConsts.chatRecentUrl}getchathistorybyuserid", +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return ChatUserModel.fromJson( +// json.decode(response.body), +// ); +// } catch (e) { +// throw e; +// } +// } + +// // Get Favorite Users +// Future getFavUsers() async { +// Response favRes = await ApiClient().getJsonForResponse( +// "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}", +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + favRes.body); +// } +// return ChatUserModel.fromJson(json.decode(favRes.body)); +// } + +// //Get User Chat History +// Future getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { +// try { +// Response response = await ApiClient().getJsonForResponse( +// "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// return response; +// } catch (e) { +// getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); +// throw e; +// } +// } + // //Favorite Users // Future favUser({required int userID, required int targetUserID}) async { // Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); @@ -137,54 +179,54 @@ class ChatApiClient { // return favoriteChatUser; // } - // //UnFavorite Users - // Future unFavUser({required int userID, required int targetUserID}) async { - // try { - // Response response = await ApiClient().postJsonForResponse( - // "${ApiConsts.chatFavUser}deleteFavUser", - // {"targetUserId": targetUserID, "userId": userID}, - // token: AppState().chatDetails!.response!.token, - // ); - // if (!kReleaseMode) { - // logger.i("res: " + response.body); - // } - // fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); - // return favoriteChatUser; - // } catch (e) { - // e as APIException; - // throw e; - // } - // } +// //UnFavorite Users +// Future unFavUser({required int userID, required int targetUserID}) async { +// try { +// Response response = await ApiClient().postJsonForResponse( +// "${ApiConsts.chatFavUser}deleteFavUser", +// {"targetUserId": targetUserID, "userId": userID}, +// token: AppState().chatDetails!.response!.token, +// ); +// if (!kReleaseMode) { +// logger.i("res: " + response.body); +// } +// fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); +// return favoriteChatUser; +// } catch (e) { +// e as APIException; +// throw e; +// } +// } // Upload Chat Media - Future uploadMedia(String userId, File file, String fileSource) async { - if (kDebugMode) { - print("${ApiConsts.chatMediaImageUploadUrl}upload"); - print(AppState().chatDetails!.response!.token); - } - - dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); - request.fields.addAll({'userId': userId, 'fileSource': fileSource}); - request.files.add(await MultipartFile.fromPath('files', file.path)); - request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); - StreamedResponse response = await request.send(); - String data = await response.stream.bytesToString(); - if (!kReleaseMode) { - logger.i("res: " + data); - } - return jsonDecode(data); - } +// Future uploadMedia(String userId, File file, String fileSource) async { +// if (kDebugMode) { +// print("${ApiConsts.chatMediaImageUploadUrl}upload"); +// print(AppState().chatDetails!.response!.token); +// } +// +// dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); +// request.fields.addAll({'userId': userId, 'fileSource': fileSource}); +// request.files.add(await MultipartFile.fromPath('files', file.path)); +// request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); +// StreamedResponse response = await request.send(); +// String data = await response.stream.bytesToString(); +// if (!kReleaseMode) { +// logger.i("res: " + data); +// } +// return jsonDecode(data); +// } - // Download File For Chat - Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { - Response response = await ApiClient().postJsonForResponse( - "${ApiConsts.chatMediaImageUploadUrl}download", - {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, - token: AppState().chatDetails!.response!.token, - ); - Uint8List data = Uint8List.fromList(response.bodyBytes); - return data; - } +// Download File For Chat +// Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { +// Response response = await ApiClient().postJsonForResponse( +// "${ApiConsts.chatMediaImageUploadUrl}download", +// {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, +// token: AppState().chatDetails!.response!.token, +// ); +// Uint8List data = Uint8List.fromList(response.bodyBytes); +// return data; +// } // //Get Chat Users & Favorite Images // Future> getUsersImages({required List encryptedEmails}) async { diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 5c5e34a9..75cb2fba 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -1,17 +1,27 @@ import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } class ChatPage extends StatefulWidget { - ChatPage({Key? key}) : super(key: key); + int moduleId; + int requestId; + String title; + bool readOnly; + + ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false}) : super(key: key); @override _ChatPageState createState() { @@ -27,11 +37,14 @@ class _ChatPageState extends State { final RecorderController recorderController = RecorderController(); PlayerController playerController = PlayerController(); + TextEditingController textEditingController = TextEditingController(); + ChatState chatState = ChatState.idle; @override void initState() { super.initState(); + getChatToken(); playerController.addListener(() async { // if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) { // await playerController.stopPlayer(); @@ -40,6 +53,11 @@ class _ChatPageState extends State { }); } + void getChatToken() { + String assigneeEmployeeNumber = ""; + Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId + 2, widget.title, context.settingProvider.username, assigneeEmployeeNumber); + } + @override void dispose() { playerController.dispose(); @@ -50,342 +68,394 @@ class _ChatPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: AppColor.white10, - appBar: const DefaultAppBar(title: "Req No. 343443"), - body: Column( - children: [ - Container( - color: AppColor.neutral50, - constraints: const BoxConstraints(maxHeight: 56), - padding: const EdgeInsets.all(16), - child: Row( + backgroundColor: AppColor.white10, + appBar: DefaultAppBar(title: widget.title), + body: Consumer(builder: (context, chatProvider, child) { + if (chatProvider.chatLoginTokenLoading) return const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3).center; + + if (chatProvider.chatLoginResponse == null) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - "Engineer: Mahmoud Shrouf", + "Failed to connect chat", overflow: TextOverflow.ellipsis, - maxLines: 2, - style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), - ).expanded, - 4.width, - Text( - "View All Documents", - style: AppTextStyles.bodyText.copyWith( - color: AppColor.white10, - decoration: TextDecoration.underline, - decorationColor: AppColor.white10, - ), + maxLines: 1, + style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w500), ), + 24.height, + AppFilledButton( + label: "Retry", + maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + getChatToken(); + }, + ).paddingOnly(start: 48, end: 48) ], - ), - ), - Container( - // width: double.infinity, - color: AppColor.neutral100, - child: ListView( + ).center; + } + return Column( + children: [ + Container( + color: AppColor.neutral50, + constraints: const BoxConstraints(maxHeight: 56), padding: const EdgeInsets.all(16), - children: [ - recipientMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"), - recipientMsgCard(false, "testing"), - recipientMsgCard(false, "testing testing testing"), - dateCard("Mon 27 Oct"), - senderMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"), - senderMsgCard(false, "Please let me know what is the issue?"), - ], - )).expanded, - Divider(height: 1, thickness: 1, color: const Color(0xff767676).withOpacity(.11)), - SafeArea( - child: ConstrainedBox( - constraints: const BoxConstraints(minHeight: 56), - child: Row( - children: [ - if (chatState == ChatState.idle) ...[ - TextFormField( - cursorColor: AppColor.neutral50, - style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), - minLines: 1, - maxLines: 3, - textInputAction: TextInputAction.none, - keyboardType: TextInputType.multiline, - decoration: InputDecoration( - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - border: InputBorder.none, - errorBorder: InputBorder.none, - contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), - alignLabelWithHint: true, - filled: true, - constraints: const BoxConstraints(), - suffixIconConstraints: const BoxConstraints(), - hintText: "Type your message here...", - hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), - // suffixIcon: Row( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.end, - // mainAxisAlignment: MainAxisAlignment.end, - // children: [ - // - // 8.width, - // ], - // ) - ), - ).expanded, - IconButton( - onPressed: () {}, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - ), - icon: "chat_attachment".toSvgAsset(width: 24, height: 24), - constraints: const BoxConstraints(), - ), - IconButton( - onPressed: () async { - await recorderController.checkPermission(); - if (recorderController.hasPermission) { - chatState = ChatState.voiceRecordingStarted; - recorderController.record(); - setState(() {}); - } else { - "Audio permission denied. Please enable from setting".showToast; - } - // if (!isPermissionGranted) { - // "Audio permission denied. Please enable from setting".showToast; - // return; - // } - }, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - ), - icon: "chat_mic".toSvgAsset(width: 24, height: 24), - constraints: const BoxConstraints(), - ), - ] else if (chatState == ChatState.voiceRecordingStarted) ...[ - AudioWaveforms( - size: Size(MediaQuery.of(context).size.width, 56.0), - waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), - padding: const EdgeInsets.only(left: 16), - recorderController: recorderController, // Customize how waveforms looks. + child: Row( + children: [ + Text( + "Engineer: Mahmoud Shrouf", + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), ).expanded, - IconButton( - onPressed: () async { - isAudioRecording = false; - await recorderController.pause(); - recordedFilePath = await recorderController.stop(); - chatState = ChatState.voiceRecordingCompleted; - setState(() {}); - }, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + 4.width, + Text( + "View All Documents", + style: AppTextStyles.bodyText.copyWith( + color: AppColor.white10, + decoration: TextDecoration.underline, + decorationColor: AppColor.white10, ), - icon: Icon(Icons.stop_circle_rounded), - constraints: const BoxConstraints(), - ) - ] else if (chatState == ChatState.voiceRecordingCompleted) ...[ - if (playerController.playerState == PlayerState.playing) - IconButton( - onPressed: () async { - await playerController.pausePlayer(); - await playerController.stopPlayer(); - setState(() {}); - }, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - ), - icon: const Icon(Icons.stop_circle_outlined, size: 20), - constraints: const BoxConstraints(), - ) - else - IconButton( - onPressed: () async { - await playerController.preparePlayer(path: recordedFilePath!); - await playerController.startPlayer(); - setState(() {}); - }, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - ), - icon: const Icon(Icons.play_circle_fill_rounded, size: 20), - constraints: const BoxConstraints(), - ), - AudioFileWaveforms( - playerController: playerController, - waveformData: recorderController.waveData, - enableSeekGesture: false, - continuousWaveform: false, - waveformType: WaveformType.long, - playerWaveStyle: const PlayerWaveStyle( - fixedWaveColor: AppColor.neutral50, - liveWaveColor: AppColor.primary10, - showSeekLine: true, - ), - size: Size(MediaQuery.of(context).size.width, 56.0), - ).expanded, - IconButton( - onPressed: () async { - await playerController.stopPlayer(); - recorderController.reset(); - recordedFilePath = null; - chatState = ChatState.idle; - setState(() {}); - }, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - ), - icon: "delete_icon".toSvgAsset(width: 24, height: 24), - constraints: const BoxConstraints(), ), ], + ), + ), + Container( + // width: double.infinity, + color: AppColor.neutral100, + child: !chatProvider.userChatHistoryLoading + ? ListView( + padding: const EdgeInsets.all(16), + children: [ + recipientMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?", loading: true), + recipientMsgCard(false, "testing", loading: true), + recipientMsgCard(false, "testing testing testing", loading: true), + // dateCard("Mon 27 Oct",), + senderMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?", loading: true), + senderMsgCard(false, "Please let me know what is the issue?", loading: true), + ], + ) + : chatProvider.chatResponseList.isEmpty + ? Text( + "Send a message to start conversation", + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50.withOpacity(.5), fontWeight: FontWeight.w500), + ).center + : ListView.builder( + itemBuilder: (cxt, index) => recipientMsgCard(true, chatProvider.chatResponseList[index].content ?? ""), itemCount: chatProvider.chatResponseList.length)) + .expanded, + if (!widget.readOnly) ...[ + Divider(height: 1, thickness: 1, color: const Color(0xff767676).withOpacity(.11)), + SafeArea( + child: ConstrainedBox( + constraints: const BoxConstraints(minHeight: 56), + child: Row( + children: [ + if (chatState == ChatState.idle) ...[ + TextFormField( + controller: textEditingController, + cursorColor: AppColor.neutral50, + style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), + minLines: 1, + maxLines: 3, + textInputAction: TextInputAction.none, + keyboardType: TextInputType.multiline, + decoration: InputDecoration( + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + border: InputBorder.none, + errorBorder: InputBorder.none, + contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), + alignLabelWithHint: true, + filled: true, + constraints: const BoxConstraints(), + suffixIconConstraints: const BoxConstraints(), + hintText: "Type your message here...", + hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), + // suffixIcon: Row( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.end, + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // + // 8.width, + // ], + // ) + ), + ).expanded, + IconButton( + onPressed: () {}, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: "chat_attachment".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + IconButton( + onPressed: () async { + await recorderController.checkPermission(); + if (recorderController.hasPermission) { + chatState = ChatState.voiceRecordingStarted; + recorderController.record(); + setState(() {}); + } else { + "Audio permission denied. Please enable from setting".showToast; + } + // if (!isPermissionGranted) { + // "Audio permission denied. Please enable from setting".showToast; + // return; + // } + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: "chat_mic".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + ] else if (chatState == ChatState.voiceRecordingStarted) ...[ + AudioWaveforms( + size: Size(MediaQuery.of(context).size.width, 56.0), + waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), + padding: const EdgeInsets.only(left: 16), + recorderController: recorderController, // Customize how waveforms looks. + ).expanded, + IconButton( + onPressed: () async { + isAudioRecording = false; + await recorderController.pause(); + recordedFilePath = await recorderController.stop(); + chatState = ChatState.voiceRecordingCompleted; + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: Icon(Icons.stop_circle_rounded), + constraints: const BoxConstraints(), + ) + ] else if (chatState == ChatState.voiceRecordingCompleted) ...[ + if (playerController.playerState == PlayerState.playing) + IconButton( + onPressed: () async { + await playerController.pausePlayer(); + await playerController.stopPlayer(); + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.stop_circle_outlined, size: 20), + constraints: const BoxConstraints(), + ) + else + IconButton( + onPressed: () async { + await playerController.preparePlayer(path: recordedFilePath!); + await playerController.startPlayer(); + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.play_circle_fill_rounded, size: 20), + constraints: const BoxConstraints(), + ), + AudioFileWaveforms( + playerController: playerController, + waveformData: recorderController.waveData, + enableSeekGesture: false, + continuousWaveform: false, + waveformType: WaveformType.long, + playerWaveStyle: const PlayerWaveStyle( + fixedWaveColor: AppColor.neutral50, + liveWaveColor: AppColor.primary10, + showSeekLine: true, + ), + size: Size(MediaQuery.of(context).size.width, 56.0), + ).expanded, + IconButton( + onPressed: () async { + await playerController.stopPlayer(); + recorderController.reset(); + recordedFilePath = null; + chatState = ChatState.idle; + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: "delete_icon".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + ], - // if (recordedFilePath == null) ...[ - // isAudioRecording - // ? AudioWaveforms( - // size: Size(MediaQuery.of(context).size.width, 56.0), - // - // // enableGesture: true, - // - // waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), - // padding: const EdgeInsets.only(left: 16), - // recorderController: recorderController, // Customize how waveforms looks. - // ).expanded - // : TextFormField( - // cursorColor: AppColor.neutral50, - // style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), - // minLines: 1, - // maxLines: 3, - // textInputAction: TextInputAction.none, - // keyboardType: TextInputType.multiline, - // decoration: InputDecoration( - // enabledBorder: InputBorder.none, - // focusedBorder: InputBorder.none, - // border: InputBorder.none, - // errorBorder: InputBorder.none, - // contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), - // alignLabelWithHint: true, - // filled: true, - // constraints: const BoxConstraints(), - // suffixIconConstraints: const BoxConstraints(), - // hintText: "Type your message here...", - // hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), - // // suffixIcon: Row( - // // mainAxisSize: MainAxisSize.min, - // // crossAxisAlignment: CrossAxisAlignment.end, - // // mainAxisAlignment: MainAxisAlignment.end, - // // children: [ - // // - // // 8.width, - // // ], - // // ) - // ), - // ).expanded, - // IconButton( - // onPressed: () {}, - // style: const ButtonStyle( - // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - // ), - // icon: "chat_attachment".toSvgAsset(width: 24, height: 24), - // constraints: const BoxConstraints(), - // ), - // ], - // if (recordedFilePath == null) - // ...[] - // else ...[ - // IconButton( - // onPressed: () async { - // await playerController.preparePlayer(path: recordedFilePath!); - // playerController.startPlayer(); - // }, - // style: const ButtonStyle( - // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - // ), - // icon: const Icon(Icons.play_circle_fill_rounded, size: 20), - // constraints: const BoxConstraints(), - // ), - // AudioFileWaveforms( - // playerController: playerController, - // size: Size(300, 50), - // ).expanded, - // IconButton( - // onPressed: () async { - // playerController.pausePlayer(); - // }, - // style: const ButtonStyle( - // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - // ), - // icon: const Icon(Icons.pause_circle_filled_outlined, size: 20), - // constraints: const BoxConstraints(), - // ), - // IconButton( - // onPressed: () {}, - // style: const ButtonStyle( - // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - // ), - // icon: "delete".toSvgAsset(width: 24, height: 24), - // constraints: const BoxConstraints(), - // ), - // ], - // if (isAudioRecording && recorderController.isRecording) - // IconButton( - // onPressed: () {}, - // style: const ButtonStyle( - // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - // ), - // icon: "chat_msg_send".toSvgAsset(width: 24, height: 24), - // constraints: const BoxConstraints(), - // ), - // if (isAudioRecording) - // IconButton( - // onPressed: () async { - // isAudioRecording = false; - // await recorderController.pause(); - // recordedFilePath = await recorderController.stop(); - // chatState = ChatState.voiceRecordingCompleted; - // setState(() {}); - // }, - // style: const ButtonStyle( - // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - // ), - // icon: Icon(Icons.stop_circle_rounded), - // constraints: const BoxConstraints(), - // ) - // else - // IconButton( - // onPressed: () async { - // await recorderController.checkPermission(); - // if (recorderController.hasPermission) { - // setState(() { - // isAudioRecording = true; - // }); - // recorderController.record(); - // } else { - // "Audio permission denied. Please enable from setting".showToast; - // } - // // if (!isPermissionGranted) { - // // "Audio permission denied. Please enable from setting".showToast; - // // return; - // // } - // }, - // style: const ButtonStyle( - // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded - // ), - // icon: "chat_mic".toSvgAsset(width: 24, height: 24), - // constraints: const BoxConstraints(), - // ), + // if (recordedFilePath == null) ...[ + // isAudioRecording + // ? AudioWaveforms( + // size: Size(MediaQuery.of(context).size.width, 56.0), + // + // // enableGesture: true, + // + // waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), + // padding: const EdgeInsets.only(left: 16), + // recorderController: recorderController, // Customize how waveforms looks. + // ).expanded + // : TextFormField( + // cursorColor: AppColor.neutral50, + // style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), + // minLines: 1, + // maxLines: 3, + // textInputAction: TextInputAction.none, + // keyboardType: TextInputType.multiline, + // decoration: InputDecoration( + // enabledBorder: InputBorder.none, + // focusedBorder: InputBorder.none, + // border: InputBorder.none, + // errorBorder: InputBorder.none, + // contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), + // alignLabelWithHint: true, + // filled: true, + // constraints: const BoxConstraints(), + // suffixIconConstraints: const BoxConstraints(), + // hintText: "Type your message here...", + // hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), + // // suffixIcon: Row( + // // mainAxisSize: MainAxisSize.min, + // // crossAxisAlignment: CrossAxisAlignment.end, + // // mainAxisAlignment: MainAxisAlignment.end, + // // children: [ + // // + // // 8.width, + // // ], + // // ) + // ), + // ).expanded, + // IconButton( + // onPressed: () {}, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "chat_attachment".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), + // ], + // if (recordedFilePath == null) + // ...[] + // else ...[ + // IconButton( + // onPressed: () async { + // await playerController.preparePlayer(path: recordedFilePath!); + // playerController.startPlayer(); + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: const Icon(Icons.play_circle_fill_rounded, size: 20), + // constraints: const BoxConstraints(), + // ), + // AudioFileWaveforms( + // playerController: playerController, + // size: Size(300, 50), + // ).expanded, + // IconButton( + // onPressed: () async { + // playerController.pausePlayer(); + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: const Icon(Icons.pause_circle_filled_outlined, size: 20), + // constraints: const BoxConstraints(), + // ), + // IconButton( + // onPressed: () {}, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "delete".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), + // ], + // if (isAudioRecording && recorderController.isRecording) + // IconButton( + // onPressed: () {}, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "chat_msg_send".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), + // if (isAudioRecording) + // IconButton( + // onPressed: () async { + // isAudioRecording = false; + // await recorderController.pause(); + // recordedFilePath = await recorderController.stop(); + // chatState = ChatState.voiceRecordingCompleted; + // setState(() {}); + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: Icon(Icons.stop_circle_rounded), + // constraints: const BoxConstraints(), + // ) + // else + // IconButton( + // onPressed: () async { + // await recorderController.checkPermission(); + // if (recorderController.hasPermission) { + // setState(() { + // isAudioRecording = true; + // }); + // recorderController.record(); + // } else { + // "Audio permission denied. Please enable from setting".showToast; + // } + // // if (!isPermissionGranted) { + // // "Audio permission denied. Please enable from setting".showToast; + // // return; + // // } + // }, + // style: const ButtonStyle( + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + // ), + // icon: "chat_mic".toSvgAsset(width: 24, height: 24), + // constraints: const BoxConstraints(), + // ), - IconButton( - onPressed: () {}, - style: const ButtonStyle( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + IconButton( + onPressed: () { + chatProvider.sendTextMessage(textEditingController.text).then((success) { + if (success) { + textEditingController.clear(); + } + }); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: chatProvider.messageIsSending + ? const SizedBox( + height: 24, + width: 24, + child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2), + ) + : "chat_msg_send".toSvgAsset(width: 24, height: 24), + constraints: const BoxConstraints(), + ), + 8.width, + ], ), - icon: "chat_msg_send".toSvgAsset(width: 24, height: 24), - constraints: const BoxConstraints(), ), - 8.width, - ], - ), - ), - ) - ], - ), - ); + ) + ] + ], + ); + })); } Widget dateCard(String date) { @@ -400,7 +470,7 @@ class _ChatPageState extends State { .center; } - Widget senderMsgCard(bool showHeader, String msg) { + Widget senderMsgCard(bool showHeader, String msg, {bool loading = false}) { Widget senderHeader = Row( mainAxisSize: MainAxisSize.min, children: [ @@ -409,13 +479,13 @@ class _ChatPageState extends State { overflow: TextOverflow.ellipsis, maxLines: 1, style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), - ), + ).toShimmer(context: context, isShow: loading), 8.width, Container( height: 26, width: 26, decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), - ), + ).toShimmer(context: context, isShow: loading), ], ); @@ -440,11 +510,11 @@ class _ChatPageState extends State { Text( msg, style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), - ), + ).toShimmer(context: context, isShow: loading), Text( "2:00 PM", style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)), - ), + ).toShimmer(context: context, isShow: loading), ], )), ], @@ -452,7 +522,7 @@ class _ChatPageState extends State { ); } - Widget recipientMsgCard(bool showHeader, String msg) { + Widget recipientMsgCard(bool showHeader, String msg, {bool loading = false}) { Widget recipientHeader = Row( mainAxisSize: MainAxisSize.min, children: [ @@ -460,14 +530,14 @@ class _ChatPageState extends State { height: 26, width: 26, decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), - ), + ).toShimmer(context: context, isShow: loading), 8.width, Text( "Mahmoud Shrouf", overflow: TextOverflow.ellipsis, maxLines: 1, style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), - ) + ).toShimmer(context: context, isShow: loading) ], ); @@ -492,7 +562,7 @@ class _ChatPageState extends State { Text( msg, style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), - ), + ).toShimmer(context: context, isShow: loading), Align( alignment: Alignment.centerRight, widthFactor: 1, @@ -502,7 +572,7 @@ class _ChatPageState extends State { ), ), ], - )), + ).toShimmer(context: context, isShow: loading)), ], ), ); diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index a22545ae..48438375 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -3,11 +3,13 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:audio_waveforms/audio_waveforms.dart'; + // import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart'; +import 'package:intl/intl.dart'; import 'package:just_audio/just_audio.dart' as JustAudio; import 'package:just_audio/just_audio.dart'; @@ -40,224 +42,296 @@ import 'package:signalr_netcore/hub_connection.dart'; import 'package:signalr_netcore/signalr_client.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.dart'; import 'package:uuid/uuid.dart'; import 'package:flutter/material.dart' as Material; +import 'chat_api_client.dart'; +import 'model/chat_participant_model.dart'; import 'model/get_search_user_chat_model.dart'; -import 'get_single_user_chat_list_model.dart'; +import 'model/get_single_user_chat_list_model.dart'; +import 'model/user_chat_history_model.dart'; +// import 'get_single_user_chat_list_model.dart'; late HubConnection chatHubConnection; class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { - ScrollController scrollController = ScrollController(); - - TextEditingController message = TextEditingController(); - TextEditingController search = TextEditingController(); - TextEditingController searchGroup = TextEditingController(); - - List userChatHistory = [], repliedMsg = []; - List? pChatHistory, searchedChats; - String chatCID = ''; - bool isLoading = true; - bool isChatScreenActive = false; - int receiverID = 0; - late File selectedFile; - String sFileType = ""; - - List favUsersList = []; - int paginationVal = 0; - int? cTypingUserId = 0; - bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; - - // Audio Recoding Work - Timer? _timer; - int _recodeDuration = 0; - bool isRecoding = false; - bool isPause = false; - bool isPlaying = false; - String? path; - String? musicFile; - late Directory appDirectory; - late RecorderController recorderController; - late PlayerController playerController; - - // List getEmployeeSubordinatesList = []; - List teamMembersList = []; - - // groups.GetUserGroups userGroups = groups.GetUserGroups(); - Material.TextDirection textDirection = Material.TextDirection.ltr; - bool isRTL = false; - String msgText = ""; - - //Chat Home Page Counter - int chatUConvCounter = 0; - - // late List groupChatHistory, groupChatReplyData; - - /// Search Provider - List? chatUsersList = []; - int pageNo = 1; - - bool disbaleChatForThisUser = false; + // ScrollController scrollController = ScrollController(); + // + // TextEditingController message = TextEditingController(); + // TextEditingController search = TextEditingController(); + // TextEditingController searchGroup = TextEditingController(); + // + // List? pChatHistory, searchedChats; + // String chatCID = ''; + // bool isLoading = true; + // bool isChatScreenActive = false; + // int receiverID = 0; + // late File selectedFile; + // String sFileType = ""; + // + // List favUsersList = []; + // int paginationVal = 0; + // int? cTypingUserId = 0; + // bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; + // + // // Audio Recoding Work + // Timer? _timer; + // int _recodeDuration = 0; + // bool isRecoding = false; + // bool isPause = false; + // bool isPlaying = false; + // String? path; + // String? musicFile; + // late Directory appDirectory; + // late RecorderController recorderController; + // late PlayerController playerController; + // + // // List getEmployeeSubordinatesList = []; + // List teamMembersList = []; + // + // // groups.GetUserGroups userGroups = groups.GetUserGroups(); + // Material.TextDirection textDirection = Material.TextDirection.ltr; + // bool isRTL = false; + // String msgText = ""; + // + // //Chat Home Page Counter + // int chatUConvCounter = 0; + // + // // late List groupChatHistory, groupChatReplyData; + // + // /// Search Provider + // List? chatUsersList = []; + // int pageNo = 1; + // + // bool disbaleChatForThisUser = false; + + bool chatLoginTokenLoading = false; + ChatLoginResponse? chatLoginResponse; + + bool chatParticipantLoading = false; + ChatParticipantModel? chatParticipantModel; + + bool userChatHistoryLoading = false; + UserChatHistoryModel? userChatHistory; + + bool messageIsSending = false; + + List chatResponseList = []; + + void reset() { + chatLoginTokenLoading = false; + chatParticipantLoading = false; + userChatHistoryLoading = false; + chatLoginResponse = null; + chatParticipantModel = null; + userChatHistory = null; + ChatApiClient().chatLoginResponse = null; + } + + Future getUserAutoLoginToken(int moduleId, int requestId, String title, String employeeNumber, String? assigneeEmployeeNumber) async { + reset(); + chatLoginTokenLoading = true; + notifyListeners(); + chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, employeeNumber); + chatLoginTokenLoading = false; + chatParticipantLoading = true; + notifyListeners(); + // loadParticipants(moduleId, requestId); + loadChatHistory(moduleId, requestId, employeeNumber, assigneeEmployeeNumber); + } - // List? uGroups = [], searchGroups = []; + // Future loadParticipants(int moduleId, int requestId) async { + // // loadChatHistoryLoading = true; + // // notifyListeners(); + // chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId); + // chatParticipantLoading = false; + // notifyListeners(); + // } - Future getUserAutoLoginToken() async { - userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + Future loadChatHistory(int moduleId, int requestId, String myId, String? assigneeEmployeeNumber) async { + userChatHistoryLoading = true; + notifyListeners(); + chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); + userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, "12"); + chatResponseList = userChatHistory?.response ?? []; - if (userLoginResponse.StatusCode == 500) { - disbaleChatForThisUser = true; - notifyListeners(); - } + userChatHistoryLoading = false; + notifyListeners(); + } - if (userLoginResponse.response != null) { - // AppState().setchatUserDetails = userLoginResponse; - } else { - // AppState().setchatUserDetails = userLoginResponse; - userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr".showToast; - disbaleChatForThisUser = true; - notifyListeners(); + Future sendTextMessage(String message) async { + messageIsSending = true; + notifyListeners(); + bool returnStatus = false; + ChatResponse? chatResponse = await ChatApiClient().sendTextMessage(message, chatParticipantModel!.id!); + if (chatResponse != null) { + returnStatus = true; + chatResponseList.add(chatResponse); } + messageIsSending = false; + notifyListeners(); + return returnStatus; } + // List? uGroups = [], searchGroups = []; + + // Future getUserAutoLoginToken() async { + // userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + // + // if (userLoginResponse.StatusCode == 500) { + // disbaleChatForThisUser = true; + // notifyListeners(); + // } + // + // if (userLoginResponse.response != null) { + // // AppState().setchatUserDetails = userLoginResponse; + // } else { + // // AppState().setchatUserDetails = userLoginResponse; + // userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr".showToast; + // disbaleChatForThisUser = true; + // notifyListeners(); + // } + // } + Future buildHubConnection() async { chatHubConnection = await getHubConnection(); await chatHubConnection.start(); if (kDebugMode) { // logger.i("Hub Conn: Startedddddddd"); } - chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); - chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); + // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); + // chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); //group On message - chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived); + // chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived); } Future getHubConnection() async { HubConnection hub; HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hub = HubConnectionBuilder() - .withUrl(URLs.chatHubUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) + .withUrl(URLs.chatHubUrlChat + "?UserId=AppState().chatDetails!.response!.id&source=Desktop&access_token=AppState().chatDetails!.response!.token", options: httpOp) .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); return hub; } void registerEvents() { - chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); + // chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); - chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); - chatHubConnection.on("OnUserTypingAsync", onUserTyping); + // chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); + // chatHubConnection.on("OnUserTypingAsync", onUserTyping); chatHubConnection.on("OnUserCountAsync", userCountAsync); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); - chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); - chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); + // chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); + // chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); // // {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]} if (kDebugMode) { - logger.i("All listeners registered"); - } - } - - Future getUserRecentChats() async { - ChatUserModel recentChat = await ChatApiClient().getRecentChats(); - ChatUserModel favUList = await ChatApiClient().getFavUsers(); - // userGroups = await ChatApiClient().getGroupsByUserId(); - if (favUList.response != null && recentChat.response != null) { - favUsersList = favUList.response!; - 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) { - user.isFav = favUser.isFav; - } - } - } - } - pChatHistory = recentChat.response ?? []; - uGroups = userGroups.groupresponse ?? []; - 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())); - sort(); - notifyListeners(); - if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { - getUserImages(); - } - } + // logger.i("All listeners registered"); + } + } + + // Future getUserRecentChats() async { + // ChatUserModel recentChat = await ChatApiClient().getRecentChats(); + // ChatUserModel favUList = await ChatApiClient().getFavUsers(); + // // userGroups = await ChatApiClient().getGroupsByUserId(); + // if (favUList.response != null && recentChat.response != null) { + // favUsersList = favUList.response!; + // 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) { + // user.isFav = favUser.isFav; + // } + // } + // } + // } + // pChatHistory = recentChat.response ?? []; + // uGroups = userGroups.groupresponse ?? []; + // 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())); + // sort(); + // notifyListeners(); + // if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { + // getUserImages(); + // } + // } Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); return ""; } - void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { - isLoading = true; - if (isNewChat) userChatHistory = []; - if (!loadMore) paginationVal = 0; - isChatScreenActive = true; - receiverID = receiverUID; - Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); - if (response.statusCode == 204) { - if (isNewChat) { - userChatHistory = []; - } else if (loadMore) {} - } else { - if (loadMore) { - List temp = getSingleUserChatModel(response.body).reversed.toList(); - userChatHistory.addAll(temp); - } else { - userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); - } - } - isLoading = false; - notifyListeners(); - - if (isChatScreenActive && receiverUID == receiverID) { - markRead(userChatHistory, receiverUID); - } - - generateConvId(); - } - - void generateConvId() async { - Uuid uuid = const Uuid(); - chatCID = uuid.v4(); - } - - void markRead(List data, int receiverID) { - for (SingleUserChatModel element in data!) { - if (AppState().chatDetails!.response!.id! == element.targetUserId) { - if (element.isSeen != null) { - if (!element.isSeen!) { - element.isSeen = true; - dynamic data = [ - { - "userChatHistoryId": element.userChatHistoryId, - "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, - "isDelivered": true, - "isSeen": true, - } - ]; - updateUserChatHistoryStatusAsync(data); - notifyListeners(); - } - } - for (ChatUser element in searchedChats!) { - if (element.id == receiverID) { - element.unreadMessageCount = 0; - chatUConvCounter = 0; - } - } - } - } - notifyListeners(); - } + // void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { + // isLoading = true; + // if (isNewChat) userChatHistory = []; + // if (!loadMore) paginationVal = 0; + // isChatScreenActive = true; + // receiverID = receiverUID; + // Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); + // if (response.statusCode == 204) { + // if (isNewChat) { + // userChatHistory = []; + // } else if (loadMore) {} + // } else { + // if (loadMore) { + // List temp = getSingleUserChatModel(response.body).reversed.toList(); + // userChatHistory.addAll(temp); + // } else { + // userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); + // } + // } + // isLoading = false; + // notifyListeners(); + // + // if (isChatScreenActive && receiverUID == receiverID) { + // markRead(userChatHistory, receiverUID); + // } + // + // generateConvId(); + // } + // + // void generateConvId() async { + // Uuid uuid = const Uuid(); + // chatCID = uuid.v4(); + // } + + // void markRead(List data, int receiverID) { + // for (SingleUserChatModel element in data!) { + // if (AppState().chatDetails!.response!.id! == element.targetUserId) { + // if (element.isSeen != null) { + // if (!element.isSeen!) { + // element.isSeen = true; + // dynamic data = [ + // { + // "userChatHistoryId": element.userChatHistoryId, + // "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, + // "isDelivered": true, + // "isSeen": true, + // } + // ]; + // updateUserChatHistoryStatusAsync(data); + // notifyListeners(); + // } + // } + // for (ChatUser element in searchedChats!) { + // if (element.id == receiverID) { + // element.unreadMessageCount = 0; + // chatUConvCounter = 0; + // } + // } + // } + // } + // notifyListeners(); + // } void updateUserChatHistoryStatusAsync(List data) { try { @@ -277,36 +351,36 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); - List getGroupChatHistoryAsync(String str) => - List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); - - Future uploadAttachments(String userId, File file, String fileSource) async { - dynamic result; - try { - Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); - if (response != null) { - result = response; - } else { - result = []; - } - } catch (e) { - throw e; - } - return result; - } - - void updateUserChatStatus(List? args) { - dynamic items = args!.toList(); - for (var cItem in items[0]) { - for (SingleUserChatModel chat in userChatHistory) { - if (cItem["contantNo"].toString() == chat.contantNo.toString()) { - chat.isSeen = cItem["isSeen"]; - chat.isDelivered = cItem["isDelivered"]; - } - } - } - notifyListeners(); - } + // List getGroupChatHistoryAsync(String str) => + // List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); + // + // Future uploadAttachments(String userId, File file, String fileSource) async { + // dynamic result; + // try { + // Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); + // if (response != null) { + // result = response; + // } else { + // result = []; + // } + // } catch (e) { + // throw e; + // } + // return result; + // } + + // void updateUserChatStatus(List? args) { + // dynamic items = args!.toList(); + // for (var cItem in items[0]) { + // for (SingleUserChatModel chat in userChatHistory) { + // if (cItem["contantNo"].toString() == chat.contantNo.toString()) { + // chat.isSeen = cItem["isSeen"]; + // chat.isDelivered = cItem["isDelivered"]; + // } + // } + // } + // notifyListeners(); + // } void getGroupUserStatus(List? args) { //note: need to implement this function... @@ -336,273 +410,273 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // notifyListeners(); } - void updateChatHistoryWindow(List? args) { - dynamic items = args!.toList(); - if (kDebugMode) { - logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); - } - logger.d(items); - // for (var user in searchedChats!) { - // if (user.id == items.first["id"]) { - // user.userStatus = items.first["userStatus"]; - // } - // } - // notifyListeners(); - } - - void chatNotDelivered(List? args) { - dynamic items = args!.toList(); - for (dynamic item in items[0]) { - for (ChatUser element in searchedChats!) { - if (element.id == item["currentUserId"]) { - int? val = element.unreadMessageCount ?? 0; - element.unreadMessageCount = val! + 1; - } - } - } - notifyListeners(); - } - - void changeStatus(List? args) { - dynamic items = args!.toList(); - for (ChatUser user in searchedChats!) { - 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"]; - } - } - } - - notifyListeners(); - } - - void filter(String value) async { - List? tmp = []; - if (value.isEmpty || value == "") { - tmp = pChatHistory; - } else { - for (ChatUser element in pChatHistory!) { - if (element.userName!.toLowerCase().contains(value.toLowerCase())) { - tmp.add(element); - } - } - } - searchedChats = tmp; - notifyListeners(); - } - - Future onMsgReceived(List? parameters) async { - List data = [], temp = []; - for (dynamic msg in parameters!) { - data = getSingleUserChatModel(jsonEncode(msg)); - temp = getSingleUserChatModel(jsonEncode(msg)); - data.first.targetUserId = temp.first.currentUserId; - data.first.targetUserName = temp.first.currentUserName; - data.first.targetUserEmail = temp.first.currentUserEmail; - data.first.currentUserId = temp.first.targetUserId; - data.first.currentUserName = temp.first.targetUserName; - data.first.currentUserEmail = temp.first.targetUserEmail; - - if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { - data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); - } - if (data.first.userChatReplyResponse != null) { - if (data.first.fileTypeResponse != null) { - if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { - data.first.userChatReplyResponse!.image = await ChatApiClient() - .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); - data.first.userChatReplyResponse!.isImageLoaded = true; - } - } - } - } - - if (searchedChats != null) { - dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); - if (contain.isEmpty) { - List emails = []; - emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); - List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - searchedChats!.add( - ChatUser( - id: data.first.currentUserId, - userName: data.first.currentUserName, - email: data.first.currentUserEmail, - unreadMessageCount: 0, - isImageLoading: false, - image: chatImages!.first.profilePicture ?? "", - isImageLoaded: true, - userStatus: 1, - isTyping: false, - userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), - ), - ); - } - } - setMsgTune(); - if (isChatScreenActive && data.first.currentUserId == receiverID) { - userChatHistory.insert(0, data.first); - } else { - if (searchedChats != null) { - for (ChatUser user in searchedChats!) { - if (user.id == data.first.currentUserId) { - int tempCount = user.unreadMessageCount ?? 0; - user.unreadMessageCount = tempCount + 1; - } - } - sort(); - } - } - - List list = [ - { - "userChatHistoryId": data.first.userChatHistoryId, - "TargetUserId": temp.first.targetUserId, - "isDelivered": true, - "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false - } - ]; - updateUserChatHistoryOnMsg(list); - invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - notifyListeners(); - } - - Future onGroupMsgReceived(List? parameters) async { - List data = [], temp = []; - - for (dynamic msg in parameters!) { - // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); - data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); - temp = data; - // data.first.currentUserId = temp.first.currentUserId; - // data.first.currentUserName = temp.first.currentUserName; - // - // data.first.currentUserId = temp.first.currentUserId; - // data.first.currentUserName = temp.first.currentUserName; - - if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { - data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); - } - if (data.first.groupChatReplyResponse != null) { - if (data.first.fileTypeResponse != null) { - if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { - data.first.groupChatReplyResponse!.image = await ChatApiClient() - .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); - data.first.groupChatReplyResponse!.isImageLoaded = true; - } - } - } - } - - // if (searchedChats != null) { - // dynamic contain = searchedChats! - // .where((ChatUser element) => element.id == data.first.currentUserId); - // if (contain.isEmpty) { - // List emails = []; - // emails.add(await EmailImageEncryption() - // .encrypt(val: data.first.currentUserEmail!)); - // List chatImages = - // await ChatApiClient().getUsersImages(encryptedEmails: emails); - // searchedChats!.add( - // ChatUser( - // id: data.first.currentUserId, - // userName: data.first.currentUserName, - // email: data.first.currentUserEmail, - // unreadMessageCount: 0, - // isImageLoading: false, - // image: chatImages!.first.profilePicture ?? "", - // isImageLoaded: true, - // userStatus: 1, - // isTyping: false, - // userLocalDownlaodedImage: await downloadImageLocal( - // chatImages.first.profilePicture, - // data.first.currentUserId.toString()), - // ), - // ); - // } - // } - groupChatHistory.insert(0, data.first); - setMsgTune(); - // if (isChatScreenActive && data.first.currentUserId == receiverID) { - - // } else { - // if (searchedChats != null) { - // for (ChatUser user in searchedChats!) { - // if (user.id == data.first.currentUserId) { - // int tempCount = user.unreadMessageCount ?? 0; - // user.unreadMessageCount = tempCount + 1; - // } - // } - sort(); - //} - //} - // - // List list = [ - // { - // "userChatHistoryId": data.first.groupId, - // "TargetUserId": temp.first.currentUserId, - // "isDelivered": true, - // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID - // ? true - // : false - // } - // ]; - // updateUserChatHistoryOnMsg(list); - // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - notifyListeners(); - } - - void OnSubmitChatAsync(List? parameters) { - print(isChatScreenActive); - print(receiverID); - print(isChatScreenActive); - logger.i(parameters); - List data = [], temp = []; - for (dynamic msg in parameters!) { - data = getSingleUserChatModel(jsonEncode(msg)); - temp = getSingleUserChatModel(jsonEncode(msg)); - data.first.targetUserId = temp.first.currentUserId; - data.first.targetUserName = temp.first.currentUserName; - data.first.targetUserEmail = temp.first.currentUserEmail; - data.first.currentUserId = temp.first.targetUserId; - data.first.currentUserName = temp.first.targetUserName; - data.first.currentUserEmail = temp.first.targetUserEmail; - } - if (isChatScreenActive && data.first.currentUserId == receiverID) { - int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); - logger.d(index); - userChatHistory[index] = data.first; - } - - notifyListeners(); - } - - void sort() { - searchedChats!.sort( - (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), - ); - } - - void onUserTyping(List? parameters) { - for (ChatUser user in searchedChats!) { - if (user.id == parameters![1] && parameters[0] == true) { - user.isTyping = parameters[0] as bool?; - Future.delayed( - const Duration(seconds: 2), - () { - user.isTyping = false; - notifyListeners(); - }, - ); - } - } - notifyListeners(); - } + // void updateChatHistoryWindow(List? args) { + // dynamic items = args!.toList(); + // if (kDebugMode) { + // logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); + // } + // logger.d(items); + // // for (var user in searchedChats!) { + // // if (user.id == items.first["id"]) { + // // user.userStatus = items.first["userStatus"]; + // // } + // // } + // // notifyListeners(); + // } + + // void chatNotDelivered(List? args) { + // dynamic items = args!.toList(); + // for (dynamic item in items[0]) { + // for (ChatUser element in searchedChats!) { + // if (element.id == item["currentUserId"]) { + // int? val = element.unreadMessageCount ?? 0; + // element.unreadMessageCount = val! + 1; + // } + // } + // } + // notifyListeners(); + // } + // + // void changeStatus(List? args) { + // dynamic items = args!.toList(); + // for (ChatUser user in searchedChats!) { + // 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"]; + // } + // } + // } + // + // notifyListeners(); + // } + // + // void filter(String value) async { + // List? tmp = []; + // if (value.isEmpty || value == "") { + // tmp = pChatHistory; + // } else { + // for (ChatUser element in pChatHistory!) { + // if (element.userName!.toLowerCase().contains(value.toLowerCase())) { + // tmp.add(element); + // } + // } + // } + // searchedChats = tmp; + // notifyListeners(); + // } + + // Future onMsgReceived(List? parameters) async { + // List data = [], temp = []; + // for (dynamic msg in parameters!) { + // data = getSingleUserChatModel(jsonEncode(msg)); + // temp = getSingleUserChatModel(jsonEncode(msg)); + // data.first.targetUserId = temp.first.currentUserId; + // data.first.targetUserName = temp.first.currentUserName; + // data.first.targetUserEmail = temp.first.currentUserEmail; + // data.first.currentUserId = temp.first.targetUserId; + // data.first.currentUserName = temp.first.targetUserName; + // data.first.currentUserEmail = temp.first.targetUserEmail; + // + // if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { + // data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); + // } + // if (data.first.userChatReplyResponse != null) { + // if (data.first.fileTypeResponse != null) { + // if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { + // data.first.userChatReplyResponse!.image = await ChatApiClient() + // .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); + // data.first.userChatReplyResponse!.isImageLoaded = true; + // } + // } + // } + // } + // + // if (searchedChats != null) { + // dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); + // if (contain.isEmpty) { + // List emails = []; + // emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); + // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + // searchedChats!.add( + // ChatUser( + // id: data.first.currentUserId, + // userName: data.first.currentUserName, + // email: data.first.currentUserEmail, + // unreadMessageCount: 0, + // isImageLoading: false, + // image: chatImages!.first.profilePicture ?? "", + // isImageLoaded: true, + // userStatus: 1, + // isTyping: false, + // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), + // ), + // ); + // } + // } + // setMsgTune(); + // if (isChatScreenActive && data.first.currentUserId == receiverID) { + // userChatHistory.insert(0, data.first); + // } else { + // if (searchedChats != null) { + // for (ChatUser user in searchedChats!) { + // if (user.id == data.first.currentUserId) { + // int tempCount = user.unreadMessageCount ?? 0; + // user.unreadMessageCount = tempCount + 1; + // } + // } + // sort(); + // } + // } + // + // List list = [ + // { + // "userChatHistoryId": data.first.userChatHistoryId, + // "TargetUserId": temp.first.targetUserId, + // "isDelivered": true, + // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false + // } + // ]; + // updateUserChatHistoryOnMsg(list); + // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + // notifyListeners(); + // } + + // Future onGroupMsgReceived(List? parameters) async { + // List data = [], temp = []; + // + // for (dynamic msg in parameters!) { + // // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); + // data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); + // temp = data; + // // data.first.currentUserId = temp.first.currentUserId; + // // data.first.currentUserName = temp.first.currentUserName; + // // + // // data.first.currentUserId = temp.first.currentUserId; + // // data.first.currentUserName = temp.first.currentUserName; + // + // if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { + // data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); + // } + // if (data.first.groupChatReplyResponse != null) { + // if (data.first.fileTypeResponse != null) { + // if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { + // data.first.groupChatReplyResponse!.image = await ChatApiClient() + // .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); + // data.first.groupChatReplyResponse!.isImageLoaded = true; + // } + // } + // } + // } + // + // // if (searchedChats != null) { + // // dynamic contain = searchedChats! + // // .where((ChatUser element) => element.id == data.first.currentUserId); + // // if (contain.isEmpty) { + // // List emails = []; + // // emails.add(await EmailImageEncryption() + // // .encrypt(val: data.first.currentUserEmail!)); + // // List chatImages = + // // await ChatApiClient().getUsersImages(encryptedEmails: emails); + // // searchedChats!.add( + // // ChatUser( + // // id: data.first.currentUserId, + // // userName: data.first.currentUserName, + // // email: data.first.currentUserEmail, + // // unreadMessageCount: 0, + // // isImageLoading: false, + // // image: chatImages!.first.profilePicture ?? "", + // // isImageLoaded: true, + // // userStatus: 1, + // // isTyping: false, + // // userLocalDownlaodedImage: await downloadImageLocal( + // // chatImages.first.profilePicture, + // // data.first.currentUserId.toString()), + // // ), + // // ); + // // } + // // } + // groupChatHistory.insert(0, data.first); + // setMsgTune(); + // // if (isChatScreenActive && data.first.currentUserId == receiverID) { + // + // // } else { + // // if (searchedChats != null) { + // // for (ChatUser user in searchedChats!) { + // // if (user.id == data.first.currentUserId) { + // // int tempCount = user.unreadMessageCount ?? 0; + // // user.unreadMessageCount = tempCount + 1; + // // } + // // } + // sort(); + // //} + // //} + // // + // // List list = [ + // // { + // // "userChatHistoryId": data.first.groupId, + // // "TargetUserId": temp.first.currentUserId, + // // "isDelivered": true, + // // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID + // // ? true + // // : false + // // } + // // ]; + // // updateUserChatHistoryOnMsg(list); + // // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + // notifyListeners(); + // } + + // void OnSubmitChatAsync(List? parameters) { + // print(isChatScreenActive); + // print(receiverID); + // print(isChatScreenActive); + // logger.i(parameters); + // List data = [], temp = []; + // for (dynamic msg in parameters!) { + // data = getSingleUserChatModel(jsonEncode(msg)); + // temp = getSingleUserChatModel(jsonEncode(msg)); + // data.first.targetUserId = temp.first.currentUserId; + // data.first.targetUserName = temp.first.currentUserName; + // data.first.targetUserEmail = temp.first.currentUserEmail; + // data.first.currentUserId = temp.first.targetUserId; + // data.first.currentUserName = temp.first.targetUserName; + // data.first.currentUserEmail = temp.first.targetUserEmail; + // } + // if (isChatScreenActive && data.first.currentUserId == receiverID) { + // int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); + // logger.d(index); + // userChatHistory[index] = data.first; + // } + // + // notifyListeners(); + // } + + // void sort() { + // searchedChats!.sort( + // (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), + // ); + // } + + // void onUserTyping(List? parameters) { + // for (ChatUser user in searchedChats!) { + // if (user.id == parameters![1] && parameters[0] == true) { + // user.isTyping = parameters[0] as bool?; + // Future.delayed( + // const Duration(seconds: 2), + // () { + // user.isTyping = false; + // notifyListeners(); + // }, + // ); + // } + // } + // notifyListeners(); + // } int getFileType(String value) { switch (value) { @@ -696,577 +770,577 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { } } - Future sendChatToServer( - {required int chatEventId, - required fileTypeId, - required int targetUserId, - required String targetUserName, - required chatReplyId, - required bool isAttachment, - required bool isReply, - Uint8List? image, - required bool isImageLoaded, - String? userEmail, - int? userStatus, - File? voiceFile, - required bool isVoiceAttached}) async { - Uuid uuid = const Uuid(); - String contentNo = uuid.v4(); - String msg; - if (isVoiceAttached) { - msg = voiceFile!.path.split("/").last; - } else { - msg = message.text; - logger.w(msg); - } - SingleUserChatModel data = SingleUserChatModel( - userChatHistoryId: 0, - chatEventId: chatEventId, - chatSource: 1, - contant: msg, - contantNo: contentNo, - conversationId: chatCID, - createdDate: DateTime.now(), - currentUserId: AppState().chatDetails!.response!.id, - currentUserName: AppState().chatDetails!.response!.userName, - targetUserId: targetUserId, - targetUserName: targetUserName, - isReplied: false, - fileTypeId: fileTypeId, - userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, - fileTypeResponse: isAttachment - ? FileTypeResponse( - fileTypeId: fileTypeId, - fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), - fileKind: "file", - fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, - fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), - ) - : null, - image: image, - isImageLoaded: isImageLoaded, - voice: isVoiceMsg ? voiceFile! : null, - voiceController: isVoiceMsg ? AudioPlayer() : null); - if (kDebugMode) { - logger.i("model data: " + jsonEncode(data)); - } - userChatHistory.insert(0, data); - isTextMsg = false; - isReplyMsg = false; - isAttachmentMsg = false; - isVoiceMsg = false; - sFileType = ""; - message.clear(); - notifyListeners(); - - String chatData = - '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; - - await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); - } + // Future sendChatToServer( + // {required int chatEventId, + // required fileTypeId, + // required int targetUserId, + // required String targetUserName, + // required chatReplyId, + // required bool isAttachment, + // required bool isReply, + // Uint8List? image, + // required bool isImageLoaded, + // String? userEmail, + // int? userStatus, + // File? voiceFile, + // required bool isVoiceAttached}) async { + // Uuid uuid = const Uuid(); + // String contentNo = uuid.v4(); + // String msg; + // if (isVoiceAttached) { + // msg = voiceFile!.path.split("/").last; + // } else { + // msg = message.text; + // logger.w(msg); + // } + // SingleUserChatModel data = SingleUserChatModel( + // userChatHistoryId: 0, + // chatEventId: chatEventId, + // chatSource: 1, + // contant: msg, + // contantNo: contentNo, + // conversationId: chatCID, + // createdDate: DateTime.now(), + // currentUserId: AppState().chatDetails!.response!.id, + // currentUserName: AppState().chatDetails!.response!.userName, + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // isReplied: false, + // fileTypeId: fileTypeId, + // userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, + // fileTypeResponse: isAttachment + // ? FileTypeResponse( + // fileTypeId: fileTypeId, + // fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), + // fileKind: "file", + // fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, + // fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), + // ) + // : null, + // image: image, + // isImageLoaded: isImageLoaded, + // voice: isVoiceMsg ? voiceFile! : null, + // voiceController: isVoiceMsg ? AudioPlayer() : null); + // if (kDebugMode) { + // logger.i("model data: " + jsonEncode(data)); + // } + // userChatHistory.insert(0, data); + // isTextMsg = false; + // isReplyMsg = false; + // isAttachmentMsg = false; + // isVoiceMsg = false; + // sFileType = ""; + // message.clear(); + // notifyListeners(); + // + // String chatData = + // '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; + // + // await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); + // } //groupChatMessage - Future sendGroupChatToServer( - {required int chatEventId, - required fileTypeId, - required int targetGroupId, - required String targetUserName, - required chatReplyId, - required bool isAttachment, - required bool isReply, - Uint8List? image, - required bool isImageLoaded, - String? userEmail, - int? userStatus, - File? voiceFile, - required bool isVoiceAttached, - required List userList}) async { - Uuid uuid = const Uuid(); - String contentNo = uuid.v4(); - String msg; - if (isVoiceAttached) { - msg = voiceFile!.path.split("/").last; - } else { - msg = message.text; - logger.w(msg); - } - groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( - //userChatHistoryId: 0, - chatEventId: chatEventId, - chatSource: 1, - contant: msg, - contantNo: contentNo, - conversationId: chatCID, - createdDate: DateTime.now().toString(), - currentUserId: AppState().chatDetails!.response!.id, - currentUserName: AppState().chatDetails!.response!.userName, - groupId: targetGroupId, - groupName: targetUserName, - isReplied: false, - fileTypeId: fileTypeId, - fileTypeResponse: isAttachment - ? groupchathistory.FileTypeResponse( - fileTypeId: fileTypeId, - fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), - fileKind: "file", - fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, - fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) - : null, - image: image, - isImageLoaded: isImageLoaded, - voice: isVoiceMsg ? voiceFile! : null, - voiceController: isVoiceMsg ? AudioPlayer() : null); - if (kDebugMode) { - logger.i("model data: " + jsonEncode(data)); - } - groupChatHistory.insert(0, data); - isTextMsg = false; - isReplyMsg = false; - isAttachmentMsg = false; - isVoiceMsg = false; - sFileType = ""; - message.clear(); - notifyListeners(); - - List targetUsers = []; - - for (GroupUserList element in userList) { - targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); - } - - String chatData = - '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; - - await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); - } - - void sendGroupChatMessage( - BuildContext context, { - required int targetUserId, - required int userStatus, - required String userEmail, - required String targetUserName, - required List userList, - }) async { - if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - logger.d("// Normal Text Message"); - if (message.text.isEmpty) { - return; - } - sendGroupChatToServer( - chatEventId: 1, - fileTypeId: null, - targetGroupId: targetUserId, - targetUserName: targetUserName, - isAttachment: false, - chatReplyId: null, - isReply: false, - isImageLoaded: false, - image: null, - isVoiceAttached: false, - userEmail: userEmail, - userStatus: userStatus, - userList: userList); - } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - logger.d("// Text Message as Reply"); - if (message.text.isEmpty) { - return; - } - sendGroupChatToServer( - chatEventId: 1, - fileTypeId: null, - targetGroupId: targetUserId, - targetUserName: targetUserName, - chatReplyId: groupChatReplyData.first.groupChatHistoryId, - isAttachment: false, - isReply: true, - isImageLoaded: groupChatReplyData.first.isImageLoaded!, - image: groupChatReplyData.first.image, - isVoiceAttached: false, - voiceFile: null, - userEmail: userEmail, - userStatus: userStatus, - userList: userList); - } - // Attachment - else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - logger.d("// Normal Image Message"); - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); - String? ext = getFileExtension(selectedFile.path); - Utils.hideLoading(context); - sendGroupChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetGroupId: targetUserId, - targetUserName: targetUserName, - isAttachment: true, - chatReplyId: null, - isReply: false, - isImageLoaded: true, - image: selectedFile.readAsBytesSync(), - isVoiceAttached: false, - userEmail: userEmail, - userStatus: userStatus, - userList: userList); - } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - logger.d("// Image as Reply Msg"); - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); - String? ext = getFileExtension(selectedFile.path); - Utils.hideLoading(context); - sendGroupChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetGroupId: targetUserId, - targetUserName: targetUserName, - isAttachment: true, - chatReplyId: repliedMsg.first.userChatHistoryId, - isReply: true, - isImageLoaded: true, - image: selectedFile.readAsBytesSync(), - isVoiceAttached: false, - userEmail: userEmail, - userStatus: userStatus, - userList: userList); - } - //Voice - - else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { - logger.d("// Normal Voice Message"); - - if (!isPause) { - path = await recorderController.stop(false); - } - if (kDebugMode) { - logger.i("path:" + path!); - } - File voiceFile = File(path!); - voiceFile.readAsBytesSync(); - _timer?.cancel(); - isPause = false; - isPlaying = false; - isRecoding = false; - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); - String? ext = getFileExtension(voiceFile.path); - Utils.hideLoading(context); - sendGroupChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - //, - targetGroupId: targetUserId, - targetUserName: targetUserName, - chatReplyId: null, - isAttachment: true, - isReply: isReplyMsg, - isImageLoaded: false, - voiceFile: voiceFile, - isVoiceAttached: true, - userEmail: userEmail, - userStatus: userStatus, - userList: userList); - notifyListeners(); - } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { - logger.d("// Voice as Reply Msg"); - - if (!isPause) { - path = await recorderController.stop(false); - } - if (kDebugMode) { - logger.i("path:" + path!); - } - File voiceFile = File(path!); - voiceFile.readAsBytesSync(); - _timer?.cancel(); - isPause = false; - isPlaying = false; - isRecoding = false; - - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); - String? ext = getFileExtension(voiceFile.path); - Utils.hideLoading(context); - sendGroupChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetGroupId: targetUserId, - targetUserName: targetUserName, - chatReplyId: null, - isAttachment: true, - isReply: isReplyMsg, - isImageLoaded: false, - voiceFile: voiceFile, - isVoiceAttached: true, - userEmail: userEmail, - userStatus: userStatus, - userList: userList); - notifyListeners(); - } - if (searchedChats != null) { - dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); - if (contain.isEmpty) { - List emails = []; - emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - searchedChats!.add( - ChatUser( - id: targetUserId, - userName: targetUserName, - unreadMessageCount: 0, - email: userEmail, - isImageLoading: false, - image: chatImages.first.profilePicture ?? "", - isImageLoaded: true, - isTyping: false, - isFav: false, - userStatus: userStatus, - // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), - ), - ); - notifyListeners(); - } - } - } - - void sendChatMessage( - BuildContext context, { - required int targetUserId, - required int userStatus, - required String userEmail, - required String targetUserName, - }) async { - if (kDebugMode) { - print("====================== Values ============================"); - print("Is Text " + isTextMsg.toString()); - print("isReply " + isReplyMsg.toString()); - print("isAttachment " + isAttachmentMsg.toString()); - print("isVoice " + isVoiceMsg.toString()); - } - //Text - if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - logger.d("// Normal Text Message"); - if (message.text.isEmpty) { - return; - } - sendChatToServer( - chatEventId: 1, - fileTypeId: null, - targetUserId: targetUserId, - targetUserName: targetUserName, - isAttachment: false, - chatReplyId: null, - isReply: false, - isImageLoaded: false, - image: null, - isVoiceAttached: false, - userEmail: userEmail, - userStatus: userStatus); - } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - logger.d("// Text Message as Reply"); - if (message.text.isEmpty) { - return; - } - sendChatToServer( - chatEventId: 1, - fileTypeId: null, - targetUserId: targetUserId, - targetUserName: targetUserName, - chatReplyId: repliedMsg.first.userChatHistoryId, - isAttachment: false, - isReply: true, - isImageLoaded: repliedMsg.first.isImageLoaded!, - image: repliedMsg.first.image, - isVoiceAttached: false, - voiceFile: null, - userEmail: userEmail, - userStatus: userStatus); - } - // Attachment - else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - logger.d("// Normal Image Message"); - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); - String? ext = getFileExtension(selectedFile.path); - Utils.hideLoading(context); - sendChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetUserId: targetUserId, - targetUserName: targetUserName, - isAttachment: true, - chatReplyId: null, - isReply: false, - isImageLoaded: true, - image: selectedFile.readAsBytesSync(), - isVoiceAttached: false, - userEmail: userEmail, - userStatus: userStatus); - } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - logger.d("// Image as Reply Msg"); - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); - String? ext = getFileExtension(selectedFile.path); - Utils.hideLoading(context); - sendChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetUserId: targetUserId, - targetUserName: targetUserName, - isAttachment: true, - chatReplyId: repliedMsg.first.userChatHistoryId, - isReply: true, - isImageLoaded: true, - image: selectedFile.readAsBytesSync(), - isVoiceAttached: false, - userEmail: userEmail, - userStatus: userStatus); - } - //Voice - - else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { - logger.d("// Normal Voice Message"); - - if (!isPause) { - path = await recorderController.stop(false); - } - if (kDebugMode) { - logger.i("path:" + path!); - } - File voiceFile = File(path!); - voiceFile.readAsBytesSync(); - _timer?.cancel(); - isPause = false; - isPlaying = false; - isRecoding = false; - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); - String? ext = getFileExtension(voiceFile.path); - Utils.hideLoading(context); - sendChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetUserId: targetUserId, - targetUserName: targetUserName, - chatReplyId: null, - isAttachment: true, - isReply: isReplyMsg, - isImageLoaded: false, - voiceFile: voiceFile, - isVoiceAttached: true, - userEmail: userEmail, - userStatus: userStatus); - notifyListeners(); - } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { - logger.d("// Voice as Reply Msg"); - - if (!isPause) { - path = await recorderController.stop(false); - } - if (kDebugMode) { - logger.i("path:" + path!); - } - File voiceFile = File(path!); - voiceFile.readAsBytesSync(); - _timer?.cancel(); - isPause = false; - isPlaying = false; - isRecoding = false; - - Utils.showLoading(context); - dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); - String? ext = getFileExtension(voiceFile.path); - Utils.hideLoading(context); - sendChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetUserId: targetUserId, - targetUserName: targetUserName, - chatReplyId: null, - isAttachment: true, - isReply: isReplyMsg, - isImageLoaded: false, - voiceFile: voiceFile, - isVoiceAttached: true, - userEmail: userEmail, - userStatus: userStatus); - notifyListeners(); - } - if (searchedChats != null) { - dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); - if (contain.isEmpty) { - List emails = []; - emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - searchedChats!.add( - ChatUser( - id: targetUserId, - userName: targetUserName, - unreadMessageCount: 0, - email: userEmail, - isImageLoading: false, - image: chatImages.first.profilePicture ?? "", - isImageLoaded: true, - isTyping: false, - isFav: false, - userStatus: userStatus, - userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), - ), - ); - notifyListeners(); - } - } - // else { - // List emails = []; - // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - // searchedChats!.add( - // ChatUser( - // id: targetUserId, - // userName: targetUserName, - // unreadMessageCount: 0, - // email: userEmail, - // isImageLoading: false, - // image: chatImages.first.profilePicture ?? "", - // isImageLoaded: true, - // isTyping: false, - // isFav: false, - // userStatus: userStatus, - // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), - // ), - // ); - // notifyListeners(); - // } - } - - void selectImageToUpload(BuildContext context) { - ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { - if (checkFileSize(file.path)) { - selectedFile = file; - isAttachmentMsg = true; - isTextMsg = false; - sFileType = getFileExtension(file.path)!; - message.text = file.path.split("/").last; - Navigator.of(context).pop(); - } else { - Utils.showToast("Max 1 mb size is allowed to upload"); - } - notifyListeners(); - }); - } - - void removeAttachment() { - isAttachmentMsg = false; - sFileType = ""; - message.text = ''; - notifyListeners(); - } + // Future sendGroupChatToServer( + // {required int chatEventId, + // required fileTypeId, + // required int targetGroupId, + // required String targetUserName, + // required chatReplyId, + // required bool isAttachment, + // required bool isReply, + // Uint8List? image, + // required bool isImageLoaded, + // String? userEmail, + // int? userStatus, + // File? voiceFile, + // required bool isVoiceAttached, + // required List userList}) async { + // Uuid uuid = const Uuid(); + // String contentNo = uuid.v4(); + // String msg; + // if (isVoiceAttached) { + // msg = voiceFile!.path.split("/").last; + // } else { + // msg = message.text; + // logger.w(msg); + // } + // groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( + // //userChatHistoryId: 0, + // chatEventId: chatEventId, + // chatSource: 1, + // contant: msg, + // contantNo: contentNo, + // conversationId: chatCID, + // createdDate: DateTime.now().toString(), + // currentUserId: AppState().chatDetails!.response!.id, + // currentUserName: AppState().chatDetails!.response!.userName, + // groupId: targetGroupId, + // groupName: targetUserName, + // isReplied: false, + // fileTypeId: fileTypeId, + // fileTypeResponse: isAttachment + // ? groupchathistory.FileTypeResponse( + // fileTypeId: fileTypeId, + // fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), + // fileKind: "file", + // fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, + // fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) + // : null, + // image: image, + // isImageLoaded: isImageLoaded, + // voice: isVoiceMsg ? voiceFile! : null, + // voiceController: isVoiceMsg ? AudioPlayer() : null); + // if (kDebugMode) { + // logger.i("model data: " + jsonEncode(data)); + // } + // groupChatHistory.insert(0, data); + // isTextMsg = false; + // isReplyMsg = false; + // isAttachmentMsg = false; + // isVoiceMsg = false; + // sFileType = ""; + // message.clear(); + // notifyListeners(); + // + // List targetUsers = []; + // + // for (GroupUserList element in userList) { + // targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); + // } + // + // String chatData = + // '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; + // + // await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); + // } + + // void sendGroupChatMessage( + // BuildContext context, { + // required int targetUserId, + // required int userStatus, + // required String userEmail, + // required String targetUserName, + // required List userList, + // }) async { + // if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + // logger.d("// Normal Text Message"); + // if (message.text.isEmpty) { + // return; + // } + // sendGroupChatToServer( + // chatEventId: 1, + // fileTypeId: null, + // targetGroupId: targetUserId, + // targetUserName: targetUserName, + // isAttachment: false, + // chatReplyId: null, + // isReply: false, + // isImageLoaded: false, + // image: null, + // isVoiceAttached: false, + // userEmail: userEmail, + // userStatus: userStatus, + // userList: userList); + // } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + // logger.d("// Text Message as Reply"); + // if (message.text.isEmpty) { + // return; + // } + // sendGroupChatToServer( + // chatEventId: 1, + // fileTypeId: null, + // targetGroupId: targetUserId, + // targetUserName: targetUserName, + // chatReplyId: groupChatReplyData.first.groupChatHistoryId, + // isAttachment: false, + // isReply: true, + // isImageLoaded: groupChatReplyData.first.isImageLoaded!, + // image: groupChatReplyData.first.image, + // isVoiceAttached: false, + // voiceFile: null, + // userEmail: userEmail, + // userStatus: userStatus, + // userList: userList); + // } + // // Attachment + // else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + // logger.d("// Normal Image Message"); + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); + // String? ext = getFileExtension(selectedFile.path); + // Utils.hideLoading(context); + // sendGroupChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // targetGroupId: targetUserId, + // targetUserName: targetUserName, + // isAttachment: true, + // chatReplyId: null, + // isReply: false, + // isImageLoaded: true, + // image: selectedFile.readAsBytesSync(), + // isVoiceAttached: false, + // userEmail: userEmail, + // userStatus: userStatus, + // userList: userList); + // } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + // logger.d("// Image as Reply Msg"); + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); + // String? ext = getFileExtension(selectedFile.path); + // Utils.hideLoading(context); + // sendGroupChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // targetGroupId: targetUserId, + // targetUserName: targetUserName, + // isAttachment: true, + // chatReplyId: repliedMsg.first.userChatHistoryId, + // isReply: true, + // isImageLoaded: true, + // image: selectedFile.readAsBytesSync(), + // isVoiceAttached: false, + // userEmail: userEmail, + // userStatus: userStatus, + // userList: userList); + // } + // //Voice + // + // else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { + // logger.d("// Normal Voice Message"); + // + // if (!isPause) { + // path = await recorderController.stop(false); + // } + // if (kDebugMode) { + // logger.i("path:" + path!); + // } + // File voiceFile = File(path!); + // voiceFile.readAsBytesSync(); + // _timer?.cancel(); + // isPause = false; + // isPlaying = false; + // isRecoding = false; + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); + // String? ext = getFileExtension(voiceFile.path); + // Utils.hideLoading(context); + // sendGroupChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // //, + // targetGroupId: targetUserId, + // targetUserName: targetUserName, + // chatReplyId: null, + // isAttachment: true, + // isReply: isReplyMsg, + // isImageLoaded: false, + // voiceFile: voiceFile, + // isVoiceAttached: true, + // userEmail: userEmail, + // userStatus: userStatus, + // userList: userList); + // notifyListeners(); + // } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { + // logger.d("// Voice as Reply Msg"); + // + // if (!isPause) { + // path = await recorderController.stop(false); + // } + // if (kDebugMode) { + // logger.i("path:" + path!); + // } + // File voiceFile = File(path!); + // voiceFile.readAsBytesSync(); + // _timer?.cancel(); + // isPause = false; + // isPlaying = false; + // isRecoding = false; + // + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); + // String? ext = getFileExtension(voiceFile.path); + // Utils.hideLoading(context); + // sendGroupChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // targetGroupId: targetUserId, + // targetUserName: targetUserName, + // chatReplyId: null, + // isAttachment: true, + // isReply: isReplyMsg, + // isImageLoaded: false, + // voiceFile: voiceFile, + // isVoiceAttached: true, + // userEmail: userEmail, + // userStatus: userStatus, + // userList: userList); + // notifyListeners(); + // } + // if (searchedChats != null) { + // dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); + // if (contain.isEmpty) { + // List emails = []; + // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); + // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + // searchedChats!.add( + // ChatUser( + // id: targetUserId, + // userName: targetUserName, + // unreadMessageCount: 0, + // email: userEmail, + // isImageLoading: false, + // image: chatImages.first.profilePicture ?? "", + // isImageLoaded: true, + // isTyping: false, + // isFav: false, + // userStatus: userStatus, + // // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + // ), + // ); + // notifyListeners(); + // } + // } + // } + + // void sendChatMessage( + // BuildContext context, { + // required int targetUserId, + // required int userStatus, + // required String userEmail, + // required String targetUserName, + // }) async { + // if (kDebugMode) { + // print("====================== Values ============================"); + // print("Is Text " + isTextMsg.toString()); + // print("isReply " + isReplyMsg.toString()); + // print("isAttachment " + isAttachmentMsg.toString()); + // print("isVoice " + isVoiceMsg.toString()); + // } + // //Text + // if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + // // logger.d("// Normal Text Message"); + // if (message.text.isEmpty) { + // return; + // } + // sendChatToServer( + // chatEventId: 1, + // fileTypeId: null, + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // isAttachment: false, + // chatReplyId: null, + // isReply: false, + // isImageLoaded: false, + // image: null, + // isVoiceAttached: false, + // userEmail: userEmail, + // userStatus: userStatus); + // } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + // logger.d("// Text Message as Reply"); + // if (message.text.isEmpty) { + // return; + // } + // sendChatToServer( + // chatEventId: 1, + // fileTypeId: null, + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // chatReplyId: repliedMsg.first.userChatHistoryId, + // isAttachment: false, + // isReply: true, + // isImageLoaded: repliedMsg.first.isImageLoaded!, + // image: repliedMsg.first.image, + // isVoiceAttached: false, + // voiceFile: null, + // userEmail: userEmail, + // userStatus: userStatus); + // } + // // Attachment + // else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { + // logger.d("// Normal Image Message"); + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); + // String? ext = getFileExtension(selectedFile.path); + // Utils.hideLoading(context); + // sendChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // isAttachment: true, + // chatReplyId: null, + // isReply: false, + // isImageLoaded: true, + // image: selectedFile.readAsBytesSync(), + // isVoiceAttached: false, + // userEmail: userEmail, + // userStatus: userStatus); + // } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { + // logger.d("// Image as Reply Msg"); + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); + // String? ext = getFileExtension(selectedFile.path); + // Utils.hideLoading(context); + // sendChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // isAttachment: true, + // chatReplyId: repliedMsg.first.userChatHistoryId, + // isReply: true, + // isImageLoaded: true, + // image: selectedFile.readAsBytesSync(), + // isVoiceAttached: false, + // userEmail: userEmail, + // userStatus: userStatus); + // } + // //Voice + // + // else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { + // logger.d("// Normal Voice Message"); + // + // if (!isPause) { + // path = await recorderController.stop(false); + // } + // if (kDebugMode) { + // logger.i("path:" + path!); + // } + // File voiceFile = File(path!); + // voiceFile.readAsBytesSync(); + // _timer?.cancel(); + // isPause = false; + // isPlaying = false; + // isRecoding = false; + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); + // String? ext = getFileExtension(voiceFile.path); + // Utils.hideLoading(context); + // sendChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // chatReplyId: null, + // isAttachment: true, + // isReply: isReplyMsg, + // isImageLoaded: false, + // voiceFile: voiceFile, + // isVoiceAttached: true, + // userEmail: userEmail, + // userStatus: userStatus); + // notifyListeners(); + // } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { + // logger.d("// Voice as Reply Msg"); + // + // if (!isPause) { + // path = await recorderController.stop(false); + // } + // if (kDebugMode) { + // logger.i("path:" + path!); + // } + // File voiceFile = File(path!); + // voiceFile.readAsBytesSync(); + // _timer?.cancel(); + // isPause = false; + // isPlaying = false; + // isRecoding = false; + // + // Utils.showLoading(context); + // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); + // String? ext = getFileExtension(voiceFile.path); + // Utils.hideLoading(context); + // sendChatToServer( + // chatEventId: 2, + // fileTypeId: getFileType(ext.toString()), + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // chatReplyId: null, + // isAttachment: true, + // isReply: isReplyMsg, + // isImageLoaded: false, + // voiceFile: voiceFile, + // isVoiceAttached: true, + // userEmail: userEmail, + // userStatus: userStatus); + // notifyListeners(); + // } + // if (searchedChats != null) { + // dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); + // if (contain.isEmpty) { + // List emails = []; + // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); + // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + // searchedChats!.add( + // ChatUser( + // id: targetUserId, + // userName: targetUserName, + // unreadMessageCount: 0, + // email: userEmail, + // isImageLoading: false, + // image: chatImages.first.profilePicture ?? "", + // isImageLoaded: true, + // isTyping: false, + // isFav: false, + // userStatus: userStatus, + // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + // ), + // ); + // notifyListeners(); + // } + // } + // // else { + // // List emails = []; + // // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); + // // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + // // searchedChats!.add( + // // ChatUser( + // // id: targetUserId, + // // userName: targetUserName, + // // unreadMessageCount: 0, + // // email: userEmail, + // // isImageLoading: false, + // // image: chatImages.first.profilePicture ?? "", + // // isImageLoaded: true, + // // isTyping: false, + // // isFav: false, + // // userStatus: userStatus, + // // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), + // // ), + // // ); + // // notifyListeners(); + // // } + // } + + // void selectImageToUpload(BuildContext context) { + // ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { + // if (checkFileSize(file.path)) { + // selectedFile = file; + // isAttachmentMsg = true; + // isTextMsg = false; + // sFileType = getFileExtension(file.path)!; + // message.text = file.path.split("/").last; + // Navigator.of(context).pop(); + // } else { + // Utils.showToast("Max 1 mb size is allowed to upload"); + // } + // notifyListeners(); + // }); + // } + + // void removeAttachment() { + // isAttachmentMsg = false; + // sFileType = ""; + // message.text = ''; + // notifyListeners(); + // } String? getFileExtension(String fileName) { try { if (kDebugMode) { - logger.i("ext: " + "." + fileName.split('.').last); + // logger.i("ext: " + "." + fileName.split('.').last); } return "." + fileName.split('.').last; } catch (e) { @@ -1323,27 +1397,27 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { } } - void chatReply(SingleUserChatModel data) { - repliedMsg = []; - data.isReplied = true; - isReplyMsg = true; - repliedMsg.add(data); - notifyListeners(); - } + // void chatReply(SingleUserChatModel data) { + // repliedMsg = []; + // data.isReplied = true; + // isReplyMsg = true; + // repliedMsg.add(data); + // notifyListeners(); + // } - void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { - groupChatReplyData = []; - data.isReplied = true; - isReplyMsg = true; - groupChatReplyData.add(data); - notifyListeners(); - } + // void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { + // groupChatReplyData = []; + // data.isReplied = true; + // isReplyMsg = true; + // groupChatReplyData.add(data); + // notifyListeners(); + // } - void closeMe() { - repliedMsg = []; - isReplyMsg = false; - notifyListeners(); - } + // void closeMe() { + // repliedMsg = []; + // isReplyMsg = false; + // notifyListeners(); + // } String dateFormte(DateTime data) { DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); @@ -1351,171 +1425,171 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { return f.format(data); } - Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { - fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); - if (favoriteChatUser.response != null) { - for (ChatUser user in searchedChats!) { - if (user.id == favoriteChatUser.response!.targetUserId!) { - user.isFav = favoriteChatUser.response!.isFav; - dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); - if (contain.isEmpty) { - favUsersList.add(user); - } - } - } - - for (ChatUser user in chatUsersList!) { - if (user.id == favoriteChatUser.response!.targetUserId!) { - user.isFav = favoriteChatUser.response!.isFav; - dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); - if (contain.isEmpty) { - favUsersList.add(user); - } - } - } - } - if (fromSearch) { - for (ChatUser user in favUsersList) { - if (user.id == targetUserID) { - user.userLocalDownlaodedImage = null; - user.isImageLoading = false; - user.isImageLoaded = false; - } - } - } - notifyListeners(); - } - - Future unFavoriteUser({required int userID, required int targetUserID}) async { - fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); - - if (favoriteChatUser.response != null) { - for (ChatUser user in searchedChats!) { - if (user.id == favoriteChatUser.response!.targetUserId!) { - user.isFav = favoriteChatUser.response!.isFav; - } - } - favUsersList.removeWhere( - (ChatUser element) => element.id == targetUserID, - ); - } - - for (ChatUser user in chatUsersList!) { - if (user.id == favoriteChatUser.response!.targetUserId!) { - user.isFav = favoriteChatUser.response!.isFav; - } - } - - notifyListeners(); - } - - void clearSelections() { - searchedChats = pChatHistory; - search.clear(); - isChatScreenActive = false; - receiverID = 0; - paginationVal = 0; - message.text = ''; - isAttachmentMsg = false; - repliedMsg = []; - sFileType = ""; - isReplyMsg = false; - isTextMsg = false; - isVoiceMsg = false; - notifyListeners(); - } - - void clearAll() { - searchedChats = pChatHistory; - search.clear(); - isChatScreenActive = false; - receiverID = 0; - paginationVal = 0; - message.text = ''; - isTextMsg = false; - isAttachmentMsg = false; - isVoiceMsg = false; - isReplyMsg = false; - repliedMsg = []; - sFileType = ""; - } - - void disposeData() { - if (!disbaleChatForThisUser) { - search.clear(); - isChatScreenActive = false; - receiverID = 0; - paginationVal = 0; - message.text = ''; - isTextMsg = false; - isAttachmentMsg = false; - isVoiceMsg = false; - isReplyMsg = false; - repliedMsg = []; - sFileType = ""; - deleteData(); - favUsersList.clear(); - searchedChats?.clear(); - pChatHistory?.clear(); - uGroups?.clear(); - searchGroup?.clear(); - chatHubConnection.stop(); - AppState().chatDetails = null; - } - } - - void deleteData() { - List exists = [], unique = []; - if (searchedChats != null) exists.addAll(searchedChats!); - exists.addAll(favUsersList!); - Map profileMap = {}; - for (ChatUser item in exists) { - profileMap[item.email!] = item; - } - unique = profileMap.values.toList(); - for (ChatUser element in unique!) { - deleteFile(element.id.toString()); - } - } - - void getUserImages() async { - List emails = []; - List exists = [], unique = []; - exists.addAll(searchedChats!); - exists.addAll(favUsersList!); - Map profileMap = {}; - for (ChatUser item in exists) { - profileMap[item.email!] = item; - } - unique = profileMap.values.toList(); - for (ChatUser element in unique!) { - emails.add(await EmailImageEncryption().encrypt(val: element.email!)); - } - - List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - for (ChatUser user in searchedChats!) { - for (ChatUserImageModel uImage in chatImages) { - if (user.email == uImage.email) { - user.image = uImage.profilePicture ?? ""; - user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); - user.isImageLoading = false; - user.isImageLoaded = true; - } - } - } - for (ChatUser favUser in favUsersList) { - for (ChatUserImageModel uImage in chatImages) { - if (favUser.email == uImage.email) { - favUser.image = uImage.profilePicture ?? ""; - favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); - favUser.isImageLoading = false; - favUser.isImageLoaded = true; - } - } - } - - notifyListeners(); - } + // Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { + // fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); + // if (favoriteChatUser.response != null) { + // for (ChatUser user in searchedChats!) { + // if (user.id == favoriteChatUser.response!.targetUserId!) { + // user.isFav = favoriteChatUser.response!.isFav; + // dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); + // if (contain.isEmpty) { + // favUsersList.add(user); + // } + // } + // } + // + // for (ChatUser user in chatUsersList!) { + // if (user.id == favoriteChatUser.response!.targetUserId!) { + // user.isFav = favoriteChatUser.response!.isFav; + // dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); + // if (contain.isEmpty) { + // favUsersList.add(user); + // } + // } + // } + // } + // if (fromSearch) { + // for (ChatUser user in favUsersList) { + // if (user.id == targetUserID) { + // user.userLocalDownlaodedImage = null; + // user.isImageLoading = false; + // user.isImageLoaded = false; + // } + // } + // } + // notifyListeners(); + // } + // + // Future unFavoriteUser({required int userID, required int targetUserID}) async { + // fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); + // + // if (favoriteChatUser.response != null) { + // for (ChatUser user in searchedChats!) { + // if (user.id == favoriteChatUser.response!.targetUserId!) { + // user.isFav = favoriteChatUser.response!.isFav; + // } + // } + // favUsersList.removeWhere( + // (ChatUser element) => element.id == targetUserID, + // ); + // } + // + // for (ChatUser user in chatUsersList!) { + // if (user.id == favoriteChatUser.response!.targetUserId!) { + // user.isFav = favoriteChatUser.response!.isFav; + // } + // } + // + // notifyListeners(); + // } + + // void clearSelections() { + // searchedChats = pChatHistory; + // search.clear(); + // isChatScreenActive = false; + // receiverID = 0; + // paginationVal = 0; + // message.text = ''; + // isAttachmentMsg = false; + // repliedMsg = []; + // sFileType = ""; + // isReplyMsg = false; + // isTextMsg = false; + // isVoiceMsg = false; + // notifyListeners(); + // } + // + // void clearAll() { + // searchedChats = pChatHistory; + // search.clear(); + // isChatScreenActive = false; + // receiverID = 0; + // paginationVal = 0; + // message.text = ''; + // isTextMsg = false; + // isAttachmentMsg = false; + // isVoiceMsg = false; + // isReplyMsg = false; + // repliedMsg = []; + // sFileType = ""; + // } + // + // void disposeData() { + // if (!disbaleChatForThisUser) { + // search.clear(); + // isChatScreenActive = false; + // receiverID = 0; + // paginationVal = 0; + // message.text = ''; + // isTextMsg = false; + // isAttachmentMsg = false; + // isVoiceMsg = false; + // isReplyMsg = false; + // repliedMsg = []; + // sFileType = ""; + // deleteData(); + // favUsersList.clear(); + // searchedChats?.clear(); + // pChatHistory?.clear(); + // // uGroups?.clear(); + // searchGroup?.clear(); + // chatHubConnection.stop(); + // // AppState().chatDetails = null; + // } + // } + // + // void deleteData() { + // List exists = [], unique = []; + // if (searchedChats != null) exists.addAll(searchedChats!); + // exists.addAll(favUsersList!); + // Map profileMap = {}; + // for (ChatUser item in exists) { + // profileMap[item.email!] = item; + // } + // unique = profileMap.values.toList(); + // for (ChatUser element in unique!) { + // deleteFile(element.id.toString()); + // } + // } + + // void getUserImages() async { + // List emails = []; + // List exists = [], unique = []; + // exists.addAll(searchedChats!); + // exists.addAll(favUsersList!); + // Map profileMap = {}; + // for (ChatUser item in exists) { + // profileMap[item.email!] = item; + // } + // unique = profileMap.values.toList(); + // for (ChatUser element in unique!) { + // emails.add(await EmailImageEncryption().encrypt(val: element.email!)); + // } + // + // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + // for (ChatUser user in searchedChats!) { + // for (ChatUserImageModel uImage in chatImages) { + // if (user.email == uImage.email) { + // user.image = uImage.profilePicture ?? ""; + // user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); + // user.isImageLoading = false; + // user.isImageLoaded = true; + // } + // } + // } + // for (ChatUser favUser in favUsersList) { + // for (ChatUserImageModel uImage in chatImages) { + // if (favUser.email == uImage.email) { + // favUser.image = uImage.profilePicture ?? ""; + // favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); + // favUser.isImageLoading = false; + // favUser.isImageLoaded = true; + // } + // } + // } + // + // notifyListeners(); + // } Future downloadImageLocal(String? encodedBytes, String userID) async { File? myfile; @@ -1570,25 +1644,25 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { } } - Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { - Utils.showLoading(context); - if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { - Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); - try { - String path = await downChatMedia(encodedString, fileTypeName ?? ""); - Utils.hideLoading(context); - OpenFilex.open(path); - } catch (e) { - Utils.showToast("Cannot open file."); - } - } - } + // Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { + // Utils.showLoading(context); + // if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { + // Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); + // try { + // String path = await downChatMedia(encodedString, fileTypeName ?? ""); + // Utils.hideLoading(context); + // OpenFilex.open(path); + // } catch (e) { + // Utils.showToast("Cannot open file."); + // } + // } + // } - void onNewChatConversion(List? params) { - dynamic items = params!.toList(); - chatUConvCounter = items[0]["singleChatCount"] ?? 0; - notifyListeners(); - } + // void onNewChatConversion(List? params) { + // dynamic items = params!.toList(); + // chatUConvCounter = items[0]["singleChatCount"] ?? 0; + // notifyListeners(); + // } Future invokeChatCounter({required int userId}) async { await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); @@ -1599,145 +1673,145 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); } - void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { - var data = json.decode(json.encode(groupDetails.groupUserList)); - await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); - } + // void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { + // var data = json.decode(json.encode(groupDetails.groupUserList)); + // await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); + // } //////// Audio Recoding Work //////////////////// - Future initAudio({required int receiverId}) async { - // final dir = Directory((Platform.isAndroid - // ? await getExternalStorageDirectory() //FOR ANDROID - // : await getApplicationSupportDirectory() //FOR IOS - // )! - appDirectory = await getApplicationDocumentsDirectory(); - String dirPath = '${appDirectory.path}/chat_audios'; - if (!await Directory(dirPath).exists()) { - await Directory(dirPath).create(); - await File('$dirPath/.nomedia').create(); - } - path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; - recorderController = RecorderController() - ..androidEncoder = AndroidEncoder.aac - ..androidOutputFormat = AndroidOutputFormat.mpeg4 - ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC - ..sampleRate = 6000 - ..updateFrequency = const Duration(milliseconds: 100) - ..bitRate = 18000; - playerController = PlayerController(); - } - - void disposeAudio() { - isRecoding = false; - isPlaying = false; - isPause = false; - isVoiceMsg = false; - recorderController.dispose(); - playerController.dispose(); - } - - void startRecoding(BuildContext context) async { - await Permission.microphone.request().then((PermissionStatus status) { - if (status.isPermanentlyDenied) { - Utils.confirmDialog( - context, - "The app needs microphone access to be able to record audio.", - onTap: () { - Navigator.of(context).pop(); - openAppSettings(); - }, - ); - } else if (status.isDenied) { - Utils.confirmDialog( - context, - "The app needs microphone access to be able to record audio.", - onTap: () { - Navigator.of(context).pop(); - openAppSettings(); - }, - ); - } else if (status.isGranted) { - sRecoding(); - } else { - startRecoding(context); - } - }); - } - - void sRecoding() async { - isVoiceMsg = true; - recorderController.reset(); - await recorderController.record(path: path); - _recodeDuration = 0; - _startTimer(); - isRecoding = !isRecoding; - notifyListeners(); - } - - Future _startTimer() async { - _timer?.cancel(); - _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { - _recodeDuration++; - if (_recodeDuration <= 59) { - applyCounter(); - } else { - pauseRecoding(); - } - }); - } - - void applyCounter() { - buildTimer(); - notifyListeners(); - } - - Future pauseRecoding() async { - isPause = true; - isPlaying = true; - recorderController.pause(); - path = await recorderController.stop(false); - File file = File(path!); - file.readAsBytesSync(); - path = file.path; - await playerController.preparePlayer(path: file.path, volume: 1.0); - _timer?.cancel(); - notifyListeners(); - } - - Future deleteRecoding() async { - _recodeDuration = 0; - _timer?.cancel(); - if (path == null) { - path = await recorderController.stop(true); - } else { - await recorderController.stop(true); - } - if (path != null && path!.isNotEmpty) { - File delFile = File(path!); - double fileSizeInKB = delFile.lengthSync() / 1024; - double fileSizeInMB = fileSizeInKB / 1024; - if (kDebugMode) { - debugPrint("Deleted file size: ${delFile.lengthSync()}"); - debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); - debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); - } - if (await delFile.exists()) { - delFile.delete(); - } - isPause = false; - isRecoding = false; - isPlaying = false; - isVoiceMsg = false; - notifyListeners(); - } - } - - String buildTimer() { - String minutes = _formatNum(_recodeDuration ~/ 60); - String seconds = _formatNum(_recodeDuration % 60); - return '$minutes : $seconds'; - } + // Future initAudio({required int receiverId}) async { + // // final dir = Directory((Platform.isAndroid + // // ? await getExternalStorageDirectory() //FOR ANDROID + // // : await getApplicationSupportDirectory() //FOR IOS + // // )! + // appDirectory = await getApplicationDocumentsDirectory(); + // String dirPath = '${appDirectory.path}/chat_audios'; + // if (!await Directory(dirPath).exists()) { + // await Directory(dirPath).create(); + // await File('$dirPath/.nomedia').create(); + // } + // path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; + // recorderController = RecorderController() + // ..androidEncoder = AndroidEncoder.aac + // ..androidOutputFormat = AndroidOutputFormat.mpeg4 + // ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC + // ..sampleRate = 6000 + // ..updateFrequency = const Duration(milliseconds: 100) + // ..bitRate = 18000; + // playerController = PlayerController(); + // } + + // void disposeAudio() { + // isRecoding = false; + // isPlaying = false; + // isPause = false; + // isVoiceMsg = false; + // recorderController.dispose(); + // playerController.dispose(); + // } + + // void startRecoding(BuildContext context) async { + // await Permission.microphone.request().then((PermissionStatus status) { + // if (status.isPermanentlyDenied) { + // Utils.confirmDialog( + // context, + // "The app needs microphone access to be able to record audio.", + // onTap: () { + // Navigator.of(context).pop(); + // openAppSettings(); + // }, + // ); + // } else if (status.isDenied) { + // Utils.confirmDialog( + // context, + // "The app needs microphone access to be able to record audio.", + // onTap: () { + // Navigator.of(context).pop(); + // openAppSettings(); + // }, + // ); + // } else if (status.isGranted) { + // sRecoding(); + // } else { + // startRecoding(context); + // } + // }); + // } + // + // void sRecoding() async { + // isVoiceMsg = true; + // recorderController.reset(); + // await recorderController.record(path: path); + // _recodeDuration = 0; + // _startTimer(); + // isRecoding = !isRecoding; + // notifyListeners(); + // } + // + // Future _startTimer() async { + // _timer?.cancel(); + // _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { + // _recodeDuration++; + // if (_recodeDuration <= 59) { + // applyCounter(); + // } else { + // pauseRecoding(); + // } + // }); + // } + // + // void applyCounter() { + // buildTimer(); + // notifyListeners(); + // } + // + // Future pauseRecoding() async { + // isPause = true; + // isPlaying = true; + // recorderController.pause(); + // path = await recorderController.stop(false); + // File file = File(path!); + // file.readAsBytesSync(); + // path = file.path; + // await playerController.preparePlayer(path: file.path, volume: 1.0); + // _timer?.cancel(); + // notifyListeners(); + // } + // + // Future deleteRecoding() async { + // _recodeDuration = 0; + // _timer?.cancel(); + // if (path == null) { + // path = await recorderController.stop(true); + // } else { + // await recorderController.stop(true); + // } + // if (path != null && path!.isNotEmpty) { + // File delFile = File(path!); + // double fileSizeInKB = delFile.lengthSync() / 1024; + // double fileSizeInMB = fileSizeInKB / 1024; + // if (kDebugMode) { + // debugPrint("Deleted file size: ${delFile.lengthSync()}"); + // debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); + // debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); + // } + // if (await delFile.exists()) { + // delFile.delete(); + // } + // isPause = false; + // isRecoding = false; + // isPlaying = false; + // isVoiceMsg = false; + // notifyListeners(); + // } + // } + // + // String buildTimer() { + // String minutes = _formatNum(_recodeDuration ~/ 60); + // String seconds = _formatNum(_recodeDuration % 60); + // return '$minutes : $seconds'; + // } String _formatNum(int number) { String numberStr = number.toString(); @@ -1766,101 +1840,102 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { return file; } - void scrollToMsg(SingleUserChatModel data) { - if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { - int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); - if (index >= 1) { - double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; - double target = contentSize * index / userChatHistory.length; - scrollController.position.animateTo( - target, - duration: const Duration(seconds: 1), - curve: Curves.easeInOut, - ); - } - } - } - - Future getTeamMembers() async { - teamMembersList = []; - isLoading = true; - if (AppState().getemployeeSubordinatesList.isNotEmpty) { - getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; - for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { - if (element.eMPLOYEEEMAILADDRESS != null) { - if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { - teamMembersList.add( - ChatUser( - id: int.parse(element.eMPLOYEENUMBER!), - email: element.eMPLOYEEEMAILADDRESS, - userName: element.eMPLOYEENAME, - phone: element.eMPLOYEEMOBILENUMBER, - userStatus: 0, - unreadMessageCount: 0, - isFav: false, - isTyping: false, - isImageLoading: false, - image: element.eMPLOYEEIMAGE ?? "", - isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), - ), - ); - } - } - } - } else { - getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); - AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; - for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { - if (element.eMPLOYEEEMAILADDRESS != null) { - if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { - teamMembersList.add( - ChatUser( - id: int.parse(element.eMPLOYEENUMBER!), - email: element.eMPLOYEEEMAILADDRESS, - userName: element.eMPLOYEENAME, - phone: element.eMPLOYEEMOBILENUMBER, - userStatus: 0, - unreadMessageCount: 0, - isFav: false, - isTyping: false, - isImageLoading: false, - image: element.eMPLOYEEIMAGE ?? "", - isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), - ), - ); - } - } - } - } - - for (ChatUser user in searchedChats!) { - for (ChatUser teamUser in teamMembersList!) { - if (user.id == teamUser.id) { - teamUser.userStatus = user.userStatus; - } - } - } - - isLoading = false; - notifyListeners(); - } - - void inputBoxDirection(String val) { - if (val.isNotEmpty) { - isTextMsg = true; - } else { - isTextMsg = false; - } - msgText = val; - notifyListeners(); - } - - void onDirectionChange(bool val) { - isRTL = val; - notifyListeners(); - } + // void scrollToMsg(SingleUserChatModel data) { + // if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { + // int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); + // if (index >= 1) { + // double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; + // double target = contentSize * index / userChatHistory.length; + // scrollController.position.animateTo( + // target, + // duration: const Duration(seconds: 1), + // curve: Curves.easeInOut, + // ); + // } + // } + // } + + // + // Future getTeamMembers() async { + // teamMembersList = []; + // isLoading = true; + // if (AppState().getemployeeSubordinatesList.isNotEmpty) { + // getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; + // for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { + // if (element.eMPLOYEEEMAILADDRESS != null) { + // if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { + // teamMembersList.add( + // ChatUser( + // id: int.parse(element.eMPLOYEENUMBER!), + // email: element.eMPLOYEEEMAILADDRESS, + // userName: element.eMPLOYEENAME, + // phone: element.eMPLOYEEMOBILENUMBER, + // userStatus: 0, + // unreadMessageCount: 0, + // isFav: false, + // isTyping: false, + // isImageLoading: false, + // image: element.eMPLOYEEIMAGE ?? "", + // isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, + // userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + // ), + // ); + // } + // } + // } + // } else { + // getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); + // AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; + // for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { + // if (element.eMPLOYEEEMAILADDRESS != null) { + // if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { + // teamMembersList.add( + // ChatUser( + // id: int.parse(element.eMPLOYEENUMBER!), + // email: element.eMPLOYEEEMAILADDRESS, + // userName: element.eMPLOYEENAME, + // phone: element.eMPLOYEEMOBILENUMBER, + // userStatus: 0, + // unreadMessageCount: 0, + // isFav: false, + // isTyping: false, + // isImageLoading: false, + // image: element.eMPLOYEEIMAGE ?? "", + // isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, + // userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + // ), + // ); + // } + // } + // } + // } + // + // for (ChatUser user in searchedChats!) { + // for (ChatUser teamUser in teamMembersList!) { + // if (user.id == teamUser.id) { + // teamUser.userStatus = user.userStatus; + // } + // } + // } + // + // isLoading = false; + // notifyListeners(); + // } + + // void inputBoxDirection(String val) { + // if (val.isNotEmpty) { + // isTextMsg = true; + // } else { + // isTextMsg = false; + // } + // msgText = val; + // notifyListeners(); + // } + // + // void onDirectionChange(bool val) { + // isRTL = val; + // notifyListeners(); + // } Material.TextDirection getTextDirection(String v) { String str = v.trim(); @@ -1892,81 +1967,81 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { return Material.TextDirection.ltr; } - void openChatByNoti(BuildContext context) async { - SingleUserChatModel nUser = SingleUserChatModel(); - Utils.saveStringFromPrefs("isAppOpendByChat", "false"); - if (await Utils.getStringFromPrefs("notificationData") != "null") { - nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); - Utils.saveStringFromPrefs("notificationData", "null"); - Future.delayed(const Duration(seconds: 2)); - for (ChatUser user in searchedChats!) { - if (user.id == nUser.targetUserId) { - Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); - return; - } - } - } - Utils.saveStringFromPrefs("notificationData", "null"); - } - - //group chat functions added here - - void filterGroups(String value) async { - // filter function added here. - List tmp = []; - if (value.isEmpty || value == "") { - tmp = userGroups.groupresponse!; - } else { - for (groups.GroupResponse element in uGroups!) { - if (element.groupName!.toLowerCase().contains(value.toLowerCase())) { - tmp.add(element); - } - } - } - uGroups = tmp; - notifyListeners(); - } - - Future deleteGroup(GroupResponse groupDetails) async { - isLoading = true; - await ChatApiClient().deleteGroup(groupDetails.groupId); - userGroups = await ChatApiClient().getGroupsByUserId(); - uGroups = userGroups.groupresponse; - isLoading = false; - notifyListeners(); - } - - Future getGroupChatHistory(groups.GroupResponse groupDetails) async { - isLoading = true; - groupChatHistory = await ChatApiClient().getGroupChatHistory(groupDetails.groupId, groupDetails.groupUserList as List); - - isLoading = false; - - notifyListeners(); - } - - void updateGroupAdmin(int? groupId, List groupUserList) async { - isLoading = true; - await ChatApiClient().updateGroupAdmin(groupId, groupUserList); - isLoading = false; - notifyListeners(); - } - - Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { - isLoading = true; - var groups = await ChatApiClient().addGroupAndUsers(request); - userGroups.groupresponse!.add(GroupResponse.fromJson(json.decode(groups)['response'])); - - isLoading = false; - notifyListeners(); - } - - Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { - isLoading = true; - await ChatApiClient().updateGroupAndUsers(request); - userGroups = await ChatApiClient().getGroupsByUserId(); - uGroups = userGroups.groupresponse; - isLoading = false; - notifyListeners(); - } +// void openChatByNoti(BuildContext context) async { +// SingleUserChatModel nUser = SingleUserChatModel(); +// Utils.saveStringFromPrefs("isAppOpendByChat", "false"); +// if (await Utils.getStringFromPrefs("notificationData") != "null") { +// nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); +// Utils.saveStringFromPrefs("notificationData", "null"); +// Future.delayed(const Duration(seconds: 2)); +// for (ChatUser user in searchedChats!) { +// if (user.id == nUser.targetUserId) { +// Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); +// return; +// } +// } +// } +// Utils.saveStringFromPrefs("notificationData", "null"); +// } + +//group chat functions added here + +// void filterGroups(String value) async { +// // filter function added here. +// List tmp = []; +// if (value.isEmpty || value == "") { +// tmp = userGroups.groupresponse!; +// } else { +// for (groups.GroupResponse element in uGroups!) { +// if (element.groupName!.toLowerCase().contains(value.toLowerCase())) { +// tmp.add(element); +// } +// } +// } +// uGroups = tmp; +// notifyListeners(); +// } + +// Future deleteGroup(GroupResponse groupDetails) async { +// isLoading = true; +// await ChatApiClient().deleteGroup(groupDetails.groupId); +// userGroups = await ChatApiClient().getGroupsByUserId(); +// uGroups = userGroups.groupresponse; +// isLoading = false; +// notifyListeners(); +// } +// +// Future getGroupChatHistory(groups.GroupResponse groupDetails) async { +// isLoading = true; +// groupChatHistory = await ChatApiClient().getGroupChatHistory(groupDetails.groupId, groupDetails.groupUserList as List); +// +// isLoading = false; +// +// notifyListeners(); +// } +// +// void updateGroupAdmin(int? groupId, List groupUserList) async { +// isLoading = true; +// await ChatApiClient().updateGroupAdmin(groupId, groupUserList); +// isLoading = false; +// notifyListeners(); +// } + +// Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { +// isLoading = true; +// var groups = await ChatApiClient().addGroupAndUsers(request); +// userGroups.groupresponse!.add(GroupResponse.fromJson(json.decode(groups)['response'])); +// +// isLoading = false; +// notifyListeners(); +// } +// +// Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { +// isLoading = true; +// await ChatApiClient().updateGroupAndUsers(request); +// userGroups = await ChatApiClient().getGroupsByUserId(); +// uGroups = userGroups.groupresponse; +// isLoading = false; +// notifyListeners(); +// } } diff --git a/lib/modules/cx_module/chat/chat_rooms_page.dart b/lib/modules/cx_module/chat/chat_rooms_page.dart index 09c102ea..15540eaa 100644 --- a/lib/modules/cx_module/chat/chat_rooms_page.dart +++ b/lib/modules/cx_module/chat/chat_rooms_page.dart @@ -80,7 +80,7 @@ class _ChatPageState extends State { ), ], ).paddingOnly(top: 4, bottom: 4).onPress(() { - Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage())); + // Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage())); return; }), separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), diff --git a/lib/modules/cx_module/chat/model/chat_login_response_model.dart b/lib/modules/cx_module/chat/model/chat_login_response_model.dart new file mode 100644 index 00000000..3fde6c54 --- /dev/null +++ b/lib/modules/cx_module/chat/model/chat_login_response_model.dart @@ -0,0 +1,30 @@ +class ChatLoginResponse { + String? token; + int? userId; + String? userName; + int? applicationId; + int? expiresIn; + String? context; + + ChatLoginResponse({this.token, this.userId, this.userName, this.applicationId, this.expiresIn, this.context}); + + ChatLoginResponse.fromJson(Map json) { + token = json['token']; + userId = json['userId']; + userName = json['userName']; + applicationId = json['applicationId']; + expiresIn = json['expiresIn']; + context = json['context']; + } + + Map toJson() { + final Map data = new Map(); + data['token'] = this.token; + data['userId'] = this.userId; + data['userName'] = this.userName; + data['applicationId'] = this.applicationId; + data['expiresIn'] = this.expiresIn; + data['context'] = this.context; + return data; + } +} diff --git a/lib/modules/cx_module/chat/model/chat_participant_model.dart b/lib/modules/cx_module/chat/model/chat_participant_model.dart new file mode 100644 index 00000000..6ef1d4e4 --- /dev/null +++ b/lib/modules/cx_module/chat/model/chat_participant_model.dart @@ -0,0 +1,65 @@ +class ChatParticipantModel { + int? id; + String? title; + String? conversationType; + List? participants; + String? lastMessage; + String? createdAt; + + ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.lastMessage, this.createdAt}); + + ChatParticipantModel.fromJson(Map json) { + id = json['id']; + title = json['title']; + conversationType = json['conversationType']; + if (json['participants'] != null) { + participants = []; + json['participants'].forEach((v) { + participants!.add(new Participants.fromJson(v)); + }); + } + lastMessage = json['lastMessage']; + createdAt = json['createdAt']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['title'] = this.title; + data['conversationType'] = this.conversationType; + if (this.participants != null) { + data['participants'] = this.participants!.map((v) => v.toJson()).toList(); + } + data['lastMessage'] = this.lastMessage; + data['createdAt'] = this.createdAt; + return data; + } +} + +class Participants { + String? userId; + String? userName; + String? employeeNumber; + String? role; + int? userStatus; + + Participants({this.userId, this.userName, this.employeeNumber, this.role, this.userStatus}); + + Participants.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + employeeNumber = json['employeeNumber']; + role = json['role']; + userStatus = json['userStatus']; + } + + Map toJson() { + final Map data = new Map(); + data['userId'] = this.userId; + data['userName'] = this.userName; + data['employeeNumber'] = this.employeeNumber; + data['role'] = this.role; + data['userStatus'] = this.userStatus; + return data; + } +} diff --git a/lib/modules/cx_module/chat/model/user_chat_history_model.dart b/lib/modules/cx_module/chat/model/user_chat_history_model.dart new file mode 100644 index 00000000..40140c77 --- /dev/null +++ b/lib/modules/cx_module/chat/model/user_chat_history_model.dart @@ -0,0 +1,65 @@ +class UserChatHistoryModel { + List? response; + bool? isSuccess; + List? onlineUserConnId; + + UserChatHistoryModel({this.response, this.isSuccess, this.onlineUserConnId}); + + UserChatHistoryModel.fromJson(Map json) { + if (json['response'] != null) { + response = []; + json['response'].forEach((v) { + response!.add(new ChatResponse.fromJson(v)); + }); + } + isSuccess = json['isSuccess']; + onlineUserConnId = json['onlineUserConnId'].cast(); + } + + Map toJson() { + final Map data = new Map(); + if (this.response != null) { + data['response'] = this.response!.map((v) => v.toJson()).toList(); + } + data['isSuccess'] = this.isSuccess; + data['onlineUserConnId'] = this.onlineUserConnId; + return data; + } +} + +class ChatResponse { + int? id; + int? conversationId; + String? userId; + int? userIdInt; + String? userName; + String? content; + String? messageType; + String? createdAt; + + ChatResponse({this.id, this.conversationId, this.userId, this.userIdInt, this.userName, this.content, this.messageType, this.createdAt}); + + ChatResponse.fromJson(Map json) { + id = json['id']; + conversationId = json['conversationId']; + userId = json['userId']; + userIdInt = json['userIdInt']; + userName = json['userName']; + content = json['content']; + messageType = json['messageType']; + createdAt = json['createdAt']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['conversationId'] = this.conversationId; + data['userId'] = this.userId; + data['userIdInt'] = this.userIdInt; + data['userName'] = this.userName; + data['content'] = this.content; + data['messageType'] = this.messageType; + data['createdAt'] = this.createdAt; + return data; + } +} diff --git a/lib/modules/cx_module/survey_page.dart b/lib/modules/cx_module/survey/survey_page.dart similarity index 97% rename from lib/modules/cx_module/survey_page.dart rename to lib/modules/cx_module/survey/survey_page.dart index ad8c0d28..fc67441c 100644 --- a/lib/modules/cx_module/survey_page.dart +++ b/lib/modules/cx_module/survey/survey_page.dart @@ -13,7 +13,10 @@ import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; class SurveyPage extends StatefulWidget { - SurveyPage({Key? key}) : super(key: key); + int moduleId; + int requestId; + + SurveyPage({Key? key, required this.moduleId, required this.requestId}) : super(key: key); @override _SurveyPageState createState() { @@ -29,6 +32,11 @@ class _SurveyPageState extends State { @override void initState() { super.initState(); + getSurveyQuestion(); + } + + void getSurveyQuestion(){ + } @override diff --git a/lib/modules/cx_module/survey/survey_provider.dart b/lib/modules/cx_module/survey/survey_provider.dart new file mode 100644 index 00000000..f9674c7c --- /dev/null +++ b/lib/modules/cx_module/survey/survey_provider.dart @@ -0,0 +1,34 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; + +class SurveyProvider with ChangeNotifier { + bool loading = false; + + void reset() { + loading = false; + // ChatApiClient().chatLoginResponse = null; + } + + Future getQuestionnaire(int surveySubmissionId) async { + reset(); + loading = true; + notifyListeners(); + final response = await ApiManager.instance.get(URLs.getQuestionnaire + "?surveySubmissionId=$surveySubmissionId"); + + loading = false; + + notifyListeners(); + } + +// Future loadChatHistory(int moduleId, int requestId) async { +// // loadChatHistoryLoading = true; +// // notifyListeners(); +// chatLoginResponse = await ChatApiClient().loadChatHistory(moduleId, requestId); +// loadChatHistoryLoading = false; +// notifyListeners(); +// } +} diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart index 8d36d425..946eda54 100644 --- a/lib/new_views/pages/login_page.dart +++ b/lib/new_views/pages/login_page.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -12,7 +13,8 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/general_response_model.dart'; -import 'package:test_sa/modules/cx_module/survey_page.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; +import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/forget_password_module/forget_passwod_verify_otp.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart'; @@ -226,9 +228,8 @@ class _LoginPageState extends State { } Future _login() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => SurveyPage())); - - return; + // Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: 1845972))); + // return; if (!_formKey.currentState!.validate()) return; if (privacyPolicyChecked == false) { From bcfa23bad31c4d31c7ef9ee5ae08eaa96ed4cbeb Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 13 Nov 2025 12:15:11 +0300 Subject: [PATCH 12/31] chat message ui completed for sender and recipient. --- lib/controllers/api_routes/urls.dart | 9 +- lib/extensions/string_extensions.dart | 15 ++++ lib/modules/cx_module/chat/chat_page.dart | 87 +++++++++++++------ lib/modules/cx_module/chat/chat_provider.dart | 21 ++++- 4 files changed, 102 insertions(+), 30 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 6bb88970..3cab3aa3 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -5,11 +5,12 @@ class URLs { // static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url - static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url - // static String _baseUrl = "$_host/mobile"; - static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + static String _baseUrl = "$_host/mobile"; + + // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index eabd9fce..a8fd4f51 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -6,6 +6,21 @@ extension StringExtensions on String { void get showToast => Fluttertoast.showToast(msg: this); + String get chatMsgTime { + DateTime dateTime = DateTime.parse(this); + return DateFormat('hh:mm a').format(dateTime); + } + + String get chatMsgDate { + DateTime dateTime = DateTime.parse(this); + return DateFormat('EEE dd MMM').format(dateTime); + } + + String get chatMsgDateWithYear { + DateTime dateTime = DateTime.parse(this); + return DateFormat('EEE dd MMM yyyy').format(dateTime); + } + String get toServiceRequestCardFormat { DateTime dateTime = DateTime.parse(this); return "${DateFormat('dd MMM, yyyy').format(dateTime)}\n${DateFormat('hh:mm a').format(dateTime)}"; diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 75cb2fba..800ebc46 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -13,6 +13,8 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'model/user_chat_history_model.dart'; + enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } class ChatPage extends StatefulWidget { @@ -105,7 +107,7 @@ class _ChatPageState extends State { child: Row( children: [ Text( - "Engineer: Mahmoud Shrouf", + chatProvider.recipient?.userName ?? "", overflow: TextOverflow.ellipsis, maxLines: 2, style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), @@ -123,18 +125,16 @@ class _ChatPageState extends State { ), ), Container( - // width: double.infinity, color: AppColor.neutral100, - child: !chatProvider.userChatHistoryLoading + child: chatProvider.userChatHistoryLoading ? ListView( padding: const EdgeInsets.all(16), children: [ - recipientMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?", loading: true), - recipientMsgCard(false, "testing", loading: true), - recipientMsgCard(false, "testing testing testing", loading: true), - // dateCard("Mon 27 Oct",), - senderMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?", loading: true), - senderMsgCard(false, "Please let me know what is the issue?", loading: true), + recipientMsgCard(true, null, msg: "Please let me know what is the issue? Please let me know what is the issue?", loading: true), + recipientMsgCard(false, null, msg: "testing", loading: true), + recipientMsgCard(false, null, msg: "testing testing testing", loading: true), + senderMsgCard(true, null, msg: "Please let me know what is the issue? Please let me know what is the issue?", loading: true), + senderMsgCard(false, null, msg: "Please let me know what is the issue?", loading: true), ], ) : chatProvider.chatResponseList.isEmpty @@ -145,7 +145,29 @@ class _ChatPageState extends State { style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50.withOpacity(.5), fontWeight: FontWeight.w500), ).center : ListView.builder( - itemBuilder: (cxt, index) => recipientMsgCard(true, chatProvider.chatResponseList[index].content ?? ""), itemCount: chatProvider.chatResponseList.length)) + padding: const EdgeInsets.all(16), + reverse: true, + itemBuilder: (cxt, index) { + final currentMessage = chatProvider.chatResponseList[index]; + final bool showSenderName = (index == chatProvider.chatResponseList.length - 1) || (currentMessage.userId != chatProvider.chatResponseList[index + 1].userId); + bool isSender = chatProvider.chatResponseList[index].userId == chatProvider.sender?.userId!; + bool showDateHeader = false; + if (index == chatProvider.chatResponseList.length - 1) { + showDateHeader = true; + } else { + final nextMessage = chatProvider.chatResponseList[index + 1]; + final currentDate = DateUtils.dateOnly(DateTime.parse(currentMessage.createdAt!)); + final nextDate = DateUtils.dateOnly(DateTime.parse(nextMessage.createdAt!)); + if (!currentDate.isAtSameMomentAs(nextDate)) { + showDateHeader = true; + } + } + return Column(mainAxisSize: MainAxisSize.min, children: [ + if (showDateHeader) dateCard(currentMessage.createdAt?.chatMsgDate ?? ""), + isSender ? senderMsgCard(showSenderName, chatProvider.chatResponseList[index]) : recipientMsgCard(showSenderName, chatProvider.chatResponseList[index]) + ]); + }, + itemCount: chatProvider.chatResponseList.length)) .expanded, if (!widget.readOnly) ...[ Divider(height: 1, thickness: 1, color: const Color(0xff767676).withOpacity(.11)), @@ -428,6 +450,9 @@ class _ChatPageState extends State { // ), IconButton( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + hoverColor: Colors.transparent, onPressed: () { chatProvider.sendTextMessage(textEditingController.text).then((success) { if (success) { @@ -470,12 +495,12 @@ class _ChatPageState extends State { .center; } - Widget senderMsgCard(bool showHeader, String msg, {bool loading = false}) { + Widget senderMsgCard(bool showHeader, ChatResponse? chatResponse, {bool loading = false, String msg = ""}) { Widget senderHeader = Row( mainAxisSize: MainAxisSize.min, children: [ Text( - "Jeniffer Jeniffer Jeniffer(Me)", + "${chatResponse?.userName ?? "User"}(Me)", overflow: TextOverflow.ellipsis, maxLines: 1, style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), @@ -484,7 +509,7 @@ class _ChatPageState extends State { Container( height: 26, width: 26, - decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), + decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.grey), ).toShimmer(context: context, isShow: loading), ], ); @@ -500,7 +525,7 @@ class _ChatPageState extends State { padding: const EdgeInsets.all(8), margin: const EdgeInsets.only(right: 26 + 8, left: 26 + 8), decoration: BoxDecoration( - color: AppColor.white10, + color: loading ? Colors.transparent : AppColor.white10, borderRadius: BorderRadius.circular(6), ), child: Column( @@ -508,11 +533,12 @@ class _ChatPageState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( - msg, + chatResponse?.content ?? msg, style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), ).toShimmer(context: context, isShow: loading), + if (loading) 4.height, Text( - "2:00 PM", + chatResponse?.createdAt?.chatMsgTime ?? "2:00 PM", style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)), ).toShimmer(context: context, isShow: loading), ], @@ -522,18 +548,28 @@ class _ChatPageState extends State { ); } - Widget recipientMsgCard(bool showHeader, String msg, {bool loading = false}) { + Widget recipientMsgCard(bool showHeader, ChatResponse? chatResponse, {bool loading = false, String msg = ""}) { + String extraSpaces = ""; + int length = 0; + if ((chatResponse?.content ?? "").isNotEmpty) { + if (chatResponse!.content!.length < 8) { + length = 8 - chatResponse.content!.length; + } + } + + String contentMsg = chatResponse?.content == null ? msg : chatResponse!.content! + extraSpaces; + print("'$contentMsg'"); Widget recipientHeader = Row( mainAxisSize: MainAxisSize.min, children: [ Container( height: 26, width: 26, - decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), + decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.grey), ).toShimmer(context: context, isShow: loading), 8.width, Text( - "Mahmoud Shrouf", + chatResponse?.userName ?? "User", overflow: TextOverflow.ellipsis, maxLines: 1, style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), @@ -552,7 +588,7 @@ class _ChatPageState extends State { padding: const EdgeInsets.all(8), margin: const EdgeInsets.only(left: 26 + 8, right: 26 + 8), decoration: BoxDecoration( - color: AppColor.primary10, + color: loading ? Colors.transparent : AppColor.primary10, borderRadius: BorderRadius.circular(6), ), child: Column( @@ -560,19 +596,20 @@ class _ChatPageState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( - msg, + contentMsg, style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), - ).toShimmer(context: context, isShow: loading), + ).paddingOnly(end: 6 * length).toShimmer(context: context, isShow: loading), + if (loading) 4.height, Align( alignment: Alignment.centerRight, widthFactor: 1, child: Text( - "2:00 PM", + chatResponse?.createdAt?.chatMsgTime ?? "2:00 PM", style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.white10), ), - ), + ).toShimmer(context: context, isShow: loading), ], - ).toShimmer(context: context, isShow: loading)), + )), ], ), ); diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 48438375..94dcad71 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -119,6 +119,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { List chatResponseList = []; + Participants? sender; + Participants? recipient; + void reset() { chatLoginTokenLoading = false; chatParticipantLoading = false; @@ -126,6 +129,8 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { chatLoginResponse = null; chatParticipantModel = null; userChatHistory = null; + sender = null; + recipient = null; ChatApiClient().chatLoginResponse = null; } @@ -152,7 +157,18 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { Future loadChatHistory(int moduleId, int requestId, String myId, String? assigneeEmployeeNumber) async { userChatHistoryLoading = true; notifyListeners(); - chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); + try { + chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); + } catch (ex) { + userChatHistoryLoading = false; + notifyListeners(); + return; + } + + try { + sender = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == myId); + recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); + } catch (e) {} userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, "12"); chatResponseList = userChatHistory?.response ?? []; @@ -168,6 +184,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { if (chatResponse != null) { returnStatus = true; chatResponseList.add(chatResponse); + try { + chatResponseList.sort((a, b) => b.createdAt!.compareTo(a.createdAt!)); + } catch (ex) {} } messageIsSending = false; notifyListeners(); From 1cc5ebd9fbe4c1241953380692eac75e7205f814 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 13 Nov 2025 14:44:52 +0300 Subject: [PATCH 13/31] survey question cont. --- lib/controllers/api_routes/urls.dart | 4 ++-- .../views/service_request_detail_main_view.dart | 2 +- lib/modules/cx_module/chat/chat_provider.dart | 6 +++--- lib/modules/cx_module/survey/survey_page.dart | 10 +++++++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 3cab3aa3..2fc39547 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -8,9 +8,9 @@ class URLs { static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url - static String _baseUrl = "$_host/mobile"; + // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index aeed58a1..2431d1ed 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -87,7 +87,7 @@ class _ServiceRequestDetailMainState extends State { IconButton( icon: const Icon(Icons.feedback_rounded), onPressed: () { - Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId))); + Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId, surveyId: 6))); }, ), IconButton( diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 94dcad71..6fa6ecd7 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -217,7 +217,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { chatHubConnection = await getHubConnection(); await chatHubConnection.start(); if (kDebugMode) { - // logger.i("Hub Conn: Startedddddddd"); + print("Hub Conn: Startedddddddd"); } // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); // chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); @@ -231,7 +231,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { HubConnection hub; HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hub = HubConnectionBuilder() - .withUrl(URLs.chatHubUrlChat + "?UserId=AppState().chatDetails!.response!.id&source=Desktop&access_token=AppState().chatDetails!.response!.token", options: httpOp) + .withUrl("${URLs.chatHubUrl}?UserId=${chatLoginResponse!.userId}&source=Desktop&access_token=${chatLoginResponse!.token}", options: httpOp) .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); return hub; } @@ -246,7 +246,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); // chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); // chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); - chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); + // chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); // // {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]} diff --git a/lib/modules/cx_module/survey/survey_page.dart b/lib/modules/cx_module/survey/survey_page.dart index fc67441c..e6157a7f 100644 --- a/lib/modules/cx_module/survey/survey_page.dart +++ b/lib/modules/cx_module/survey/survey_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; @@ -12,11 +13,14 @@ import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'survey_provider.dart'; + class SurveyPage extends StatefulWidget { int moduleId; int requestId; + int surveyId; - SurveyPage({Key? key, required this.moduleId, required this.requestId}) : super(key: key); + SurveyPage({Key? key, required this.moduleId, required this.requestId, required this.surveyId}) : super(key: key); @override _SurveyPageState createState() { @@ -35,8 +39,8 @@ class _SurveyPageState extends State { getSurveyQuestion(); } - void getSurveyQuestion(){ - + void getSurveyQuestion() { + Provider.of(context, listen: false).getQuestionnaire(widget.surveyId); } @override From 9d7c3a38b262cc4c7e767e7936aa508910407c8c Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 13 Nov 2025 17:52:13 +0300 Subject: [PATCH 14/31] chat connection improvements --- lib/controllers/api_routes/urls.dart | 2 + .../new_models/work_order_detail_model.dart | 55 ++-- .../service_request_detail_main_view.dart | 3 +- .../cx_module/chat/chat_api_client.dart | 15 +- lib/modules/cx_module/chat/chat_page.dart | 7 +- lib/modules/cx_module/chat/chat_provider.dart | 13 +- .../chat/model/user_chat_history_model.dart | 159 ++++++++++++ .../cx_module/survey/questionnaire_model.dart | 169 ++++++++++++ lib/modules/cx_module/survey/survey_page.dart | 241 +++++++++++------- .../cx_module/survey/survey_provider.dart | 42 +-- 10 files changed, 562 insertions(+), 144 deletions(-) create mode 100644 lib/modules/cx_module/survey/questionnaire_model.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 2fc39547..3ef46b03 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -351,4 +351,6 @@ class URLs { //survey static get getQuestionnaire => '$_baseUrl/SurveyQuestionnaire/GetQuestionnaire'; + + static get submitSurvey => '$_baseUrl/SurveyQuestionnaire/SubmitSurvey'; } diff --git a/lib/models/new_models/work_order_detail_model.dart b/lib/models/new_models/work_order_detail_model.dart index febd3d80..25519bd6 100644 --- a/lib/models/new_models/work_order_detail_model.dart +++ b/lib/models/new_models/work_order_detail_model.dart @@ -348,33 +348,46 @@ class AssetGroup { } class WorkOrderAssignedEmployee { - WorkOrderAssignedEmployee({ - required this.userId, - required this.userName, - required this.email, - required this.languageId, - }); - - String userId; + String? userId; String? userName; String? email; + String? employeeId; int? languageId; + String? extensionNo; + String? phoneNumber; + String? positionName; + String? position; + bool? isActive; - factory WorkOrderAssignedEmployee.fromJson(Map json) { - return WorkOrderAssignedEmployee( - userId: json["userId"], - userName: json["userName"], - email: json["email"], - languageId: json["languageId"], - ); + WorkOrderAssignedEmployee({this.userId, this.userName, this.email, this.employeeId, this.languageId, this.extensionNo, this.phoneNumber, this.positionName, this.position, this.isActive}); + + WorkOrderAssignedEmployee.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + extensionNo = json['extensionNo']; + phoneNumber = json['phoneNumber']; + positionName = json['positionName']; + position = json['position']; + isActive = json['isActive']; } - Map toJson() => { - "userId": userId, - "userName": userName, - "email": email, - "languageId": languageId, - }; + Map toJson() { + final Map data = new Map(); + data['userId'] = this.userId; + data['userName'] = this.userName; + data['email'] = this.email; + data['employeeId'] = this.employeeId; + data['languageId'] = this.languageId; + data['extensionNo'] = this.extensionNo; + data['phoneNumber'] = this.phoneNumber; + data['positionName'] = this.positionName; + data['position'] = this.position; + data['isActive'] = this.isActive; + return data; + } } class AssetLoan { diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 2431d1ed..cd50f283 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -93,7 +93,8 @@ class _ServiceRequestDetailMainState extends State { IconButton( icon: const Icon(Icons.chat_bubble), onPressed: () { - Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: widget.requestId))); + Navigator.push( + context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: widget.requestId, title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? ""))); }, ), isNurse diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 985666c0..b6d5adc8 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -61,8 +61,8 @@ class ChatApiClient { return chatLoginResponse; } - Future loadParticipants(int moduleId, int referenceId,String? assigneeEmployeeNumber) async { - Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); + Future loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async { + Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId", token: chatLoginResponse!.token); if (!kReleaseMode) { // logger.i("login-res: " + response.body); @@ -74,18 +74,21 @@ class ChatApiClient { } } - Future loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async { + Future> loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async { Response response = await ApiClient().postJsonForResponse( "${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()}, token: chatLoginResponse!.token); try { if (response.statusCode == 200) { - return UserChatHistoryModel.fromJson(jsonDecode(response.body)); + List data = jsonDecode(response.body); + return data.map((elemet) => ChatHistoryResponse.fromJson(elemet)).toList(); + + // return UserChatHistoryModel.fromJson(jsonDecode(response.body)); } else { - return null; + return []; } } catch (ex) { - return null; + return []; } } diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 800ebc46..f7e8fb5c 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -6,6 +6,8 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart'; import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; @@ -56,8 +58,9 @@ class _ChatPageState extends State { } void getChatToken() { - String assigneeEmployeeNumber = ""; - Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId + 2, widget.title, context.settingProvider.username, assigneeEmployeeNumber); + String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, + Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!, assigneeEmployeeNumber); } @override diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 6fa6ecd7..84262c5c 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -113,7 +113,10 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { ChatParticipantModel? chatParticipantModel; bool userChatHistoryLoading = false; - UserChatHistoryModel? userChatHistory; + + // UserChatHistoryModel? userChatHistory; + + List? userChatHistory; bool messageIsSending = false; @@ -134,7 +137,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { ChatApiClient().chatLoginResponse = null; } - Future getUserAutoLoginToken(int moduleId, int requestId, String title, String employeeNumber, String? assigneeEmployeeNumber) async { + Future getUserAutoLoginToken(int moduleId, int requestId, String title, String employeeNumber, String assigneeEmployeeNumber) async { reset(); chatLoginTokenLoading = true; notifyListeners(); @@ -154,7 +157,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // notifyListeners(); // } - Future loadChatHistory(int moduleId, int requestId, String myId, String? assigneeEmployeeNumber) async { + Future loadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { userChatHistoryLoading = true; notifyListeners(); try { @@ -169,8 +172,8 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { sender = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == myId); recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); } catch (e) {} - userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, "12"); - chatResponseList = userChatHistory?.response ?? []; + userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); + // chatResponseList = userChatHistory?.response ?? []; userChatHistoryLoading = false; notifyListeners(); diff --git a/lib/modules/cx_module/chat/model/user_chat_history_model.dart b/lib/modules/cx_module/chat/model/user_chat_history_model.dart index 40140c77..84d8a257 100644 --- a/lib/modules/cx_module/chat/model/user_chat_history_model.dart +++ b/lib/modules/cx_module/chat/model/user_chat_history_model.dart @@ -63,3 +63,162 @@ class ChatResponse { return data; } } + +class ChatHistoryResponse { + int? userChatHistoryId; + int? userChatHistoryLineId; + String? contant; + String? contantNo; + String? currentUserId; + String? currentEmployeeNumber; + String? currentUserName; + String? currentUserEmail; + String? currentFullName; + String? targetUserId; + String? targetEmployeeNumber; + String? targetUserName; + String? targetUserEmail; + String? targetFullName; + String? encryptedTargetUserId; + String? encryptedTargetUserName; + int? chatEventId; + String? fileTypeId; + bool? isSeen; + bool? isDelivered; + String? createdDate; + int? chatSource; + String? conversationId; + FileTypeResponse? fileTypeResponse; + String? userChatReplyResponse; + String? deviceToken; + bool? isHuaweiDevice; + String? platform; + String? voipToken; + + ChatHistoryResponse( + {this.userChatHistoryId, + this.userChatHistoryLineId, + this.contant, + this.contantNo, + this.currentUserId, + this.currentEmployeeNumber, + this.currentUserName, + this.currentUserEmail, + this.currentFullName, + this.targetUserId, + this.targetEmployeeNumber, + this.targetUserName, + this.targetUserEmail, + this.targetFullName, + this.encryptedTargetUserId, + this.encryptedTargetUserName, + this.chatEventId, + this.fileTypeId, + this.isSeen, + this.isDelivered, + this.createdDate, + this.chatSource, + this.conversationId, + this.fileTypeResponse, + this.userChatReplyResponse, + this.deviceToken, + this.isHuaweiDevice, + this.platform, + this.voipToken}); + + ChatHistoryResponse.fromJson(Map json) { + userChatHistoryId = json['userChatHistoryId']; + userChatHistoryLineId = json['userChatHistoryLineId']; + contant = json['contant']; + contantNo = json['contantNo']; + currentUserId = json['currentUserId']; + currentEmployeeNumber = json['currentEmployeeNumber']; + currentUserName = json['currentUserName']; + currentUserEmail = json['currentUserEmail']; + currentFullName = json['currentFullName']; + targetUserId = json['targetUserId']; + targetEmployeeNumber = json['targetEmployeeNumber']; + targetUserName = json['targetUserName']; + targetUserEmail = json['targetUserEmail']; + targetFullName = json['targetFullName']; + encryptedTargetUserId = json['encryptedTargetUserId']; + encryptedTargetUserName = json['encryptedTargetUserName']; + chatEventId = json['chatEventId']; + fileTypeId = json['fileTypeId']; + isSeen = json['isSeen']; + isDelivered = json['isDelivered']; + createdDate = json['createdDate']; + chatSource = json['chatSource']; + conversationId = json['conversationId']; + fileTypeResponse = json['fileTypeResponse'] != null ? new FileTypeResponse.fromJson(json['fileTypeResponse']) : null; + userChatReplyResponse = json['userChatReplyResponse']; + deviceToken = json['deviceToken']; + isHuaweiDevice = json['isHuaweiDevice']; + platform = json['platform']; + voipToken = json['voipToken']; + } + + Map toJson() { + final Map data = new Map(); + data['userChatHistoryId'] = this.userChatHistoryId; + data['userChatHistoryLineId'] = this.userChatHistoryLineId; + data['contant'] = this.contant; + data['contantNo'] = this.contantNo; + data['currentUserId'] = this.currentUserId; + data['currentEmployeeNumber'] = this.currentEmployeeNumber; + data['currentUserName'] = this.currentUserName; + data['currentUserEmail'] = this.currentUserEmail; + data['currentFullName'] = this.currentFullName; + data['targetUserId'] = this.targetUserId; + data['targetEmployeeNumber'] = this.targetEmployeeNumber; + data['targetUserName'] = this.targetUserName; + data['targetUserEmail'] = this.targetUserEmail; + data['targetFullName'] = this.targetFullName; + data['encryptedTargetUserId'] = this.encryptedTargetUserId; + data['encryptedTargetUserName'] = this.encryptedTargetUserName; + data['chatEventId'] = this.chatEventId; + data['fileTypeId'] = this.fileTypeId; + data['isSeen'] = this.isSeen; + data['isDelivered'] = this.isDelivered; + data['createdDate'] = this.createdDate; + data['chatSource'] = this.chatSource; + data['conversationId'] = this.conversationId; + if (this.fileTypeResponse != null) { + data['fileTypeResponse'] = this.fileTypeResponse!.toJson(); + } + data['userChatReplyResponse'] = this.userChatReplyResponse; + data['deviceToken'] = this.deviceToken; + data['isHuaweiDevice'] = this.isHuaweiDevice; + data['platform'] = this.platform; + data['voipToken'] = this.voipToken; + return data; + } +} + +class FileTypeResponse { + int? fileTypeId; + String? fileTypeName; + String? fileTypeDescription; + String? fileKind; + String? fileName; + + FileTypeResponse({this.fileTypeId, this.fileTypeName, this.fileTypeDescription, this.fileKind, this.fileName}); + + FileTypeResponse.fromJson(Map json) { + fileTypeId = json['fileTypeId']; + fileTypeName = json['fileTypeName']; + fileTypeDescription = json['fileTypeDescription']; + fileKind = json['fileKind']; + fileName = json['fileName']; + } + + Map toJson() { + final Map data = new Map(); + data['fileTypeId'] = this.fileTypeId; + data['fileTypeName'] = this.fileTypeName; + data['fileTypeDescription'] = this.fileTypeDescription; + data['fileKind'] = this.fileKind; + data['fileName'] = this.fileName; + return data; + } +} diff --git a/lib/modules/cx_module/survey/questionnaire_model.dart b/lib/modules/cx_module/survey/questionnaire_model.dart new file mode 100644 index 00000000..9528cf87 --- /dev/null +++ b/lib/modules/cx_module/survey/questionnaire_model.dart @@ -0,0 +1,169 @@ +class Questionnaire { + int? questionnaireId; + int? surveySubmissionId; + SurveyType? surveyType; + String? surveyName; + String? surveyDescription; + ServiceRequestDetails? serviceRequestDetails; + List? surveyQuestions; + + Questionnaire({this.questionnaireId, this.surveySubmissionId, this.surveyType, this.surveyName, this.surveyDescription, this.serviceRequestDetails, this.surveyQuestions}); + + Questionnaire.fromJson(Map json) { + questionnaireId = json['questionnaireId']; + surveySubmissionId = json['surveySubmissionId']; + surveyType = json['surveyType'] != null ? new SurveyType.fromJson(json['surveyType']) : null; + surveyName = json['surveyName']; + surveyDescription = json['surveyDescription']; + serviceRequestDetails = json['serviceRequestDetails'] != null ? new ServiceRequestDetails.fromJson(json['serviceRequestDetails']) : null; + if (json['surveyQuestions'] != null) { + surveyQuestions = []; + json['surveyQuestions'].forEach((v) { + surveyQuestions!.add(new SurveyQuestions.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['questionnaireId'] = this.questionnaireId; + data['surveySubmissionId'] = this.surveySubmissionId; + if (this.surveyType != null) { + data['surveyType'] = this.surveyType!.toJson(); + } + data['surveyName'] = this.surveyName; + data['surveyDescription'] = this.surveyDescription; + if (this.serviceRequestDetails != null) { + data['serviceRequestDetails'] = this.serviceRequestDetails!.toJson(); + } + if (this.surveyQuestions != null) { + data['surveyQuestions'] = this.surveyQuestions!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class SurveyType { + int? id; + String? name; + int? value; + + SurveyType({this.id, this.name, this.value}); + + SurveyType.fromJson(Map json) { + id = json['id']; + name = json['name']; + value = json['value']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['name'] = this.name; + data['value'] = this.value; + return data; + } +} + +class ServiceRequestDetails { + int? serviceRequestTypeId; + String? serviceRequestType; + String? serviceRequestNo; + + ServiceRequestDetails({this.serviceRequestTypeId, this.serviceRequestType, this.serviceRequestNo}); + + ServiceRequestDetails.fromJson(Map json) { + serviceRequestTypeId = json['serviceRequestTypeId']; + serviceRequestType = json['serviceRequestType']; + serviceRequestNo = json['serviceRequestNo']; + } + + Map toJson() { + final Map data = new Map(); + data['serviceRequestTypeId'] = this.serviceRequestTypeId; + data['serviceRequestType'] = this.serviceRequestType; + data['serviceRequestNo'] = this.serviceRequestNo; + return data; + } +} + +class SurveyQuestions { + int? questionId; + String? questionText; + SurveyType? questionType; + List? surveyAnswerOptions; + + SurveyQuestions({this.questionId, this.questionText, this.questionType, this.surveyAnswerOptions}); + + SurveyQuestions.fromJson(Map json) { + questionId = json['questionId']; + questionText = json['questionText']; + questionType = json['questionType'] != null ? new SurveyType.fromJson(json['questionType']) : null; + if (json['surveyAnswerOptions'] != null) { + surveyAnswerOptions = []; + json['surveyAnswerOptions'].forEach((v) { + surveyAnswerOptions!.add(new SurveyAnswerOptions.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['questionId'] = this.questionId; + data['questionText'] = this.questionText; + if (this.questionType != null) { + data['questionType'] = this.questionType!.toJson(); + } + if (this.surveyAnswerOptions != null) { + data['surveyAnswerOptions'] = this.surveyAnswerOptions!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class SurveyAnswerOptions { + int? optionId; + String? optionText; + int? displayOrder; + + SurveyAnswerOptions({this.optionId, this.optionText, this.displayOrder}); + + SurveyAnswerOptions.fromJson(Map json) { + optionId = json['optionId']; + optionText = json['optionText']; + displayOrder = json['displayOrder']; + } + + Map toJson() { + final Map data = new Map(); + data['optionId'] = this.optionId; + data['optionText'] = this.optionText; + data['displayOrder'] = this.displayOrder; + return data; + } +} + +class SurveyAnswers { + int? questionId; + int? surveyAnswerOptionId; + String? surveyAnswerText; + int? surveyAnswerRating; + + SurveyAnswers({this.questionId, this.surveyAnswerOptionId, this.surveyAnswerText, this.surveyAnswerRating}); + + SurveyAnswers.fromJson(Map json) { + questionId = json['questionId']; + surveyAnswerOptionId = json['surveyAnswerOptionId']; + surveyAnswerText = json['surveyAnswerText']; + surveyAnswerRating = json['surveyAnswerRating']; + } + + Map toJson() { + final Map data = new Map(); + data['questionId'] = this.questionId; + data['surveyAnswerOptionId'] = this.surveyAnswerOptionId; + data['surveyAnswerText'] = this.surveyAnswerText; + data['surveyAnswerRating'] = this.surveyAnswerRating; + return data; + } +} diff --git a/lib/modules/cx_module/survey/survey_page.dart b/lib/modules/cx_module/survey/survey_page.dart index e6157a7f..75a3a28e 100644 --- a/lib/modules/cx_module/survey/survey_page.dart +++ b/lib/modules/cx_module/survey/survey_page.dart @@ -6,8 +6,10 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cx_module/chat/chat_rooms_page.dart'; +import 'package:test_sa/modules/cx_module/survey/questionnaire_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; @@ -29,18 +31,34 @@ class SurveyPage extends StatefulWidget { } class _SurveyPageState extends State { - int serviceSatisfiedRating = -1; + // int serviceSatisfiedRating = -1; int serviceProvidedRating = -1; String comments = ""; + bool loading = false; + + Questionnaire? questionnaire; + + List answers = []; + @override void initState() { super.initState(); getSurveyQuestion(); } - void getSurveyQuestion() { - Provider.of(context, listen: false).getQuestionnaire(widget.surveyId); + void getSurveyQuestion() async { + loading = true; + setState(() {}); + questionnaire = await Provider.of(context, listen: false).getQuestionnaire(widget.surveyId); + for (int i = 0; i < (questionnaire?.surveyQuestions?.length ?? 0); i++) { + answers.add(SurveyAnswers( + questionId: questionnaire!.surveyQuestions![i].questionId!, + surveyAnswerRating: -1, + )); + } + loading = false; + setState(() {}); } @override @@ -53,98 +71,135 @@ class _SurveyPageState extends State { return Scaffold( backgroundColor: AppColor.neutral100, appBar: const DefaultAppBar(title: "Survey"), - body: Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "How satisfied are you with our services?", - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), - ), - 12.height, - SizedBox( - height: 32, - child: ListView.separated( - itemBuilder: (cxt, index) => (serviceSatisfiedRating >= index ? 'star_filled'.toSvgAsset() : 'star_empty'.toSvgAsset()).onPress(() { - setState(() { - serviceSatisfiedRating = index; - }); - }), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (cxt, index) => 8.width, - itemCount: 5, - scrollDirection: Axis.horizontal, - ), - ), - 16.height, - Text( - "Was the service provided promptly by our engineer?", - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), - ), - 12.height, - SizedBox( - height: 32, - child: ListView.separated( - itemBuilder: (cxt, index) => (serviceProvidedRating >= index ? 'star_filled'.toSvgAsset() : 'star_empty'.toSvgAsset()).onPress(() { - setState(() { - serviceProvidedRating = index; - }); - }), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (cxt, index) => 8.width, - itemCount: 5, - scrollDirection: Axis.horizontal, - ), - ), - 16.height, - Text( - "Request Type", - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), - ), - 16.height, - AppTextFormField( - initialValue: "", - textInputType: TextInputType.multiline, - alignLabelWithHint: true, - labelText: "Additional Comments", - backgroundColor: AppColor.fieldBgColor(context), - style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), - labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)), - floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), - showShadow: false, - onChange: (value) { - comments = value; + body: loading + ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3).center + : (questionnaire == null) + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Failed to get questionnaire", + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w500), + ), + 24.height, + AppFilledButton( + label: "Retry", + maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () { + getSurveyQuestion(); + }, + ).paddingOnly(start: 48, end: 48) + ], + ).center + : Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (cxt, index) { + SurveyQuestions question = questionnaire!.surveyQuestions![index]; + return question.questionType?.value == 4 + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + question.questionText ?? "", + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + 12.height, + SizedBox( + height: 32, + child: ListView.separated( + itemBuilder: (cxt, _index) => (answers[index].surveyAnswerRating! >= _index ? 'star_filled'.toSvgAsset() : 'star_empty'.toSvgAsset()).onPress(() { + setState(() { + answers[index].surveyAnswerRating = _index; + // serviceSatisfiedRating = _index; + }); + }), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (cxt, index) => 8.width, + itemCount: 5, + scrollDirection: Axis.horizontal, + ), + ), + ], + ) + : AppTextFormField( + initialValue: answers[index].surveyAnswerText, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + labelText: questionnaire!.surveyQuestions![index].questionText, + backgroundColor: AppColor.fieldBgColor(context), + style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)), + floatingLabelStyle: + TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + showShadow: false, + onChange: (value) { + answers[index].surveyAnswerText = value; + }, + ); + }, + separatorBuilder: (cxt, index) => 16.height, + itemCount: questionnaire?.surveyQuestions?.length ?? 0) + .toShadowContainer(context, borderRadius: 20, showShadow: false), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + label: context.translation.submit, + buttonColor: AppColor.primary10, + onPressed: () async { + FocusScope.of(context).unfocus(); + if (validateAnswers()) { + Map payload = { + "surveySubmissionId": questionnaire!.surveySubmissionId, + "questionnaireId": questionnaire!.questionnaireId, + "submittedUserId": context.userProvider.user!.userID, + "surveySubmissionStatusId": 0, + "surveyAnswers": answers.map((element) => element.toJson()).toList(), + }; + Utils.showLoading(context); + bool isSuccess = await Provider.of(context, listen: false).submitQuestionare(payload); + Utils.hideLoading(context); + if (isSuccess) { + //getSurveyQuestion(); + } //reload Data + } }, ), - ], - ).toShadowContainer(context, borderRadius: 20, showShadow: false)) - .expanded, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - label: context.translation.submit, - buttonColor: AppColor.primary10, - onPressed: () { - if (serviceSatisfiedRating < 0) { - "Provide rate services satisfaction".showToast; - return; - } - if (serviceProvidedRating < 0) { - "Provide rate services provided by engineer".showToast; - return; - } - Navigator.push(context, MaterialPageRoute(builder: (context) => ChatRoomsPage())); - return; - }, - ), - ), - ], - ), + ), + ], + ), ); } + + bool validateAnswers() { + bool status = true; + for (int i = 0; i < answers.length; i++) { + if (questionnaire!.surveyQuestions![i].questionType!.value == 4) { + if (answers[i].surveyAnswerRating! < 0) { + "Please rate (${questionnaire!.surveyQuestions![i].questionText})".showToast; + status = false; + break; + } + } else if (questionnaire!.surveyQuestions![i].questionType!.value == 3) { + answers[i].surveyAnswerRating = null; + if ((answers[i].surveyAnswerText ?? "").isEmpty) { + "Please answer (${questionnaire!.surveyQuestions![i].questionText})".showToast; + status = false; + break; + } + } + } + return status; + } } diff --git a/lib/modules/cx_module/survey/survey_provider.dart b/lib/modules/cx_module/survey/survey_provider.dart index f9674c7c..f1a76a86 100644 --- a/lib/modules/cx_module/survey/survey_provider.dart +++ b/lib/modules/cx_module/survey/survey_provider.dart @@ -1,34 +1,44 @@ import 'dart:async'; +import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; + +import 'questionnaire_model.dart'; class SurveyProvider with ChangeNotifier { bool loading = false; void reset() { loading = false; + // questionnaire = null; // ChatApiClient().chatLoginResponse = null; } - Future getQuestionnaire(int surveySubmissionId) async { - reset(); - loading = true; - notifyListeners(); - final response = await ApiManager.instance.get(URLs.getQuestionnaire + "?surveySubmissionId=$surveySubmissionId"); - - loading = false; - - notifyListeners(); + Future getQuestionnaire(int surveySubmissionId) async { + try { + final response = await ApiManager.instance.get("${URLs.getQuestionnaire.toString().replaceFirst("/mobile/", "/api/")}?surveySubmissionId=$surveySubmissionId"); + if (response.statusCode >= 200 && response.statusCode < 300) { + return Questionnaire.fromJson(jsonDecode(response.body)["data"]); + } + } catch (ex) { + "Failed, Retry.".showToast; + } + return null; } -// Future loadChatHistory(int moduleId, int requestId) async { -// // loadChatHistoryLoading = true; -// // notifyListeners(); -// chatLoginResponse = await ChatApiClient().loadChatHistory(moduleId, requestId); -// loadChatHistoryLoading = false; -// notifyListeners(); -// } + Future submitQuestionare(Map payload) async { + try { + final response = await ApiManager.instance.post(URLs.submitSurvey.toString().replaceFirst("/mobile/", "/api/"), body: payload); + if (response.statusCode >= 200 && response.statusCode < 300) { + return true; + } + } catch (ex) { + "Failed, Retry.".showToast; + } + return false; + } } From a04ae0c8331b8b5ff4da593cb37932706d2d8f93 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 16 Nov 2025 10:02:58 +0300 Subject: [PATCH 15/31] attachment fixes --- assets/images/attachment_icon.svg | 3 + lib/controllers/api_routes/urls.dart | 1 + lib/main.dart | 4 +- .../activity_maintenance_model.dart | 2 +- .../models/engineer_data_model.dart | 53 +++ .../equipment_internal_audit_data_model.dart | 14 +- .../internal_audit_attachment_model.dart | 14 +- .../system_internal_audit_data_model.dart | 16 + .../system_internal_audit_form_model.dart | 13 +- ...odel.dart => update_audit_form_model.dart} | 37 ++- .../create_equipment_internal_audit_form.dart | 2 +- .../equipment_internal_audit_detail_page.dart | 47 ++- .../update_equipment_internal_audit_page.dart | 257 +++++++-------- .../create_system_internal_audit_form.dart | 25 +- .../system_internal_audit_detail_page.dart | 102 ++++-- .../update_system_internal_audit_page.dart | 301 +++++++++--------- .../provider/internal_audit_provider.dart | 48 ++- 17 files changed, 556 insertions(+), 383 deletions(-) create mode 100644 assets/images/attachment_icon.svg create mode 100644 lib/modules/internal_audit_module/models/engineer_data_model.dart rename lib/modules/internal_audit_module/models/{audit_form_model.dart => update_audit_form_model.dart} (64%) diff --git a/assets/images/attachment_icon.svg b/assets/images/attachment_icon.svg new file mode 100644 index 00000000..d0da9eaf --- /dev/null +++ b/assets/images/attachment_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 36d8e431..e7cf01b2 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -322,6 +322,7 @@ class URLs { static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem"; static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer"; + static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer"; static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID"; } diff --git a/lib/main.dart b/lib/main.dart index c5b39ef2..1ad94683 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -31,6 +31,7 @@ import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart'; @@ -365,7 +366,8 @@ class MyApp extends StatelessWidget { HelpCenterPage.id: (_) => const HelpCenterPage(), CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(), CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(), - UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(), + UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(), + UpdateSystemInternalAuditPage.id: (_) => UpdateSystemInternalAuditPage(), // SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), // SwipeHistoryView.routeName: (_) => const SwipeHistoryView(), }, diff --git a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart index dda5432b..21541769 100644 --- a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart +++ b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart @@ -31,11 +31,11 @@ class ActivityMaintenanceHelperModel { WorkOrderAssignedEmployee? assignedEmployee; SuppEngineerWorkOrders? supEngineer; ActivityMaintenanceAssistantEmployees? modelAssistantEmployees; + List? assistantEmployList=[]; List? assistantEmployees; List? activityMaintenanceTimers = []; TimerModel? activityMaintenanceTimerModel = TimerModel(); TimerModel? activityTimePicker; - List? assistantEmployList=[]; List? timerModelList = []; ActivityMaintenanceHelperModel( diff --git a/lib/modules/internal_audit_module/models/engineer_data_model.dart b/lib/modules/internal_audit_module/models/engineer_data_model.dart new file mode 100644 index 00000000..dbb34d24 --- /dev/null +++ b/lib/modules/internal_audit_module/models/engineer_data_model.dart @@ -0,0 +1,53 @@ +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; + +class EngineerData { + int? id; + String? debrief; + String? startTime; + String? endTime; + double? totalHours; + bool? isComplete; + int? statusId; + int? requestId; + List? attachments; + + EngineerData({ + this.id, + this.debrief, + this.startTime, + this.endTime, + this.totalHours, + this.isComplete, + this.statusId, + this.requestId, + this.attachments, + }); + + EngineerData.fromJson(Map json) { + id = json['id']; + debrief = json['debrief']; + startTime = json['startTime']; + endTime = json['endTime']; + totalHours = (json['totalHours'] as num?)?.toDouble(); + isComplete = json['isComplete']; + statusId = json['statusId']; + requestId = json['requestId']; + attachments = json['attachments'] != null ? (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList() : []; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['debrief'] = debrief; + data['startTime'] = startTime; + data['endTime'] = endTime; + data['totalHours'] = totalHours; + data['isComplete'] = isComplete; + data['statusId'] = statusId; + data['requestId'] = requestId; + if (attachments != null) { + data['attachments'] = attachments!.map((e) => e.toJson()).toList(); + } + return data; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart index be9c00bb..92f41bab 100644 --- a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart @@ -1,4 +1,5 @@ import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; @@ -15,6 +16,8 @@ class EquipmentInternalAuditDataModel { String? remarks; List? equipmentsFindings; List? attachments; + EngineerData? engineerData; + EquipmentInternalAuditDataModel({ this.id, @@ -29,6 +32,7 @@ class EquipmentInternalAuditDataModel { this.remarks, this.equipmentsFindings, this.attachments, + this.engineerData, }); EquipmentInternalAuditDataModel.fromJson(Map json) { @@ -48,7 +52,14 @@ class EquipmentInternalAuditDataModel { equipmentsFindings!.add(EquipmentsFinding.fromJson(v)); }); } - // attachments = json['attachments'] != null ? List.from(json['attachments']) : []; + attachments = json['attachments'] != null + ? (json['attachments'] as List) + .map((e) => InternalAuditAttachments.fromJson(e)) + .where((e) => e.name != null) // optional filter if you want to skip null names + .toList() + : []; + engineerData = json['engineerData'] != null ? EngineerData.fromJson(json['engineerData']) : null; + } Map toJson() { @@ -76,6 +87,7 @@ class EquipmentInternalAuditDataModel { equipmentsFindings!.map((v) => v.toJson()).toList(); } data['attachments'] = attachments; + if (engineerData != null) data['engineerData'] = engineerData!.toJson(); return data; } } diff --git a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart index a81f2d17..5e21d5ae 100644 --- a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart +++ b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart @@ -1,23 +1,27 @@ +import 'dart:developer'; + class InternalAuditAttachments { - InternalAuditAttachments({this.id,this.originalName, this.name,this.createdBy}); + InternalAuditAttachments({this.id, this.originalName, this.name, this.createdBy}); int? id; String? name; String? originalName; - String ?createdBy; + String? createdBy; + InternalAuditAttachments.fromJson(Map json) { + log('name is ${json['name']}'); id = json['id']; - name = json['name']; + name = (json['name'] != null && !json['name'].toString().startsWith('data:image/jpeg')) ? json['name'] : null; originalName = json['originalName']; createdBy = json['createdBy']; } Map toJson() { final Map data = {}; - // data['id'] = id; + data['id'] = id; data['name'] = name; data['originalName'] = originalName; // data['createdBy'] = createdBy; return data; } -} \ No newline at end of file +} diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart index ae84e97f..0546ccdc 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart @@ -1,4 +1,6 @@ import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; class SystemInternalAuditDataModel { @@ -17,6 +19,8 @@ class SystemInternalAuditDataModel { String? createdDate; String? modifiedBy; String? modifiedDate; + List? attachments; + EngineerData? engineerData; SystemInternalAuditDataModel({ this.id, @@ -34,6 +38,8 @@ class SystemInternalAuditDataModel { this.createdDate, this.modifiedBy, this.modifiedDate, + this.attachments, + this.engineerData, }); SystemInternalAuditDataModel.fromJson(Map json) { @@ -52,6 +58,13 @@ class SystemInternalAuditDataModel { createdDate = json['createdDate']; modifiedBy = json['modifiedBy']; modifiedDate = json['modifiedDate']; + attachments = json['attachments'] != null + ? (json['attachments'] as List) + .map((e) => InternalAuditAttachments.fromJson(e)) + .where((e) => e.name != null) // optional filter if you want to skip null names + .toList() + : []; + engineerData = json['engineerData'] != null ? EngineerData.fromJson(json['engineerData']) : null; } Map toJson() { @@ -71,6 +84,7 @@ class SystemInternalAuditDataModel { data['createdDate'] = createdDate; data['modifiedBy'] = modifiedBy; data['modifiedDate'] = modifiedDate; + if (engineerData != null) data['engineerData'] = engineerData!.toJson(); return data; } } @@ -120,3 +134,5 @@ class Auditor { return data; } } + + diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart index 4082eb03..3fda34d0 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart @@ -1,7 +1,7 @@ - import 'dart:developer'; import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; class SystemInternalAuditFormModel { int? id; @@ -13,12 +13,13 @@ class SystemInternalAuditFormModel { int? correctiveMaintenanceId; int? planPreventiveVisitId; int? assetTransferId; + List? attachments = []; int? taskJobId; int? taskAlertJobId; int? gasRefillId; int? planRecurrentTaskId; int? statusId; - SystemAuditWorkOrderDetailModel ?workOrderDetailModel; + SystemAuditWorkOrderDetailModel? workOrderDetailModel; SystemInternalAuditFormModel({ this.id, @@ -36,6 +37,7 @@ class SystemInternalAuditFormModel { this.planRecurrentTaskId, this.workOrderDetailModel, this.statusId, + this.attachments, }); Map toJson() { @@ -54,6 +56,7 @@ class SystemInternalAuditFormModel { 'gasRefillId': gasRefillId, 'planRecurrentTaskId': planRecurrentTaskId, 'statusId': statusId, + 'attachments': attachments?.map((e) => e.toJson()).toList(), }; } } @@ -73,12 +76,13 @@ class WoAutoCompleteModel { Map toJson() { final Map data = {}; - data['id'] =id; + data['id'] = id; data['woOrderNo'] = workOrderNo; data['displayName'] = workOrderNo; return data; } } + class SystemAuditWorkOrderDetailModel { String? createdBy; DateTime? createdDate; @@ -196,6 +200,3 @@ class SystemAuditWorkOrderDetailModel { }; } } - - - diff --git a/lib/modules/internal_audit_module/models/audit_form_model.dart b/lib/modules/internal_audit_module/models/update_audit_form_model.dart similarity index 64% rename from lib/modules/internal_audit_module/models/audit_form_model.dart rename to lib/modules/internal_audit_module/models/update_audit_form_model.dart index dd3e6975..6942d51f 100644 --- a/lib/modules/internal_audit_module/models/audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/update_audit_form_model.dart @@ -1,5 +1,6 @@ import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; class AuditFormModel { int? id; @@ -12,19 +13,24 @@ class AuditFormModel { List? attachments; bool? isComplete; TimerModel? auditTimerModel = TimerModel(); + List? auditTimers = []; + TimerModel? auditTimePicker; + List? timerModelList = []; - AuditFormModel({ - this.id, - this.requestId, - this.debrief, - this.startTime, - this.endTime, - this.totalHours, - this.createdDate, - this.attachments, - this.isComplete, - this.auditTimerModel, - }); + AuditFormModel( + {this.id, + this.requestId, + this.debrief, + this.startTime, + this.endTime, + this.totalHours, + this.createdDate, + this.attachments, + this.isComplete, + this.auditTimerModel, + this.timerModelList, + this.auditTimePicker, + this.auditTimers}); AuditFormModel.fromJson(Map json) { id = json['id']; @@ -34,9 +40,7 @@ class AuditFormModel { endTime = json['endTime'] != null ? DateTime.tryParse(json['endTime']) : null; totalHours = json['totalHours']?.toDouble(); if (json['attachments'] != null) { - attachments = (json['attachments'] as List) - .map((e) => InternalAuditAttachments.fromJson(e)) - .toList(); + attachments = (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList(); } isComplete = json['isComplete']; } @@ -48,9 +52,10 @@ class AuditFormModel { 'debrief': debrief, 'startTime': startTime?.toIso8601String(), 'endTime': endTime?.toIso8601String(), + // 'auditTimer': auditTimers, 'totalHours': totalHours, 'attachments': attachments?.map((e) => e.toJson()).toList(), 'isComplete': isComplete, }; } -} \ No newline at end of file +} diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart index db29aee6..532a5b14 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart @@ -111,7 +111,7 @@ class _CreateEquipmentInternalAuditFormState extends State allAttachments = []; @override void initState() { @@ -46,6 +50,13 @@ class _EquipmentInternalAuditDetailPageState extends State getAuditData() async { model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId); + allAttachments.clear(); + allAttachments = [ + ...(model?.attachments ?? []), + ...(model?.engineerData?.attachments ?? []), + ]; + + } @override @@ -62,8 +73,8 @@ class _EquipmentInternalAuditDetailPageState extends State provider.isLoading, builder: (_, isLoading, __) { if (isLoading) return const ALoading(); - if (model==null) return NoDataFound(message: context.translation.noDataFound).center; - return Column( + if (model == null) return NoDataFound(message: context.translation.noDataFound).center; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SingleChildScrollView( @@ -76,24 +87,19 @@ class _EquipmentInternalAuditDetailPageState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], - //TODO need to check for attachments backend need to fix the name they are sending wrong string - // if (model!.attachments!.isNotEmpty) ...[ - // const Divider().defaultStyle(context), - // Text( - // "Attachments".addTranslation, - // style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - // ), - // 8.height, - // FilesList(images: model!.attachments!.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), - // ], ], ).paddingAll(0).toShadowContainer(context), ).expanded, @@ -103,8 +109,17 @@ class _EquipmentInternalAuditDetailPageState extends State UpdateEquipmentInternalAuditPage(model: model))); + onPressed: () async { + final result = await Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => UpdateEquipmentInternalAuditPage(model: model), + ), + ); + if (result == true) { + await getAuditData(); + setState(() {}); // refresh UI with new model + } + // Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateEquipmentInternalAuditPage(model: model))); }), ), ], diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart index 02115d62..e5d3072f 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart @@ -2,9 +2,9 @@ import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; @@ -14,12 +14,14 @@ import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; @@ -32,7 +34,7 @@ class UpdateEquipmentInternalAuditPage extends StatefulWidget { static const String id = "update-equipment-internal-audit"; EquipmentInternalAuditDataModel? model; - UpdateEquipmentInternalAuditPage({Key? key,this.model}) : super(key: key); + UpdateEquipmentInternalAuditPage({Key? key, this.model}) : super(key: key); @override State createState() => _UpdateEquipmentInternalAuditPageState(); @@ -46,6 +48,7 @@ class _UpdateEquipmentInternalAuditPageState extends State _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); List _attachments = []; + //TODO need to check if it's needed or not.. List timerList = []; @@ -54,137 +57,93 @@ class _UpdateEquipmentInternalAuditPageState extends State GenericAttachmentModel(id: e.id?.toInt()??0, name: e.name!)).toList() ?? []; + _attachments = widget.model?.engineerData?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? []; - } - void calculateWorkingTime() { - // final timers = _formModel.gasRefillTimers ?? []; - // totalWorkingHours = timers.fold(0.0, (sum, item) { - // if (item.startDate == null || item.endDate == null) return sum; - // try { - // final start = DateTime.parse(item.startDate!); - // final end = DateTime.parse(item.endDate!); - // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours - // return sum + diffInHours; - // } catch (_) { - // return sum; - // } - // }); - // - // timerList = timers.map((e) { - // return TimerHistoryModel( - // id: e.id, - // startTime: e.startDate, - // endTime: e.endDate, - // workingHours: e.workingHours, - // ); - // }).toList(); + calculateWorkingTime(); } + void calculateWorkingTime() { + final helperModel = formModel; + final timers = helperModel.auditTimers ?? []; + totalWorkingHours = timers.fold(0.0, (sum, item) { + if (item.startDate == null || item.endDate == null) return sum; + try { + final start = DateTime.parse(item.startDate!); + final end = DateTime.parse(item.endDate!); + final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + return sum + diffInHours; + } catch (_) { + return sum; + } + }); + timerList = timers.map((e) { + return TimerHistoryModel( + id: e.id, + startTime: e.startDate, + endTime: e.endDate, + workingHours: e.startDate, + ); + }).toList(); + } _onSubmit(BuildContext context) async { bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; - InternalAuditProvider provider = Provider.of(context,listen: false); + InternalAuditProvider provider = Provider.of(context, listen: false); + + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + formModel.auditTimers ??= []; + if (formModel.auditTimePicker != null) { + int durationInSecond = formModel.auditTimePicker!.endAt!.difference(formModel.auditTimePicker!.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: formModel.auditTimePicker!.startAt!.toIso8601String(), // Handle potential null + endDate: formModel.auditTimePicker!.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + } + formModel.timerModelList?.forEach((timer) { + int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: timer.startAt!.toIso8601String(), // Handle potential null + endDate: timer.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + }); _formKey.currentState!.save(); formModel.attachments = []; for (var item in _attachments) { - String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') - ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") - : item.name ?? ''; + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; formModel.attachments!.add( InternalAuditAttachments( id: item.id, originalName: fileName, - // name: fileName, + name: fileName, ), ); } - provider.updateEquipmentInternalAudit(model: formModel); + final success = await provider.updateEquipmentInternalAudit(model: formModel); + Navigator.pop(context); + if (formModel.isComplete == true) { + //Navigate to List screen. + } else if (formModel.isComplete == false) { + //Navigate to Detail screen. + if (success) { + Navigator.of(context).pop(true); + } else { + Fluttertoast.showToast(msg: 'Failed to update'); + } - log('payload ${formModel.toJson()}'); - - - - // if (isTimerPickerEnable) { - // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.gasRefillTimePicker == null) { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // } else { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // - // if (_currentDetails.deliverdQty == null) { - // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); - // return false; - // } - // _formModel.gasRefillDetails = []; - // _formModel.gasRefillDetails?.add(_currentDetails); - // - // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; - // if (_formModel.gasRefillTimePicker != null) { - // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null - // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // } - // _formModel.timerModelList?.forEach((timer) { - // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: timer.startAt!.toIso8601String(), // Handle potential null - // endDate: timer.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // }); - // _formModel.gasRefillAttachments = []; - // for (var item in _attachments) { - // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; - // _formModel.gasRefillAttachments?.add(GasRefillAttachments( - // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); - // } - - // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { - // Navigator.pop(context); - // if (success) { - // if (status == 1) { - // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); - // // when click complete then this request remove from the list and status changes to closed.. - // _gasRefillProvider?.reset(); - // allRequestsProvider.getAllRequests(context, typeTransaction: 2); - // } - // Navigator.pop(context); - // } - // }); + } } @override @@ -206,7 +165,6 @@ class _UpdateEquipmentInternalAuditPageState extends State? timerModelList = []; return Column( mainAxisSize: MainAxisSize.min, children: [ + //TODO multiple timer .. + // AppTimer( + // label: context.translation.timer, + // timer: formModel.auditTimerModel, + // // enabled: enableTimer, + // pickerTimer: formModel.auditTimePicker, + // pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + // onPick: (time) { + // formModel.auditTimePicker = time; + // setState(() {}); + // log('Time picker start ${formModel.auditTimePicker?.startAt}'); + // log('Time picker end ${formModel.auditTimePicker?.endAt}'); + // }, + // timerProgress: (isRunning) {}, + // onChange: (timer) async { + // formModel.auditTimerModel = timer; + // log('start ${formModel.auditTimerModel?.startAt}'); + // log('end ${formModel.auditTimerModel?.endAt}'); + // if (timer.startAt != null && timer.endAt != null) { + // formModel.timerModelList = formModel.timerModelList ?? []; + // formModel.timerModelList!.add(timer); + // } + // setState(() {}); + // log('list length ${formModel.timerModelList?.length}'); + // return true; + // }, + // ), AppTimer( label: context.translation.workingHours, - timer: timer, + timer: formModel.auditTimerModel, pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), - pickerTimer: timerPicker, - onPick: (time) { - updateTimer(timer: timer); - + pickerTimer: formModel.auditTimePicker, + onPick: (timer) { + updateTimer(timer: timer); }, width: double.infinity, decoration: BoxDecoration( diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart index a443588d..20ab2451 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart @@ -15,6 +15,7 @@ import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; @@ -47,7 +48,7 @@ class _CreateSystemInternalAuditFormState extends State _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - final List _deviceImages = []; + final List _attachments = []; late TextEditingController _woAutoCompleteController; bool showLoading = false; @@ -148,15 +149,14 @@ class _CreateSystemInternalAuditFormState extends State(context, listen: false); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); + _model.attachments=[]; + for (var item in _attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + _model.attachments?.add(InternalAuditAttachments(id: item.id, name: fileName)); + } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); _model.auditorId = context.userProvider.user?.userID; bool status = await internalAuditProvider.addSystemInternalAudit(context: context, request: _model); diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart index 7052f2fd..484d5b4e 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart @@ -1,19 +1,24 @@ -import 'dart:io'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; + import 'package:test_sa/views/widgets/loaders/app_loading.dart'; class SystemInternalAuditDetailPage extends StatefulWidget { @@ -30,8 +35,9 @@ class SystemInternalAuditDetailPage extends StatefulWidget { class _SystemInternalAuditDetailPageState extends State { bool isWoType = true; - // EquipmentInternalAuditDataModel? model; + SystemInternalAuditDataModel? model; late InternalAuditProvider _internalAuditProvider; + List allAttachments = []; @override void initState() { @@ -43,7 +49,12 @@ class _SystemInternalAuditDetailPageState extends State getAuditData() async { - await _internalAuditProvider.getInternalSystemAuditById(widget.auditId); + model = await _internalAuditProvider.getInternalSystemAuditById(widget.auditId); + allAttachments.clear(); + allAttachments = [ + ...(model?.attachments ?? []), + ...(model?.engineerData?.attachments ?? []), + ]; } @override @@ -70,28 +81,27 @@ class _SystemInternalAuditDetailPageState extends State URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), - // ], + if (allAttachments.isNotEmpty) ...[ + const Divider().defaultStyle(context), + Text( + "Attachments".addTranslation, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), + ], ], ).paddingAll(0).toShadowContainer(context), ).expanded, @@ -101,8 +111,16 @@ class _SystemInternalAuditDetailPageState extends State UpdateSystemInternalAuditPage(model: model), + ), + ); + if (result == true) { + await getAuditData(); + setState(() {}); // refresh UI with new model + } }), ), ], @@ -112,6 +130,7 @@ class _SystemInternalAuditDetailPageState extends State createState() => _UpdateInternalAuditPageState(); + State createState() => _UpdateSystemInternalAuditPageState(); } -class _UpdateInternalAuditPageState extends State { +class _UpdateSystemInternalAuditPageState extends State { final bool _isLoading = false; double totalWorkingHours = 0.0; - late UserProvider _userProvider; - final TextEditingController _commentController = TextEditingController(); + AuditFormModel formModel = AuditFormModel(); final TextEditingController _workingHoursController = TextEditingController(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - bool _firstTime = true; List _attachments = []; + + //TODO need to check if it's needed or not.. List timerList = []; @override void initState() { + populateForm(); super.initState(); } - void calculateWorkingTime() { - // final timers = _formModel.gasRefillTimers ?? []; - // totalWorkingHours = timers.fold(0.0, (sum, item) { - // if (item.startDate == null || item.endDate == null) return sum; - // try { - // final start = DateTime.parse(item.startDate!); - // final end = DateTime.parse(item.endDate!); - // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours - // return sum + diffInHours; - // } catch (_) { - // return sum; - // } - // }); - // - // timerList = timers.map((e) { - // return TimerHistoryModel( - // id: e.id, - // startTime: e.startDate, - // endTime: e.endDate, - // workingHours: e.workingHours, - // ); - // }).toList(); + void populateForm() { + formModel.requestId = widget.model?.id; + formModel.id = widget.model?.id; + _attachments = widget.model?.engineerData?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? []; + + calculateWorkingTime(); } - @override - void setState(VoidCallback fn) { - if (mounted) super.setState(() {}); + void calculateWorkingTime() { + final helperModel = formModel; + final timers = helperModel.auditTimers ?? []; + totalWorkingHours = timers.fold(0.0, (sum, item) { + if (item.startDate == null || item.endDate == null) return sum; + try { + final start = DateTime.parse(item.startDate!); + final end = DateTime.parse(item.endDate!); + final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + return sum + diffInHours; + } catch (_) { + return sum; + } + }); + timerList = timers.map((e) { + return TimerHistoryModel( + id: e.id, + startTime: e.startDate, + endTime: e.endDate, + workingHours: e.startDate, + ); + }).toList(); } - _onSubmit(BuildContext context, int status) async { + _onSubmit(BuildContext context) async { bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + InternalAuditProvider provider = Provider.of(context, listen: false); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - // if (isTimerPickerEnable) { - // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.gasRefillTimePicker == null) { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // } else { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // - // if (_currentDetails.deliverdQty == null) { - // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); - // return false; - // } - // _formModel.gasRefillDetails = []; - // _formModel.gasRefillDetails?.add(_currentDetails); - // - // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; - // if (_formModel.gasRefillTimePicker != null) { - // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null - // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // } - // _formModel.timerModelList?.forEach((timer) { - // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: timer.startAt!.toIso8601String(), // Handle potential null - // endDate: timer.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // }); - // _formModel.gasRefillAttachments = []; - // for (var item in _attachments) { - // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; - // _formModel.gasRefillAttachments?.add(GasRefillAttachments( - // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); - // } + formModel.auditTimers ??= []; + if (formModel.auditTimePicker != null) { + int durationInSecond = formModel.auditTimePicker!.endAt!.difference(formModel.auditTimePicker!.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: formModel.auditTimePicker!.startAt!.toIso8601String(), // Handle potential null + endDate: formModel.auditTimePicker!.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + } + formModel.timerModelList?.forEach((timer) { + int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: timer.startAt!.toIso8601String(), // Handle potential null + endDate: timer.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + }); - // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { - // Navigator.pop(context); - // if (success) { - // if (status == 1) { - // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); - // // when click complete then this request remove from the list and status changes to closed.. - // _gasRefillProvider?.reset(); - // allRequestsProvider.getAllRequests(context, typeTransaction: 2); - // } - // Navigator.pop(context); - // } - // }); + _formKey.currentState!.save(); + formModel.attachments = []; + for (var item in _attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + formModel.attachments!.add( + InternalAuditAttachments( + id: item.id, + // originalName: fileName, + name: fileName, + ), + ); + } + log('submit press'); + log('data ${formModel.toJson()}'); + final success = await provider.updateSystemInternalAudit(model: formModel); + Navigator.pop(context); + if (formModel.isComplete == true) { + //Navigate to List screen. + } else if (formModel.isComplete == false) { + if (success) { + Navigator.of(context).pop(true); + } else { + Fluttertoast.showToast(msg: 'Failed to update'); + } + } } @override void dispose() { - _commentController.dispose(); _workingHoursController.dispose(); super.dispose(); } void updateTimer({TimerModel? timer}) { - // _formModel.timer = timer; - // if (timer?.startAt != null && timer?.endAt != null) { - // _formModel.timerModelList = _formModel.timerModelList ?? []; - // _formModel.timerModelList!.add(timer!); - // } - // notifyListeners(); + if (timer?.startAt != null && timer?.endAt != null) { + final start = timer!.startAt!; + final end = timer.endAt!; + + final difference = end.difference(start); + final totalHours = difference.inSeconds / 3600.0; + formModel.startTime = start; + formModel.endTime = end; + formModel.totalHours = totalHours; + } } @override Widget build(BuildContext context) { - _userProvider = Provider.of(context); return Scaffold( appBar: DefaultAppBar( title: 'Update Information'.addTranslation, onWillPopScope: () { - _onSubmit(context, 0); + formModel.isComplete = false; + _onSubmit(context); }, ), key: _scaffoldKey, @@ -210,21 +198,22 @@ class _UpdateInternalAuditPageState extends State { hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), alignLabelWithHint: true, + initialValue: formModel.debrief, backgroundColor: AppColor.fieldBgColor(context), showShadow: false, - controller: _commentController, - onChange: (value) {}, - onSaved: (value) {}, + onSaved: (value) { + formModel.debrief = value; + }, ), 8.height, _timerWidget(context, totalWorkingHours), 16.height, AttachmentPicker( - label: context.translation.attachFiles, + label: 'Upload Attachment', attachment: _attachments, buttonColor: AppColor.primary10, onlyImages: false, - buttonIcon: 'image-plus'.toSvgAsset( + buttonIcon: 'attachment_icon'.toSvgAsset( color: AppColor.primary10, ), ), @@ -238,17 +227,22 @@ class _UpdateInternalAuditPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ AppFilledButton( - label: context.translation.save, - buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, - textColor: context.isDark ? AppColor.white10 : AppColor.black10, - onPressed: () => _onSubmit(context, 0), - ).expanded, + label: context.translation.save, + buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, + textColor: context.isDark ? AppColor.white10 : AppColor.black10, + onPressed: () { + log('button press '); + formModel.isComplete = false; + _onSubmit(context); + }).expanded, 12.width, AppFilledButton( - label: context.translation.complete, - buttonColor: AppColor.primary10, - onPressed: () => _onSubmit(context, 1), - ).expanded, + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: () { + formModel.isComplete = true; + _onSubmit(context); + }).expanded, ], ), ), @@ -258,35 +252,52 @@ class _UpdateInternalAuditPageState extends State { ).handlePopScope( cxt: context, onSave: () { - _onSubmit(context, 0); + formModel.isComplete = false; + _onSubmit(context); }); } Widget _timerWidget(BuildContext context, double totalWorkingHours) { - TimerModel? timer = TimerModel(); - TimerModel? timerPicker; - List? timerModelList = []; return Column( mainAxisSize: MainAxisSize.min, children: [ + // AppTimer( + // label: context.translation.timer, + // timer: formModel.auditTimerModel, + // // enabled: enableTimer, + // pickerTimer: formModel.auditTimePicker, + // pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + // onPick: (time) { + // formModel.auditTimePicker = time; + // }, + // timerProgress: (isRunning) {}, + // onChange: (timer) async { + // formModel.auditTimerModel = timer; + // if (timer.startAt != null && timer.endAt != null) { + // formModel.timerModelList = formModel.timerModelList ?? []; + // formModel.timerModelList!.add(timer); + // } + // return true; + // }, + // ), AppTimer( label: context.translation.workingHours, - timer: timer, - // pickerFromDate: DateTime.tryParse(widget.gasRefillModel?.createdDate ?? ''), - pickerFromDate: DateTime.tryParse(''), - pickerTimer: timerPicker, + timer: formModel.auditTimerModel, + pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + pickerTimer: formModel.auditTimePicker, onPick: (time) { - //timerPicker = time; + updateTimer(timer: time); }, width: double.infinity, decoration: BoxDecoration( color: AppColor.fieldBgColor(context), - // color: AppColor.neutral100, borderRadius: BorderRadius.circular(10), ), timerProgress: (isRunning) {}, onChange: (timer) async { updateTimer(timer: timer); + log('here onChange ${timer.startAt}'); + return true; }, ), diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart index 314fb2d9..75f0a436 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -10,9 +10,10 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset_search.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; @@ -57,22 +58,30 @@ class InternalAuditProvider extends ChangeNotifier { } } - Future getInternalSystemAuditById(int id) async { + Future getInternalSystemAuditById(int id) async { try { isLoading = true; notifyListeners(); Response response = await ApiManager.instance.get("${URLs.getInternalAuditSystemById}?AuditSystemId=$id"); - if (response.statusCode >= 200 && response.statusCode < 300) {} - isLoading = false; - notifyListeners(); - return 0; + if (response.statusCode >= 200 && response.statusCode < 300) { + final decodedBody = jsonDecode(response.body); + SystemInternalAuditDataModel model = SystemInternalAuditDataModel.fromJson(decodedBody["data"]); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; + } } catch (error) { isLoading = false; notifyListeners(); - return -1; + return null; } } - Future loadAllWorkOrderDetailsByID({required int workOrderTypeId,required int workOrderId}) async { + + Future loadAllWorkOrderDetailsByID({required int workOrderTypeId, required int workOrderId}) async { try { isLoading = true; notifyListeners(); @@ -94,6 +103,7 @@ class InternalAuditProvider extends ChangeNotifier { return null; } } + Future updateEquipmentInternalAudit({required AuditFormModel model}) async { isLoading = true; Response response; @@ -114,6 +124,27 @@ class InternalAuditProvider extends ChangeNotifier { } } + Future updateSystemInternalAudit({required AuditFormModel model}) async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.put(URLs.updateAuditSystemEngineer, body: model.toJson()); + stateCode = response.statusCode; + isLoading = false; + notifyListeners(); + log('status code ${stateCode}'); + if (stateCode == 200) { + return true; + } + return false; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; + } + } + Future addEquipmentInternalAudit({ required BuildContext context, required EquipmentInternalAuditFormModel request, @@ -137,6 +168,7 @@ class InternalAuditProvider extends ChangeNotifier { return status; } } + Future addSystemInternalAudit({ required BuildContext context, required SystemInternalAuditFormModel request, From a902204ff13ef677315d455005d12e7e2e57ffed Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 16 Nov 2025 11:30:08 +0300 Subject: [PATCH 16/31] survey improvements. --- lib/controllers/api_routes/api_manager.dart | 4 +++- lib/extensions/context_extension.dart | 4 ++-- lib/modules/cx_module/survey/survey_page.dart | 17 ++++++++++++----- .../cx_module/survey/survey_provider.dart | 16 ++++++++++++---- .../swipe_module/dialoge/confirm_dialog.dart | 4 ++-- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/lib/controllers/api_routes/api_manager.dart b/lib/controllers/api_routes/api_manager.dart index 20c55464..9594acd0 100644 --- a/lib/controllers/api_routes/api_manager.dart +++ b/lib/controllers/api_routes/api_manager.dart @@ -42,7 +42,9 @@ class ApiManager { if (jsonDecode(response.body) is Map) { final message = jsonDecode(response.body)["message"]; if (message != null && message.toString().isNotEmpty) { - Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG); + if (enableToastMessage) { + Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG); + } } } } diff --git a/lib/extensions/context_extension.dart b/lib/extensions/context_extension.dart index 82960243..f85af74c 100644 --- a/lib/extensions/context_extension.dart +++ b/lib/extensions/context_extension.dart @@ -31,9 +31,9 @@ extension BuildContextExtension on BuildContext { - void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog( + void showConfirmDialog(String message, {String? title, VoidCallback? onTap, String? okTitle}) => showDialog( context: this, - builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title), + builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title,okTitle: okTitle), ); Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet( diff --git a/lib/modules/cx_module/survey/survey_page.dart b/lib/modules/cx_module/survey/survey_page.dart index 75a3a28e..71fa34f9 100644 --- a/lib/modules/cx_module/survey/survey_page.dart +++ b/lib/modules/cx_module/survey/survey_page.dart @@ -34,6 +34,7 @@ class _SurveyPageState extends State { // int serviceSatisfiedRating = -1; int serviceProvidedRating = -1; String comments = ""; + String message = ""; bool loading = false; @@ -50,7 +51,10 @@ class _SurveyPageState extends State { void getSurveyQuestion() async { loading = true; setState(() {}); - questionnaire = await Provider.of(context, listen: false).getQuestionnaire(widget.surveyId); + await Provider.of(context, listen: false).getQuestionnaire(widget.surveyId, (msg, questions) { + message = msg; + questionnaire = questions; + }); for (int i = 0; i < (questionnaire?.surveyQuestions?.length ?? 0); i++) { answers.add(SurveyAnswers( questionId: questionnaire!.surveyQuestions![i].questionId!, @@ -79,18 +83,18 @@ class _SurveyPageState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - "Failed to get questionnaire", + message.isNotEmpty ? message : "Failed to get questionnaire", overflow: TextOverflow.ellipsis, maxLines: 1, style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w500), ), 24.height, AppFilledButton( - label: "Retry", + label: message.isNotEmpty ? "Go Back " : "Retry", maxWidth: true, buttonColor: AppColor.primary10, onPressed: () { - getSurveyQuestion(); + message.isNotEmpty ? Navigator.pop(context) : getSurveyQuestion(); }, ).paddingOnly(start: 48, end: 48) ], @@ -171,7 +175,10 @@ class _SurveyPageState extends State { bool isSuccess = await Provider.of(context, listen: false).submitQuestionare(payload); Utils.hideLoading(context); if (isSuccess) { - //getSurveyQuestion(); + context.showConfirmDialog("Thank you for submitting the Feedback. It value for us to improve system and overall experience.", title: "Thanks!", okTitle: "Go Back", + onTap: () { + Navigator.pop(context); + }); } //reload Data } }, diff --git a/lib/modules/cx_module/survey/survey_provider.dart b/lib/modules/cx_module/survey/survey_provider.dart index f1a76a86..4fe0b468 100644 --- a/lib/modules/cx_module/survey/survey_provider.dart +++ b/lib/modules/cx_module/survey/survey_provider.dart @@ -18,16 +18,24 @@ class SurveyProvider with ChangeNotifier { // ChatApiClient().chatLoginResponse = null; } - Future getQuestionnaire(int surveySubmissionId) async { + getQuestionnaire(int surveySubmissionId, Function(String message, Questionnaire? questionnaire) onResponse) async { + String responseMsg = ""; + Questionnaire? q; try { - final response = await ApiManager.instance.get("${URLs.getQuestionnaire.toString().replaceFirst("/mobile/", "/api/")}?surveySubmissionId=$surveySubmissionId"); + final response = await ApiManager.instance.get("${URLs.getQuestionnaire.toString().replaceFirst("/mobile/", "/api/")}?surveySubmissionId=$surveySubmissionId", enableToastMessage: false); if (response.statusCode >= 200 && response.statusCode < 300) { - return Questionnaire.fromJson(jsonDecode(response.body)["data"]); + if (jsonDecode(response.body)["message"] != null && jsonDecode(response.body)["message"].toString().isNotEmpty) { + responseMsg = jsonDecode(response.body)["message"]; + } else { + q = Questionnaire.fromJson(jsonDecode(response.body)["data"]); + } } } catch (ex) { "Failed, Retry.".showToast; } - return null; + onResponse(responseMsg, q); + + // return null; } Future submitQuestionare(Map payload) async { diff --git a/lib/new_views/swipe_module/dialoge/confirm_dialog.dart b/lib/new_views/swipe_module/dialoge/confirm_dialog.dart index 7b76d715..60db0c03 100644 --- a/lib/new_views/swipe_module/dialoge/confirm_dialog.dart +++ b/lib/new_views/swipe_module/dialoge/confirm_dialog.dart @@ -17,7 +17,7 @@ class ConfirmDialog extends StatelessWidget { @override Widget build(BuildContext context) { return Dialog( - backgroundColor:AppColor.background(context), + backgroundColor: AppColor.background(context), shape: const RoundedRectangleBorder(), insetPadding: const EdgeInsets.only(left: 21, right: 21), child: Padding( @@ -32,7 +32,7 @@ class ConfirmDialog extends StatelessWidget { Expanded( child: Text( title ?? "Confirm", - style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: AppColor.headingTextColor(context), height: 35 / 24, letterSpacing: -0.96), + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: AppColor.headingTextColor(context), height: 35 / 24, letterSpacing: -0.96), ).paddingOnly(top: 16), ), IconButton( From db1e7ea0bd8fb5412459c679fa00e482a3bdf314 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 16 Nov 2025 12:53:20 +0300 Subject: [PATCH 17/31] 1 to 1 chat ui completed for text message, with 2 users. --- lib/extensions/string_extensions.dart | 2 +- .../cx_module/chat/chat_api_client.dart | 18 +-- lib/modules/cx_module/chat/chat_page.dart | 111 ++++++++++-------- lib/modules/cx_module/chat/chat_provider.dart | 16 +-- 4 files changed, 82 insertions(+), 65 deletions(-) diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index a8fd4f51..16ae3fec 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -18,7 +18,7 @@ extension StringExtensions on String { String get chatMsgDateWithYear { DateTime dateTime = DateTime.parse(this); - return DateFormat('EEE dd MMM yyyy').format(dateTime); + return DateFormat('EEE dd MMM, yyyy').format(dateTime); } String get toServiceRequestCardFormat { diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index b6d5adc8..9641b0ec 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -78,18 +78,18 @@ class ChatApiClient { Response response = await ApiClient().postJsonForResponse( "${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()}, token: chatLoginResponse!.token); - try { - if (response.statusCode == 200) { - List data = jsonDecode(response.body); - return data.map((elemet) => ChatHistoryResponse.fromJson(elemet)).toList(); + // try { + if (response.statusCode == 200) { + List data = jsonDecode(response.body); + return data.map((elemet) => ChatHistoryResponse.fromJson(elemet)).toList(); - // return UserChatHistoryModel.fromJson(jsonDecode(response.body)); - } else { - return []; - } - } catch (ex) { + // return UserChatHistoryModel.fromJson(jsonDecode(response.body)); + } else { return []; } + // } catch (ex) { + // return []; + // } } Future sendTextMessage(String message, int conversationId) async { diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index f7e8fb5c..ef183c10 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -59,8 +59,17 @@ class _ChatPageState extends State { void getChatToken() { String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; - Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, - Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!, assigneeEmployeeNumber); + String myEmployeeId = context.userProvider.user!.username!; + + // String sender = context.settingProvider.username; + String receiver = context.userProvider.isNurse + ? assigneeEmployeeNumber + : (context.userProvider.isEngineer ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId! : ""); + + // assigneeEmployeeNumber + + // Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, myEmployeeId, assigneeEmployeeNumber); + Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver); } @override @@ -152,21 +161,22 @@ class _ChatPageState extends State { reverse: true, itemBuilder: (cxt, index) { final currentMessage = chatProvider.chatResponseList[index]; - final bool showSenderName = (index == chatProvider.chatResponseList.length - 1) || (currentMessage.userId != chatProvider.chatResponseList[index + 1].userId); - bool isSender = chatProvider.chatResponseList[index].userId == chatProvider.sender?.userId!; + final bool showSenderName = + (index == chatProvider.chatResponseList.length - 1) || (currentMessage.currentUserId != chatProvider.chatResponseList[index + 1].currentUserId); + bool isSender = chatProvider.chatResponseList[index].currentUserId == chatProvider.sender?.userId!; bool showDateHeader = false; if (index == chatProvider.chatResponseList.length - 1) { showDateHeader = true; } else { final nextMessage = chatProvider.chatResponseList[index + 1]; - final currentDate = DateUtils.dateOnly(DateTime.parse(currentMessage.createdAt!)); - final nextDate = DateUtils.dateOnly(DateTime.parse(nextMessage.createdAt!)); + final currentDate = DateUtils.dateOnly(DateTime.parse(currentMessage.createdDate!)); + final nextDate = DateUtils.dateOnly(DateTime.parse(nextMessage.createdDate!)); if (!currentDate.isAtSameMomentAs(nextDate)) { showDateHeader = true; } } return Column(mainAxisSize: MainAxisSize.min, children: [ - if (showDateHeader) dateCard(currentMessage.createdAt?.chatMsgDate ?? ""), + if (showDateHeader) dateCard(currentMessage.createdDate?.chatMsgDateWithYear ?? ""), isSender ? senderMsgCard(showSenderName, chatProvider.chatResponseList[index]) : recipientMsgCard(showSenderName, chatProvider.chatResponseList[index]) ]); }, @@ -200,15 +210,6 @@ class _ChatPageState extends State { suffixIconConstraints: const BoxConstraints(), hintText: "Type your message here...", hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), - // suffixIcon: Row( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.end, - // mainAxisAlignment: MainAxisAlignment.end, - // children: [ - // - // 8.width, - // ], - // ) ), ).expanded, IconButton( @@ -498,12 +499,12 @@ class _ChatPageState extends State { .center; } - Widget senderMsgCard(bool showHeader, ChatResponse? chatResponse, {bool loading = false, String msg = ""}) { + Widget senderMsgCard(bool showHeader, ChatHistoryResponse? chatResponse, {bool loading = false, String msg = ""}) { Widget senderHeader = Row( mainAxisSize: MainAxisSize.min, children: [ Text( - "${chatResponse?.userName ?? "User"}(Me)", + "${chatResponse?.currentUserName ?? "User"}(Me)", overflow: TextOverflow.ellipsis, maxLines: 1, style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), @@ -524,44 +525,60 @@ class _ChatPageState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ if (showHeader) ...[senderHeader, 4.height] else 8.height, - Container( - padding: const EdgeInsets.all(8), - margin: const EdgeInsets.only(right: 26 + 8, left: 26 + 8), - decoration: BoxDecoration( - color: loading ? Colors.transparent : AppColor.white10, - borderRadius: BorderRadius.circular(6), + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Flexible( + fit: FlexFit.loose, + child: Container( + padding: const EdgeInsets.all(8), + margin: const EdgeInsets.only(right: 8, left: 26 + 8), + decoration: BoxDecoration( + color: loading ? Colors.transparent : AppColor.white10, + borderRadius: BorderRadius.circular(6), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + chatResponse?.contant ?? msg, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), + ).toShimmer(context: context, isShow: loading), + if (loading) 4.height, + Text( + chatResponse?.createdDate?.chatMsgTime ?? "2:00 PM", + style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)), + ).toShimmer(context: context, isShow: loading), + ], + )), ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - chatResponse?.content ?? msg, - style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), - ).toShimmer(context: context, isShow: loading), - if (loading) 4.height, - Text( - chatResponse?.createdAt?.chatMsgTime ?? "2:00 PM", - style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)), - ).toShimmer(context: context, isShow: loading), - ], - )), + if (chatResponse != null) + if (chatResponse.isSeen!) + "chat_seen".toSvgAsset(width: 16, height: 16) + else if (chatResponse.isDelivered!) + "chat_delivered".toSvgAsset(width: 16, height: 16) + else + "chat_sent".toSvgAsset(width: 16, height: 16), + (26 + 8).width, + ], + ), ], ), ); } - Widget recipientMsgCard(bool showHeader, ChatResponse? chatResponse, {bool loading = false, String msg = ""}) { + Widget recipientMsgCard(bool showHeader, ChatHistoryResponse? chatResponse, {bool loading = false, String msg = ""}) { String extraSpaces = ""; int length = 0; - if ((chatResponse?.content ?? "").isNotEmpty) { - if (chatResponse!.content!.length < 8) { - length = 8 - chatResponse.content!.length; + if ((chatResponse?.contant ?? "").isNotEmpty) { + if (chatResponse!.contant!.length < 8) { + length = 8 - chatResponse.contant!.length; } } - String contentMsg = chatResponse?.content == null ? msg : chatResponse!.content! + extraSpaces; - print("'$contentMsg'"); + String contentMsg = chatResponse?.contant == null ? msg : chatResponse!.contant! + extraSpaces; Widget recipientHeader = Row( mainAxisSize: MainAxisSize.min, children: [ @@ -572,7 +589,7 @@ class _ChatPageState extends State { ).toShimmer(context: context, isShow: loading), 8.width, Text( - chatResponse?.userName ?? "User", + chatResponse?.currentUserName ?? "User", overflow: TextOverflow.ellipsis, maxLines: 1, style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), @@ -607,7 +624,7 @@ class _ChatPageState extends State { alignment: Alignment.centerRight, widthFactor: 1, child: Text( - chatResponse?.createdAt?.chatMsgTime ?? "2:00 PM", + chatResponse?.createdDate?.chatMsgTime ?? "2:00 PM", style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.white10), ), ).toShimmer(context: context, isShow: loading), diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 84262c5c..c86c5096 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -120,7 +120,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { bool messageIsSending = false; - List chatResponseList = []; + List chatResponseList = []; Participants? sender; Participants? recipient; @@ -137,16 +137,16 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { ChatApiClient().chatLoginResponse = null; } - Future getUserAutoLoginToken(int moduleId, int requestId, String title, String employeeNumber, String assigneeEmployeeNumber) async { + Future getUserAutoLoginToken(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async { reset(); chatLoginTokenLoading = true; notifyListeners(); - chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, employeeNumber); + chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId); chatLoginTokenLoading = false; chatParticipantLoading = true; notifyListeners(); // loadParticipants(moduleId, requestId); - loadChatHistory(moduleId, requestId, employeeNumber, assigneeEmployeeNumber); + loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); } // Future loadParticipants(int moduleId, int requestId) async { @@ -173,8 +173,8 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); } catch (e) {} userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); - // chatResponseList = userChatHistory?.response ?? []; - + chatResponseList = userChatHistory ?? []; + chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); userChatHistoryLoading = false; notifyListeners(); } @@ -186,9 +186,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { ChatResponse? chatResponse = await ChatApiClient().sendTextMessage(message, chatParticipantModel!.id!); if (chatResponse != null) { returnStatus = true; - chatResponseList.add(chatResponse); + // chatResponseList.add(chatResponse); try { - chatResponseList.sort((a, b) => b.createdAt!.compareTo(a.createdAt!)); + chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); } catch (ex) {} } messageIsSending = false; From 47e68b8cc363794ba996166649a4011889c9cd4c Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 16 Nov 2025 13:24:50 +0300 Subject: [PATCH 18/31] switch to dev. --- lib/controllers/api_routes/urls.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 3ef46b03..c848148b 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,8 +4,8 @@ class URLs { static const String appReleaseBuildNumber = "28"; // static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url // static String _baseUrl = "$_host/mobile"; From 781e61814a921c3e8e22ca52f69fe6b6fd0af695 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 16 Nov 2025 14:51:09 +0300 Subject: [PATCH 19/31] survey questionare finalized. --- lib/controllers/api_routes/urls.dart | 4 +-- .../service_request_detail_main_view.dart | 2 +- .../cx_module/survey/questionnaire_model.dart | 5 +++- lib/modules/cx_module/survey/survey_page.dart | 30 ++++++++++--------- .../cx_module/survey/survey_provider.dart | 12 ++++---- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index c848148b..95b2085c 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -8,9 +8,9 @@ class URLs { // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url - // static String _baseUrl = "$_host/mobile"; + static String _baseUrl = "$_host/mobile"; - static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index cd50f283..1f129652 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -87,7 +87,7 @@ class _ServiceRequestDetailMainState extends State { IconButton( icon: const Icon(Icons.feedback_rounded), onPressed: () { - Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId, surveyId: 6))); + Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId, surveyId: 5))); }, ), IconButton( diff --git a/lib/modules/cx_module/survey/questionnaire_model.dart b/lib/modules/cx_module/survey/questionnaire_model.dart index 9528cf87..9f2ac626 100644 --- a/lib/modules/cx_module/survey/questionnaire_model.dart +++ b/lib/modules/cx_module/survey/questionnaire_model.dart @@ -91,13 +91,15 @@ class SurveyQuestions { int? questionId; String? questionText; SurveyType? questionType; + bool? isMandatory; List? surveyAnswerOptions; - SurveyQuestions({this.questionId, this.questionText, this.questionType, this.surveyAnswerOptions}); + SurveyQuestions({this.questionId, this.questionText, this.questionType, this.surveyAnswerOptions, this.isMandatory}); SurveyQuestions.fromJson(Map json) { questionId = json['questionId']; questionText = json['questionText']; + isMandatory = json['isMandatory']; questionType = json['questionType'] != null ? new SurveyType.fromJson(json['questionType']) : null; if (json['surveyAnswerOptions'] != null) { surveyAnswerOptions = []; @@ -111,6 +113,7 @@ class SurveyQuestions { final Map data = new Map(); data['questionId'] = this.questionId; data['questionText'] = this.questionText; + data['isMandatory'] = this.isMandatory; if (this.questionType != null) { data['questionType'] = this.questionType!.toJson(); } diff --git a/lib/modules/cx_module/survey/survey_page.dart b/lib/modules/cx_module/survey/survey_page.dart index 71fa34f9..1975eef3 100644 --- a/lib/modules/cx_module/survey/survey_page.dart +++ b/lib/modules/cx_module/survey/survey_page.dart @@ -175,8 +175,8 @@ class _SurveyPageState extends State { bool isSuccess = await Provider.of(context, listen: false).submitQuestionare(payload); Utils.hideLoading(context); if (isSuccess) { - context.showConfirmDialog("Thank you for submitting the Feedback. It value for us to improve system and overall experience.", title: "Thanks!", okTitle: "Go Back", - onTap: () { + context.showConfirmDialog("Thanks for submitting the Feedback. Its value for us to improve our system and overall experience.", title: "Thank you!", onTap: () { + Navigator.pop(context); Navigator.pop(context); }); } //reload Data @@ -192,18 +192,20 @@ class _SurveyPageState extends State { bool validateAnswers() { bool status = true; for (int i = 0; i < answers.length; i++) { - if (questionnaire!.surveyQuestions![i].questionType!.value == 4) { - if (answers[i].surveyAnswerRating! < 0) { - "Please rate (${questionnaire!.surveyQuestions![i].questionText})".showToast; - status = false; - break; - } - } else if (questionnaire!.surveyQuestions![i].questionType!.value == 3) { - answers[i].surveyAnswerRating = null; - if ((answers[i].surveyAnswerText ?? "").isEmpty) { - "Please answer (${questionnaire!.surveyQuestions![i].questionText})".showToast; - status = false; - break; + if (questionnaire!.surveyQuestions![i].isMandatory ?? false) { + if (questionnaire!.surveyQuestions![i].questionType!.value == 4) { + if (answers[i].surveyAnswerRating! < 0) { + "Please rate (${questionnaire!.surveyQuestions![i].questionText})".showToast; + status = false; + break; + } + } else if (questionnaire!.surveyQuestions![i].questionType!.value == 3) { + answers[i].surveyAnswerRating = null; + if ((answers[i].surveyAnswerText ?? "").isEmpty) { + "Please answer (${questionnaire!.surveyQuestions![i].questionText})".showToast; + status = false; + break; + } } } } diff --git a/lib/modules/cx_module/survey/survey_provider.dart b/lib/modules/cx_module/survey/survey_provider.dart index 4fe0b468..cc1b73f6 100644 --- a/lib/modules/cx_module/survey/survey_provider.dart +++ b/lib/modules/cx_module/survey/survey_provider.dart @@ -22,25 +22,25 @@ class SurveyProvider with ChangeNotifier { String responseMsg = ""; Questionnaire? q; try { - final response = await ApiManager.instance.get("${URLs.getQuestionnaire.toString().replaceFirst("/mobile/", "/api/")}?surveySubmissionId=$surveySubmissionId", enableToastMessage: false); + final response = await ApiManager.instance.get("${URLs.getQuestionnaire}?surveySubmissionId=$surveySubmissionId", enableToastMessage: false); if (response.statusCode >= 200 && response.statusCode < 300) { + q = Questionnaire.fromJson(jsonDecode(response.body)["data"]); + } else { if (jsonDecode(response.body)["message"] != null && jsonDecode(response.body)["message"].toString().isNotEmpty) { responseMsg = jsonDecode(response.body)["message"]; - } else { - q = Questionnaire.fromJson(jsonDecode(response.body)["data"]); - } + } else {} } } catch (ex) { "Failed, Retry.".showToast; } onResponse(responseMsg, q); - // return null; + // return null; } Future submitQuestionare(Map payload) async { try { - final response = await ApiManager.instance.post(URLs.submitSurvey.toString().replaceFirst("/mobile/", "/api/"), body: payload); + final response = await ApiManager.instance.post(URLs.submitSurvey, body: payload); if (response.statusCode >= 200 && response.statusCode < 300) { return true; } From 186987c5ce99751e6487997ca886efdb9b90c211 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 17 Nov 2025 11:50:54 +0300 Subject: [PATCH 20/31] chat flow improvement and connect to SignalR. --- lib/controllers/api_routes/urls.dart | 1 + lib/extensions/string_extensions.dart | 6 +- lib/extensions/widget_extensions.dart | 4 +- .../service_request_detail_main_view.dart | 54 +- .../cx_module/chat/chat_api_client.dart | 9 +- lib/modules/cx_module/chat/chat_page.dart | 55 +- lib/modules/cx_module/chat/chat_provider.dart | 3031 +++++++++-------- .../get_single_user_chat_list_model.dart | 8 +- .../chat/model/user_chat_history_model.dart | 448 +-- 9 files changed, 1881 insertions(+), 1735 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 95b2085c..563de659 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -17,6 +17,7 @@ class URLs { // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation static const String chatHubUrl = "https://apiderichat.hmg.com/chathub"; + static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 16ae3fec..855560d1 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -7,17 +7,17 @@ extension StringExtensions on String { void get showToast => Fluttertoast.showToast(msg: this); String get chatMsgTime { - DateTime dateTime = DateTime.parse(this); + DateTime dateTime = DateTime.parse(this).toLocal(); return DateFormat('hh:mm a').format(dateTime); } String get chatMsgDate { - DateTime dateTime = DateTime.parse(this); + DateTime dateTime = DateTime.parse(this).toLocal(); return DateFormat('EEE dd MMM').format(dateTime); } String get chatMsgDateWithYear { - DateTime dateTime = DateTime.parse(this); + DateTime dateTime = DateTime.parse(this).toLocal(); return DateFormat('EEE dd MMM, yyyy').format(dateTime); } diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 8caa8ccf..3fd48cd8 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -79,13 +79,15 @@ extension WidgetExtensions on Widget { : this; } - Widget toShimmer({bool isShow = true, double radius = 20, required BuildContext context}) => isShow + Widget toShimmer({bool isShow = true, double radius = 20, double? width, double? height, required BuildContext context}) => isShow ? Shimmer.fromColors( baseColor: context.isDark ? AppColor.backgroundDark : const Color(0xffe8eff0), highlightColor: AppColor.background(context), child: ClipRRect( borderRadius: BorderRadius.circular(radius), child: Container( + width: width, + height: height, color: AppColor.background(context), child: this, ), diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 1f129652..e13d41eb 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -12,6 +12,7 @@ import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_mo import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; @@ -90,13 +91,35 @@ class _ServiceRequestDetailMainState extends State { Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId, surveyId: 5))); }, ), - IconButton( - icon: const Icon(Icons.chat_bubble), - onPressed: () { - Navigator.push( - context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: widget.requestId, title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? ""))); - }, - ), + Selector( + selector: (_, myModel) => myModel.isLoading, // Selects only the userName + builder: (_, isLoading, __) { + if (isLoading) { + return const SizedBox(); + } else { + ServiceRequestDetailProvider provider = Provider.of(context, listen: false); + if (provider.currentWorkOrder?.data?.status?.value == 2) { + getChatToken(1, provider.currentWorkOrder?.data?.workOrderNo ?? ""); + return Consumer(builder: (pContext, requestProvider, _) { + return IconButton( + icon: const Icon(Icons.chat_bubble), + onPressed: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ChatPage( + moduleId: 1, + requestId: widget.requestId, + title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? "", + readOnly: _requestProvider.isReadOnlyRequest, + ))); + }, + ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); + }); + } + return const SizedBox(); + } + }), isNurse ? IconButton( icon: 'qr'.toSvgAsset( @@ -156,4 +179,21 @@ class _ServiceRequestDetailMainState extends State { )), ); } + + void getChatToken(int moduleId, String title) { + ChatProvider cProvider = Provider.of(context, listen: false); + if (cProvider.chatLoginResponse != null) return; + String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + String myEmployeeId = context.userProvider.user!.username!; + + // String sender = context.settingProvider.username; + String receiver = context.userProvider.isNurse + ? assigneeEmployeeNumber + : (context.userProvider.isEngineer ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId! : ""); + + // assigneeEmployeeNumber + // ChatProvider cProvider = Provider.of(context, listen: false); + // Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, myEmployeeId, assigneeEmployeeNumber); + cProvider.getUserAutoLoginTokenSilent(moduleId, widget.requestId, title, myEmployeeId, receiver); + } } diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 9641b0ec..929f9946 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -13,6 +13,7 @@ import 'api_client.dart'; import 'model/chat_login_response_model.dart'; import 'model/chat_participant_model.dart'; import 'model/get_search_user_chat_model.dart'; +import 'model/get_single_user_chat_list_model.dart'; import 'model/get_user_login_token_model.dart' as userLoginTokenModel; import 'model/user_chat_history_model.dart'; @@ -74,14 +75,14 @@ class ChatApiClient { } } - Future> loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async { + Future> loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async { Response response = await ApiClient().postJsonForResponse( "${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()}, token: chatLoginResponse!.token); // try { if (response.statusCode == 200) { List data = jsonDecode(response.body); - return data.map((elemet) => ChatHistoryResponse.fromJson(elemet)).toList(); + return data.map((elemet) => SingleUserChatModel.fromJson(elemet)).toList(); // return UserChatHistoryModel.fromJson(jsonDecode(response.body)); } else { @@ -92,7 +93,7 @@ class ChatApiClient { // } } - Future sendTextMessage(String message, int conversationId) async { +/* Future sendTextMessage(String message, int conversationId) async { try { Response response = await ApiClient().postJsonForResponse("${URLs.chatHubUrlApi}/chat/conversations/$conversationId/messages", {"content": message, "messageType": "Text"}, token: chatLoginResponse!.token); @@ -106,7 +107,7 @@ class ChatApiClient { print(ex); return null; } - } + }*/ // Future getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { // ChatUserModel chatUserModel; diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index ef183c10..c1196027 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -15,6 +17,7 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'model/get_single_user_chat_list_model.dart'; import 'model/user_chat_history_model.dart'; enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } @@ -45,10 +48,12 @@ class _ChatPageState extends State { ChatState chatState = ChatState.idle; + late String receiver; + @override void initState() { super.initState(); - getChatToken(); + loadChatHistory(); playerController.addListener(() async { // if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) { // await playerController.stopPlayer(); @@ -57,19 +62,14 @@ class _ChatPageState extends State { }); } - void getChatToken() { + void loadChatHistory() { String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; String myEmployeeId = context.userProvider.user!.username!; - // String sender = context.settingProvider.username; - String receiver = context.userProvider.isNurse + receiver = context.userProvider.isNurse ? assigneeEmployeeNumber : (context.userProvider.isEngineer ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId! : ""); - - // assigneeEmployeeNumber - - // Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, myEmployeeId, assigneeEmployeeNumber); - Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver); + Provider.of(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver); } @override @@ -100,12 +100,10 @@ class _ChatPageState extends State { ), 24.height, AppFilledButton( - label: "Retry", + label: "Go Back", maxWidth: true, buttonColor: AppColor.primary10, - onPressed: () async { - getChatToken(); - }, + onPressed: () => Navigator.pop(context), ).paddingOnly(start: 48, end: 48) ], ).center; @@ -169,14 +167,14 @@ class _ChatPageState extends State { showDateHeader = true; } else { final nextMessage = chatProvider.chatResponseList[index + 1]; - final currentDate = DateUtils.dateOnly(DateTime.parse(currentMessage.createdDate!)); - final nextDate = DateUtils.dateOnly(DateTime.parse(nextMessage.createdDate!)); + final currentDate = DateUtils.dateOnly(currentMessage.createdDate!); + final nextDate = DateUtils.dateOnly(nextMessage.createdDate!); if (!currentDate.isAtSameMomentAs(nextDate)) { showDateHeader = true; } } return Column(mainAxisSize: MainAxisSize.min, children: [ - if (showDateHeader) dateCard(currentMessage.createdDate?.chatMsgDateWithYear ?? ""), + if (showDateHeader) dateCard(currentMessage.createdDate?.toString().chatMsgDateWithYear ?? ""), isSender ? senderMsgCard(showSenderName, chatProvider.chatResponseList[index]) : recipientMsgCard(showSenderName, chatProvider.chatResponseList[index]) ]); }, @@ -198,6 +196,9 @@ class _ChatPageState extends State { maxLines: 3, textInputAction: TextInputAction.none, keyboardType: TextInputType.multiline, + onChanged: (text) { + chatHubConnection.invoke("SendTypingAsync", args: [context.userProvider.user!.username!]); + }, decoration: InputDecoration( enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, @@ -458,7 +459,19 @@ class _ChatPageState extends State { highlightColor: Colors.transparent, hoverColor: Colors.transparent, onPressed: () { - chatProvider.sendTextMessage(textEditingController.text).then((success) { + chatProvider.invokeSendMessage({ + "Contant": textEditingController.text, + // "ContantNo": "0cc8b126-6180-4f91-a64d-2f62443b3f3f", + // "CreatedDate": "2025-11-09T18:58:12.502Z", + "CurrentEmployeeNumber": context.userProvider.user!.username!, + "ChatEventId": 1, + "ConversationId": chatProvider.chatParticipantModel!.id!.toString(), + "ModuleCode": widget.moduleId.toString(), + "ReferenceNumber": widget.requestId.toString(), + "UserChatHistoryLineRequestList": [ + {"TargetEmployeeNumber": receiver, "TargetUserStatus": 1, "IsSeen": false, "IsDelivered": true, "SeenOn": null, "DeliveredOn": null} + ] + }).then((success) { if (success) { textEditingController.clear(); } @@ -499,7 +512,7 @@ class _ChatPageState extends State { .center; } - Widget senderMsgCard(bool showHeader, ChatHistoryResponse? chatResponse, {bool loading = false, String msg = ""}) { + Widget senderMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = ""}) { Widget senderHeader = Row( mainAxisSize: MainAxisSize.min, children: [ @@ -548,7 +561,7 @@ class _ChatPageState extends State { ).toShimmer(context: context, isShow: loading), if (loading) 4.height, Text( - chatResponse?.createdDate?.chatMsgTime ?? "2:00 PM", + chatResponse?.createdDate?.toString().chatMsgTime ?? "2:00 PM", style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)), ).toShimmer(context: context, isShow: loading), ], @@ -569,7 +582,7 @@ class _ChatPageState extends State { ); } - Widget recipientMsgCard(bool showHeader, ChatHistoryResponse? chatResponse, {bool loading = false, String msg = ""}) { + Widget recipientMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = ""}) { String extraSpaces = ""; int length = 0; if ((chatResponse?.contant ?? "").isNotEmpty) { @@ -624,7 +637,7 @@ class _ChatPageState extends State { alignment: Alignment.centerRight, widthFactor: 1, child: Text( - chatResponse?.createdDate?.chatMsgTime ?? "2:00 PM", + chatResponse?.createdDate?.toString().chatMsgTime ?? "2:00 PM", style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.white10), ), ).toShimmer(context: context, isShow: loading), diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index c86c5096..84384087 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -116,11 +116,11 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // UserChatHistoryModel? userChatHistory; - List? userChatHistory; + List? userChatHistory; bool messageIsSending = false; - List chatResponseList = []; + List chatResponseList = []; Participants? sender; Participants? recipient; @@ -137,41 +137,59 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { ChatApiClient().chatLoginResponse = null; } - Future getUserAutoLoginToken(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async { + // Future getUserAutoLoginToken(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async { + // reset(); + // chatLoginTokenLoading = true; + // notifyListeners(); + // chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId); + // chatLoginTokenLoading = false; + // chatParticipantLoading = true; + // notifyListeners(); + // // loadParticipants(moduleId, requestId); + // if (chatLoginResponse != null) { + // await loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); + // } + // } + + Future getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async { reset(); chatLoginTokenLoading = true; notifyListeners(); - chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId); + try { + chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId); + chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); + sender = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == myId); + recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); + } catch (ex) {} chatLoginTokenLoading = false; - chatParticipantLoading = true; notifyListeners(); - // loadParticipants(moduleId, requestId); - loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); } - // Future loadParticipants(int moduleId, int requestId) async { - // // loadChatHistoryLoading = true; - // // notifyListeners(); - // chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId); - // chatParticipantLoading = false; + // Future getUserLoadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { + // await loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); + // } + + // Future loadParticipants(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { + // userChatHistoryLoading = true; // notifyListeners(); + // try { + // chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); + // } catch (ex) { + // userChatHistoryLoading = false; + // notifyListeners(); + // return; + // } + // + // try { + // sender = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == myId); + // recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); + // } catch (e) {} // } - Future loadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { + Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { userChatHistoryLoading = true; notifyListeners(); - try { - chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); - } catch (ex) { - userChatHistoryLoading = false; - notifyListeners(); - return; - } - - try { - sender = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == myId); - recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); - } catch (e) {} + await buildHubConnection(chatParticipantModel!.id!.toString()); userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); chatResponseList = userChatHistory ?? []; chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); @@ -179,23 +197,64 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } - Future sendTextMessage(String message) async { + // Future loadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { + // userChatHistoryLoading = true; + // notifyListeners(); + // userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); + // chatResponseList = userChatHistory ?? []; + // chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); + // userChatHistoryLoading = false; + // notifyListeners(); + // } + + Future invokeSendMessage(Object object) async { messageIsSending = true; notifyListeners(); bool returnStatus = false; - ChatResponse? chatResponse = await ChatApiClient().sendTextMessage(message, chatParticipantModel!.id!); - if (chatResponse != null) { + try { + await chatHubConnection.invoke("AddChatUserAsync", args: [object]); returnStatus = true; - // chatResponseList.add(chatResponse); - try { - chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); - } catch (ex) {} - } + } catch (ex) {} + messageIsSending = false; notifyListeners(); return returnStatus; } + // Future sendTextMessage(String message) async { + // messageIsSending = true; + // notifyListeners(); + // bool returnStatus = false; + // + // ChatResponse? chatResponse = await ChatApiClient().sendTextMessage(message, chatParticipantModel!.id!); + // if (chatResponse != null) { + // returnStatus = true; + // // chatResponseList.add(chatResponse); + // try { + // chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); + // } catch (ex) {} + // } + // messageIsSending = false; + // notifyListeners(); + // return returnStatus; + // } + + void sendMsgSignalR() { + var abc = { + "Contant": "Follow-up: Test results look good.", + "ContantNo": "0cc8b126-6180-4f91-a64d-2f62443b3f3f", + "CreatedDate": "2025-11-09T18:58:12.502Z", + "CurrentEmployeeNumber": "EMP123456", + "ChatEventId": 1, + "ConversationId": "15521", + "ModuleCode": "CRM", + "ReferenceNumber": "CASE-55231", + "UserChatHistoryLineRequestList": [ + {"TargetEmployeeNumber": "EMP654321", "TargetUserStatus": 1, "IsSeen": false, "IsDelivered": true, "SeenOn": null, "DeliveredOn": null} + ] + }; + } + // List? uGroups = [], searchGroups = []; // Future getUserAutoLoginToken() async { @@ -216,14 +275,18 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } // } - Future buildHubConnection() async { + Future buildHubConnection(String conversationID) async { chatHubConnection = await getHubConnection(); await chatHubConnection.start(); if (kDebugMode) { print("Hub Conn: Startedddddddd"); } - // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); - // chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); + + await chatHubConnection.invoke("JoinConversation", args: [conversationID]); + chatHubConnection.on("ReceiveMessage", onMsgReceived1); + chatHubConnection.on("OnMessageReceivedAsync", onMsgReceived); + chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); + chatHubConnection.on("OnTypingAsync", OnTypingAsync); //group On message @@ -234,7 +297,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { HubConnection hub; HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hub = HubConnectionBuilder() - .withUrl("${URLs.chatHubUrl}?UserId=${chatLoginResponse!.userId}&source=Desktop&access_token=${chatLoginResponse!.token}", options: httpOp) + .withUrl("${URLs.chatHubUrlChat}?UserId=${chatLoginResponse!.userId}&source=Desktop&access_token=${chatLoginResponse!.token}", options: httpOp) .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); return hub; } @@ -492,1502 +555,1529 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // notifyListeners(); // } - // Future onMsgReceived(List? parameters) async { - // List data = [], temp = []; - // for (dynamic msg in parameters!) { - // data = getSingleUserChatModel(jsonEncode(msg)); - // temp = getSingleUserChatModel(jsonEncode(msg)); - // data.first.targetUserId = temp.first.currentUserId; - // data.first.targetUserName = temp.first.currentUserName; - // data.first.targetUserEmail = temp.first.currentUserEmail; - // data.first.currentUserId = temp.first.targetUserId; - // data.first.currentUserName = temp.first.targetUserName; - // data.first.currentUserEmail = temp.first.targetUserEmail; - // - // if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { - // data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); - // } - // if (data.first.userChatReplyResponse != null) { - // if (data.first.fileTypeResponse != null) { - // if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { - // data.first.userChatReplyResponse!.image = await ChatApiClient() - // .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); - // data.first.userChatReplyResponse!.isImageLoaded = true; - // } - // } - // } - // } - // - // if (searchedChats != null) { - // dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); - // if (contain.isEmpty) { - // List emails = []; - // emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); - // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - // searchedChats!.add( - // ChatUser( - // id: data.first.currentUserId, - // userName: data.first.currentUserName, - // email: data.first.currentUserEmail, - // unreadMessageCount: 0, - // isImageLoading: false, - // image: chatImages!.first.profilePicture ?? "", - // isImageLoaded: true, - // userStatus: 1, - // isTyping: false, - // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), - // ), - // ); - // } - // } - // setMsgTune(); - // if (isChatScreenActive && data.first.currentUserId == receiverID) { - // userChatHistory.insert(0, data.first); - // } else { - // if (searchedChats != null) { - // for (ChatUser user in searchedChats!) { - // if (user.id == data.first.currentUserId) { - // int tempCount = user.unreadMessageCount ?? 0; - // user.unreadMessageCount = tempCount + 1; - // } - // } - // sort(); - // } - // } - // - // List list = [ - // { - // "userChatHistoryId": data.first.userChatHistoryId, - // "TargetUserId": temp.first.targetUserId, - // "isDelivered": true, - // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false - // } - // ]; - // updateUserChatHistoryOnMsg(list); - // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - // notifyListeners(); - // } + Future OnTypingAsync(List? parameters) async { + print("OnTypingAsync:$parameters"); + } - // Future onGroupMsgReceived(List? parameters) async { - // List data = [], temp = []; - // - // for (dynamic msg in parameters!) { - // // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); - // data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); - // temp = data; - // // data.first.currentUserId = temp.first.currentUserId; - // // data.first.currentUserName = temp.first.currentUserName; - // // - // // data.first.currentUserId = temp.first.currentUserId; - // // data.first.currentUserName = temp.first.currentUserName; - // - // if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { - // data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); - // } - // if (data.first.groupChatReplyResponse != null) { - // if (data.first.fileTypeResponse != null) { - // if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { - // data.first.groupChatReplyResponse!.image = await ChatApiClient() - // .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); - // data.first.groupChatReplyResponse!.isImageLoaded = true; - // } - // } - // } - // } + // Future OnSubmitChatAsync(List? parameters) async { + // // List data = jsonDecode(parameters!.first!.toString()); // - // // if (searchedChats != null) { - // // dynamic contain = searchedChats! - // // .where((ChatUser element) => element.id == data.first.currentUserId); - // // if (contain.isEmpty) { - // // List emails = []; - // // emails.add(await EmailImageEncryption() - // // .encrypt(val: data.first.currentUserEmail!)); - // // List chatImages = - // // await ChatApiClient().getUsersImages(encryptedEmails: emails); - // // searchedChats!.add( - // // ChatUser( - // // id: data.first.currentUserId, - // // userName: data.first.currentUserName, - // // email: data.first.currentUserEmail, - // // unreadMessageCount: 0, - // // isImageLoading: false, - // // image: chatImages!.first.profilePicture ?? "", - // // isImageLoaded: true, - // // userStatus: 1, - // // isTyping: false, - // // userLocalDownlaodedImage: await downloadImageLocal( - // // chatImages.first.profilePicture, - // // data.first.currentUserId.toString()), - // // ), - // // ); - // // } - // // } - // groupChatHistory.insert(0, data.first); - // setMsgTune(); - // // if (isChatScreenActive && data.first.currentUserId == receiverID) { + // print("OnSubmitChatAsync:$parameters"); // - // // } else { - // // if (searchedChats != null) { - // // for (ChatUser user in searchedChats!) { - // // if (user.id == data.first.currentUserId) { - // // int tempCount = user.unreadMessageCount ?? 0; - // // user.unreadMessageCount = tempCount + 1; - // // } - // // } - // sort(); - // //} - // //} - // // - // // List list = [ - // // { - // // "userChatHistoryId": data.first.groupId, - // // "TargetUserId": temp.first.currentUserId, - // // "isDelivered": true, - // // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID - // // ? true - // // : false - // // } - // // ]; - // // updateUserChatHistoryOnMsg(list); - // // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - // notifyListeners(); - // } - - // void OnSubmitChatAsync(List? parameters) { - // print(isChatScreenActive); - // print(receiverID); - // print(isChatScreenActive); - // logger.i(parameters); - // List data = [], temp = []; // for (dynamic msg in parameters!) { - // data = getSingleUserChatModel(jsonEncode(msg)); - // temp = getSingleUserChatModel(jsonEncode(msg)); - // data.first.targetUserId = temp.first.currentUserId; - // data.first.targetUserName = temp.first.currentUserName; - // data.first.targetUserEmail = temp.first.currentUserEmail; - // data.first.currentUserId = temp.first.targetUserId; - // data.first.currentUserName = temp.first.targetUserName; - // data.first.currentUserEmail = temp.first.targetUserEmail; - // } - // if (isChatScreenActive && data.first.currentUserId == receiverID) { - // int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); - // logger.d(index); - // userChatHistory[index] = data.first; + // var data = getSingleUserChatModel(jsonEncode(msg)); + // print(data); // } // - // notifyListeners(); - // } - - // void sort() { - // searchedChats!.sort( - // (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), - // ); + // // List data = parameters!.first!; + // // chatResponseList = chatResponseList + data.map((elemet) => ChatHistoryResponse.fromJson(element)).toList(); + // // chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); + // // notifyListeners(); // } - // void onUserTyping(List? parameters) { - // for (ChatUser user in searchedChats!) { - // if (user.id == parameters![1] && parameters[0] == true) { - // user.isTyping = parameters[0] as bool?; - // Future.delayed( - // const Duration(seconds: 2), - // () { - // user.isTyping = false; - // notifyListeners(); - // }, - // ); - // } - // } - // notifyListeners(); - // } + Future onMsgReceived1(List? parameters) async { + print("onMsgReceived1:$parameters"); + } - int getFileType(String value) { - switch (value) { - case ".pdf": - return 1; - case ".png": - return 3; - case ".txt": - return 5; - case ".jpg": - return 12; - case ".jpeg": - return 4; - case ".xls": - return 7; - case ".xlsx": - return 7; - case ".doc": - return 6; - case ".docx": - return 6; - case ".ppt": - return 8; - case ".pptx": - return 8; - case ".zip": - return 2; - case ".rar": - return 2; - case ".aac": - return 13; - case ".mp3": - return 14; - case ".mp4": - return 16; - case ".mov": - return 16; - case ".avi": - return 16; - case ".flv": - return 16; - - default: - return 0; + Future onMsgReceived(List? parameters) async { + List data = [], temp = []; + print("OnMessageReceivedAsync:$parameters"); + for (dynamic msg in parameters!) { + data = getSingleUserChatModel(jsonEncode(msg)); + // temp = getSingleUserChatModel(jsonEncode(msg)); + // data.first.targetUserId = temp.first.currentUserId; + // data.first.targetUserName = temp.first.currentUserName; + // data.first.targetUserEmail = temp.first.currentUserEmail; + // data.first.currentUserId = temp.first.targetUserId; + // data.first.currentUserName = temp.first.targetUserName; + // data.first.currentUserEmail = temp.first.targetUserEmail; + + // if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { + // data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); + // } + // if (data.first.userChatReplyResponse != null) { + // if (data.first.fileTypeResponse != null) { + // if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { + // data.first.userChatReplyResponse!.image = await ChatApiClient() + // .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); + // data.first.userChatReplyResponse!.isImageLoaded = true; + // } + // } + // } } + // + // if + // + // ( + // + // searchedChats != null) { + // dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); + // if (contain.isEmpty) { + // List emails = []; + // emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); + // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); + // searchedChats!.add( + // ChatUser( + // id: data.first.currentUserId, + // userName: data.first.currentUserName, + // email: data.first.currentUserEmail, + // unreadMessageCount: 0, + // isImageLoading: false, + // image: chatImages!.first.profilePicture ?? "", + // isImageLoaded: true, + // userStatus: 1, + // isTyping: false, + // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), + // ), + // ); + // } + // } + setMsgTune(); + // userChatHistory = userChatHistory! + data; + // chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); + userChatHistory?.insert(0, data.first); + notifyListeners(); + // if (isChatScreenActive && data.first.currentUserId == receiverID) { + // + // } else { + // // if (searchedChats != null) { + // // for (ChatUser user in searchedChats!) { + // // if (user.id == data.first.currentUserId) { + // // int tempCount = user.unreadMessageCount ?? 0; + // // user.unreadMessageCount = tempCount + 1; + // // } + // // } + // // sort(); + // // } + // } + + // List list = [ + // { + // "userChatHistoryId": data.first.userChatHistoryId, + // "TargetUserId": temp.first.targetUserId, + // "isDelivered": true, + // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false + // } + // ]; + // updateUserChatHistoryOnMsg(list); + // invokeChatCounter(userId: AppState().chatDetails!.response!. + // id + // + // ! + // + // ); + + // notifyListeners + // + // ( + // + // ); } - String getFileTypeDescription(String value) { - switch (value) { - case ".pdf": - return "application/pdf"; - case ".png": - return "image/png"; - case ".txt": - return "text/plain"; - case ".jpg": - return "image/jpg"; - case ".jpeg": - return "image/jpeg"; - case ".ppt": - return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; - case ".pptx": - return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; - case ".doc": - return "application/vnd.openxmlformats-officedocument.wordprocessingm"; - case ".docx": - return "application/vnd.openxmlformats-officedocument.wordprocessingm"; - case ".xls": - return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; - case ".xlsx": - return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; - case ".zip": - return "application/octet-stream"; - case ".rar": - return "application/octet-stream"; - case ".aac": - return "audio/aac"; - case ".mp3": - return "audio/mp3"; - case ".mp4": - return "video/mp4"; - case ".avi": - return "video/avi"; - case ".flv": - return "video/flv"; - case ".mov": - return "video/mov"; - - default: - return ""; +// Future onGroupMsgReceived(List? parameters) async { +// List data = [], temp = []; +// +// for (dynamic msg in parameters!) { +// // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); +// data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); +// temp = data; +// // data.first.currentUserId = temp.first.currentUserId; +// // data.first.currentUserName = temp.first.currentUserName; +// // +// // data.first.currentUserId = temp.first.currentUserId; +// // data.first.currentUserName = temp.first.currentUserName; +// +// if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { +// data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); +// } +// if (data.first.groupChatReplyResponse != null) { +// if (data.first.fileTypeResponse != null) { +// if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { +// data.first.groupChatReplyResponse!.image = await ChatApiClient() +// .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); +// data.first.groupChatReplyResponse!.isImageLoaded = true; +// } +// } +// } +// } +// +// // if (searchedChats != null) { +// // dynamic contain = searchedChats! +// // .where((ChatUser element) => element.id == data.first.currentUserId); +// // if (contain.isEmpty) { +// // List emails = []; +// // emails.add(await EmailImageEncryption() +// // .encrypt(val: data.first.currentUserEmail!)); +// // List chatImages = +// // await ChatApiClient().getUsersImages(encryptedEmails: emails); +// // searchedChats!.add( +// // ChatUser( +// // id: data.first.currentUserId, +// // userName: data.first.currentUserName, +// // email: data.first.currentUserEmail, +// // unreadMessageCount: 0, +// // isImageLoading: false, +// // image: chatImages!.first.profilePicture ?? "", +// // isImageLoaded: true, +// // userStatus: 1, +// // isTyping: false, +// // userLocalDownlaodedImage: await downloadImageLocal( +// // chatImages.first.profilePicture, +// // data.first.currentUserId.toString()), +// // ), +// // ); +// // } +// // } +// groupChatHistory.insert(0, data.first); +// setMsgTune(); +// // if (isChatScreenActive && data.first.currentUserId == receiverID) { +// +// // } else { +// // if (searchedChats != null) { +// // for (ChatUser user in searchedChats!) { +// // if (user.id == data.first.currentUserId) { +// // int tempCount = user.unreadMessageCount ?? 0; +// // user.unreadMessageCount = tempCount + 1; +// // } +// // } +// sort(); +// //} +// //} +// // +// // List list = [ +// // { +// // "userChatHistoryId": data.first.groupId, +// // "TargetUserId": temp.first.currentUserId, +// // "isDelivered": true, +// // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID +// // ? true +// // : false +// // } +// // ]; +// // updateUserChatHistoryOnMsg(list); +// // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); +// notifyListeners(); +// } + + void OnSubmitChatAsync(List? parameters) { + List data = []; + for (dynamic msg in parameters!) { + data = getSingleUserChatModel(jsonEncode(msg)); } + chatResponseList.insert(0, data.first); + notifyListeners(); } - // Future sendChatToServer( - // {required int chatEventId, - // required fileTypeId, - // required int targetUserId, - // required String targetUserName, - // required chatReplyId, - // required bool isAttachment, - // required bool isReply, - // Uint8List? image, - // required bool isImageLoaded, - // String? userEmail, - // int? userStatus, - // File? voiceFile, - // required bool isVoiceAttached}) async { - // Uuid uuid = const Uuid(); - // String contentNo = uuid.v4(); - // String msg; - // if (isVoiceAttached) { - // msg = voiceFile!.path.split("/").last; - // } else { - // msg = message.text; - // logger.w(msg); - // } - // SingleUserChatModel data = SingleUserChatModel( - // userChatHistoryId: 0, - // chatEventId: chatEventId, - // chatSource: 1, - // contant: msg, - // contantNo: contentNo, - // conversationId: chatCID, - // createdDate: DateTime.now(), - // currentUserId: AppState().chatDetails!.response!.id, - // currentUserName: AppState().chatDetails!.response!.userName, - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // isReplied: false, - // fileTypeId: fileTypeId, - // userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, - // fileTypeResponse: isAttachment - // ? FileTypeResponse( - // fileTypeId: fileTypeId, - // fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), - // fileKind: "file", - // fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, - // fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), - // ) - // : null, - // image: image, - // isImageLoaded: isImageLoaded, - // voice: isVoiceMsg ? voiceFile! : null, - // voiceController: isVoiceMsg ? AudioPlayer() : null); - // if (kDebugMode) { - // logger.i("model data: " + jsonEncode(data)); - // } - // userChatHistory.insert(0, data); - // isTextMsg = false; - // isReplyMsg = false; - // isAttachmentMsg = false; - // isVoiceMsg = false; - // sFileType = ""; - // message.clear(); - // notifyListeners(); - // - // String chatData = - // '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; - // - // await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); - // } +// void sort() { +// searchedChats!.sort( +// (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), +// ); +// } - //groupChatMessage - - // Future sendGroupChatToServer( - // {required int chatEventId, - // required fileTypeId, - // required int targetGroupId, - // required String targetUserName, - // required chatReplyId, - // required bool isAttachment, - // required bool isReply, - // Uint8List? image, - // required bool isImageLoaded, - // String? userEmail, - // int? userStatus, - // File? voiceFile, - // required bool isVoiceAttached, - // required List userList}) async { - // Uuid uuid = const Uuid(); - // String contentNo = uuid.v4(); - // String msg; - // if (isVoiceAttached) { - // msg = voiceFile!.path.split("/").last; - // } else { - // msg = message.text; - // logger.w(msg); - // } - // groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( - // //userChatHistoryId: 0, - // chatEventId: chatEventId, - // chatSource: 1, - // contant: msg, - // contantNo: contentNo, - // conversationId: chatCID, - // createdDate: DateTime.now().toString(), - // currentUserId: AppState().chatDetails!.response!.id, - // currentUserName: AppState().chatDetails!.response!.userName, - // groupId: targetGroupId, - // groupName: targetUserName, - // isReplied: false, - // fileTypeId: fileTypeId, - // fileTypeResponse: isAttachment - // ? groupchathistory.FileTypeResponse( - // fileTypeId: fileTypeId, - // fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), - // fileKind: "file", - // fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, - // fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) - // : null, - // image: image, - // isImageLoaded: isImageLoaded, - // voice: isVoiceMsg ? voiceFile! : null, - // voiceController: isVoiceMsg ? AudioPlayer() : null); - // if (kDebugMode) { - // logger.i("model data: " + jsonEncode(data)); - // } - // groupChatHistory.insert(0, data); - // isTextMsg = false; - // isReplyMsg = false; - // isAttachmentMsg = false; - // isVoiceMsg = false; - // sFileType = ""; - // message.clear(); - // notifyListeners(); - // - // List targetUsers = []; - // - // for (GroupUserList element in userList) { - // targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); - // } - // - // String chatData = - // '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; - // - // await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); - // } +// void onUserTyping(List? parameters) { +// for (ChatUser user in searchedChats!) { +// if (user.id == parameters![1] && parameters[0] == true) { +// user.isTyping = parameters[0] as bool?; +// Future.delayed( +// const Duration(seconds: 2), +// () { +// user.isTyping = false; +// notifyListeners(); +// }, +// ); +// } +// } +// notifyListeners(); +} - // void sendGroupChatMessage( - // BuildContext context, { - // required int targetUserId, - // required int userStatus, - // required String userEmail, - // required String targetUserName, - // required List userList, - // }) async { - // if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - // logger.d("// Normal Text Message"); - // if (message.text.isEmpty) { - // return; - // } - // sendGroupChatToServer( - // chatEventId: 1, - // fileTypeId: null, - // targetGroupId: targetUserId, - // targetUserName: targetUserName, - // isAttachment: false, - // chatReplyId: null, - // isReply: false, - // isImageLoaded: false, - // image: null, - // isVoiceAttached: false, - // userEmail: userEmail, - // userStatus: userStatus, - // userList: userList); - // } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - // logger.d("// Text Message as Reply"); - // if (message.text.isEmpty) { - // return; - // } - // sendGroupChatToServer( - // chatEventId: 1, - // fileTypeId: null, - // targetGroupId: targetUserId, - // targetUserName: targetUserName, - // chatReplyId: groupChatReplyData.first.groupChatHistoryId, - // isAttachment: false, - // isReply: true, - // isImageLoaded: groupChatReplyData.first.isImageLoaded!, - // image: groupChatReplyData.first.image, - // isVoiceAttached: false, - // voiceFile: null, - // userEmail: userEmail, - // userStatus: userStatus, - // userList: userList); - // } - // // Attachment - // else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - // logger.d("// Normal Image Message"); - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); - // String? ext = getFileExtension(selectedFile.path); - // Utils.hideLoading(context); - // sendGroupChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // targetGroupId: targetUserId, - // targetUserName: targetUserName, - // isAttachment: true, - // chatReplyId: null, - // isReply: false, - // isImageLoaded: true, - // image: selectedFile.readAsBytesSync(), - // isVoiceAttached: false, - // userEmail: userEmail, - // userStatus: userStatus, - // userList: userList); - // } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - // logger.d("// Image as Reply Msg"); - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); - // String? ext = getFileExtension(selectedFile.path); - // Utils.hideLoading(context); - // sendGroupChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // targetGroupId: targetUserId, - // targetUserName: targetUserName, - // isAttachment: true, - // chatReplyId: repliedMsg.first.userChatHistoryId, - // isReply: true, - // isImageLoaded: true, - // image: selectedFile.readAsBytesSync(), - // isVoiceAttached: false, - // userEmail: userEmail, - // userStatus: userStatus, - // userList: userList); - // } - // //Voice - // - // else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { - // logger.d("// Normal Voice Message"); - // - // if (!isPause) { - // path = await recorderController.stop(false); - // } - // if (kDebugMode) { - // logger.i("path:" + path!); - // } - // File voiceFile = File(path!); - // voiceFile.readAsBytesSync(); - // _timer?.cancel(); - // isPause = false; - // isPlaying = false; - // isRecoding = false; - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); - // String? ext = getFileExtension(voiceFile.path); - // Utils.hideLoading(context); - // sendGroupChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // //, - // targetGroupId: targetUserId, - // targetUserName: targetUserName, - // chatReplyId: null, - // isAttachment: true, - // isReply: isReplyMsg, - // isImageLoaded: false, - // voiceFile: voiceFile, - // isVoiceAttached: true, - // userEmail: userEmail, - // userStatus: userStatus, - // userList: userList); - // notifyListeners(); - // } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { - // logger.d("// Voice as Reply Msg"); - // - // if (!isPause) { - // path = await recorderController.stop(false); - // } - // if (kDebugMode) { - // logger.i("path:" + path!); - // } - // File voiceFile = File(path!); - // voiceFile.readAsBytesSync(); - // _timer?.cancel(); - // isPause = false; - // isPlaying = false; - // isRecoding = false; - // - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); - // String? ext = getFileExtension(voiceFile.path); - // Utils.hideLoading(context); - // sendGroupChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // targetGroupId: targetUserId, - // targetUserName: targetUserName, - // chatReplyId: null, - // isAttachment: true, - // isReply: isReplyMsg, - // isImageLoaded: false, - // voiceFile: voiceFile, - // isVoiceAttached: true, - // userEmail: userEmail, - // userStatus: userStatus, - // userList: userList); - // notifyListeners(); - // } - // if (searchedChats != null) { - // dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); - // if (contain.isEmpty) { - // List emails = []; - // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - // searchedChats!.add( - // ChatUser( - // id: targetUserId, - // userName: targetUserName, - // unreadMessageCount: 0, - // email: userEmail, - // isImageLoading: false, - // image: chatImages.first.profilePicture ?? "", - // isImageLoaded: true, - // isTyping: false, - // isFav: false, - // userStatus: userStatus, - // // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), - // ), - // ); - // notifyListeners(); - // } - // } - // } +int getFileType(String value) { + switch (value) { + case ".pdf": + return 1; + case ".png": + return 3; + case ".txt": + return 5; + case ".jpg": + return 12; + case ".jpeg": + return 4; + case ".xls": + return 7; + case ".xlsx": + return 7; + case ".doc": + return 6; + case ".docx": + return 6; + case ".ppt": + return 8; + case ".pptx": + return 8; + case ".zip": + return 2; + case ".rar": + return 2; + case ".aac": + return 13; + case ".mp3": + return 14; + case ".mp4": + return 16; + case ".mov": + return 16; + case ".avi": + return 16; + case ".flv": + return 16; + + default: + return 0; + } +} - // void sendChatMessage( - // BuildContext context, { - // required int targetUserId, - // required int userStatus, - // required String userEmail, - // required String targetUserName, - // }) async { - // if (kDebugMode) { - // print("====================== Values ============================"); - // print("Is Text " + isTextMsg.toString()); - // print("isReply " + isReplyMsg.toString()); - // print("isAttachment " + isAttachmentMsg.toString()); - // print("isVoice " + isVoiceMsg.toString()); - // } - // //Text - // if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - // // logger.d("// Normal Text Message"); - // if (message.text.isEmpty) { - // return; - // } - // sendChatToServer( - // chatEventId: 1, - // fileTypeId: null, - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // isAttachment: false, - // chatReplyId: null, - // isReply: false, - // isImageLoaded: false, - // image: null, - // isVoiceAttached: false, - // userEmail: userEmail, - // userStatus: userStatus); - // } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - // logger.d("// Text Message as Reply"); - // if (message.text.isEmpty) { - // return; - // } - // sendChatToServer( - // chatEventId: 1, - // fileTypeId: null, - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // chatReplyId: repliedMsg.first.userChatHistoryId, - // isAttachment: false, - // isReply: true, - // isImageLoaded: repliedMsg.first.isImageLoaded!, - // image: repliedMsg.first.image, - // isVoiceAttached: false, - // voiceFile: null, - // userEmail: userEmail, - // userStatus: userStatus); - // } - // // Attachment - // else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { - // logger.d("// Normal Image Message"); - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); - // String? ext = getFileExtension(selectedFile.path); - // Utils.hideLoading(context); - // sendChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // isAttachment: true, - // chatReplyId: null, - // isReply: false, - // isImageLoaded: true, - // image: selectedFile.readAsBytesSync(), - // isVoiceAttached: false, - // userEmail: userEmail, - // userStatus: userStatus); - // } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { - // logger.d("// Image as Reply Msg"); - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); - // String? ext = getFileExtension(selectedFile.path); - // Utils.hideLoading(context); - // sendChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // isAttachment: true, - // chatReplyId: repliedMsg.first.userChatHistoryId, - // isReply: true, - // isImageLoaded: true, - // image: selectedFile.readAsBytesSync(), - // isVoiceAttached: false, - // userEmail: userEmail, - // userStatus: userStatus); - // } - // //Voice - // - // else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { - // logger.d("// Normal Voice Message"); - // - // if (!isPause) { - // path = await recorderController.stop(false); - // } - // if (kDebugMode) { - // logger.i("path:" + path!); - // } - // File voiceFile = File(path!); - // voiceFile.readAsBytesSync(); - // _timer?.cancel(); - // isPause = false; - // isPlaying = false; - // isRecoding = false; - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); - // String? ext = getFileExtension(voiceFile.path); - // Utils.hideLoading(context); - // sendChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // chatReplyId: null, - // isAttachment: true, - // isReply: isReplyMsg, - // isImageLoaded: false, - // voiceFile: voiceFile, - // isVoiceAttached: true, - // userEmail: userEmail, - // userStatus: userStatus); - // notifyListeners(); - // } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { - // logger.d("// Voice as Reply Msg"); - // - // if (!isPause) { - // path = await recorderController.stop(false); - // } - // if (kDebugMode) { - // logger.i("path:" + path!); - // } - // File voiceFile = File(path!); - // voiceFile.readAsBytesSync(); - // _timer?.cancel(); - // isPause = false; - // isPlaying = false; - // isRecoding = false; - // - // Utils.showLoading(context); - // dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); - // String? ext = getFileExtension(voiceFile.path); - // Utils.hideLoading(context); - // sendChatToServer( - // chatEventId: 2, - // fileTypeId: getFileType(ext.toString()), - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // chatReplyId: null, - // isAttachment: true, - // isReply: isReplyMsg, - // isImageLoaded: false, - // voiceFile: voiceFile, - // isVoiceAttached: true, - // userEmail: userEmail, - // userStatus: userStatus); - // notifyListeners(); - // } - // if (searchedChats != null) { - // dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); - // if (contain.isEmpty) { - // List emails = []; - // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - // searchedChats!.add( - // ChatUser( - // id: targetUserId, - // userName: targetUserName, - // unreadMessageCount: 0, - // email: userEmail, - // isImageLoading: false, - // image: chatImages.first.profilePicture ?? "", - // isImageLoaded: true, - // isTyping: false, - // isFav: false, - // userStatus: userStatus, - // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), - // ), - // ); - // notifyListeners(); - // } - // } - // // else { - // // List emails = []; - // // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - // // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - // // searchedChats!.add( - // // ChatUser( - // // id: targetUserId, - // // userName: targetUserName, - // // unreadMessageCount: 0, - // // email: userEmail, - // // isImageLoading: false, - // // image: chatImages.first.profilePicture ?? "", - // // isImageLoaded: true, - // // isTyping: false, - // // isFav: false, - // // userStatus: userStatus, - // // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), - // // ), - // // ); - // // notifyListeners(); - // // } - // } +String getFileTypeDescription(String value) { + switch (value) { + case ".pdf": + return "application/pdf"; + case ".png": + return "image/png"; + case ".txt": + return "text/plain"; + case ".jpg": + return "image/jpg"; + case ".jpeg": + return "image/jpeg"; + case ".ppt": + return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + case ".pptx": + return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + case ".doc": + return "application/vnd.openxmlformats-officedocument.wordprocessingm"; + case ".docx": + return "application/vnd.openxmlformats-officedocument.wordprocessingm"; + case ".xls": + return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + case ".xlsx": + return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + case ".zip": + return "application/octet-stream"; + case ".rar": + return "application/octet-stream"; + case ".aac": + return "audio/aac"; + case ".mp3": + return "audio/mp3"; + case ".mp4": + return "video/mp4"; + case ".avi": + return "video/avi"; + case ".flv": + return "video/flv"; + case ".mov": + return "video/mov"; + + default: + return ""; + } +} - // void selectImageToUpload(BuildContext context) { - // ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { - // if (checkFileSize(file.path)) { - // selectedFile = file; - // isAttachmentMsg = true; - // isTextMsg = false; - // sFileType = getFileExtension(file.path)!; - // message.text = file.path.split("/").last; - // Navigator.of(context).pop(); - // } else { - // Utils.showToast("Max 1 mb size is allowed to upload"); - // } - // notifyListeners(); - // }); - // } +// Future sendChatToServer( +// {required int chatEventId, +// required fileTypeId, +// required int targetUserId, +// required String targetUserName, +// required chatReplyId, +// required bool isAttachment, +// required bool isReply, +// Uint8List? image, +// required bool isImageLoaded, +// String? userEmail, +// int? userStatus, +// File? voiceFile, +// required bool isVoiceAttached}) async { +// Uuid uuid = const Uuid(); +// String contentNo = uuid.v4(); +// String msg; +// if (isVoiceAttached) { +// msg = voiceFile!.path.split("/").last; +// } else { +// msg = message.text; +// logger.w(msg); +// } +// SingleUserChatModel data = SingleUserChatModel( +// userChatHistoryId: 0, +// chatEventId: chatEventId, +// chatSource: 1, +// contant: msg, +// contantNo: contentNo, +// conversationId: chatCID, +// createdDate: DateTime.now(), +// currentUserId: AppState().chatDetails!.response!.id, +// currentUserName: AppState().chatDetails!.response!.userName, +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isReplied: false, +// fileTypeId: fileTypeId, +// userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, +// fileTypeResponse: isAttachment +// ? FileTypeResponse( +// fileTypeId: fileTypeId, +// fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), +// fileKind: "file", +// fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, +// fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), +// ) +// : null, +// image: image, +// isImageLoaded: isImageLoaded, +// voice: isVoiceMsg ? voiceFile! : null, +// voiceController: isVoiceMsg ? AudioPlayer() : null); +// if (kDebugMode) { +// logger.i("model data: " + jsonEncode(data)); +// } +// userChatHistory.insert(0, data); +// isTextMsg = false; +// isReplyMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// sFileType = ""; +// message.clear(); +// notifyListeners(); +// +// String chatData = +// '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; +// +// await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); +// } - // void removeAttachment() { - // isAttachmentMsg = false; - // sFileType = ""; - // message.text = ''; - // notifyListeners(); - // } +//groupChatMessage + +// Future sendGroupChatToServer( +// {required int chatEventId, +// required fileTypeId, +// required int targetGroupId, +// required String targetUserName, +// required chatReplyId, +// required bool isAttachment, +// required bool isReply, +// Uint8List? image, +// required bool isImageLoaded, +// String? userEmail, +// int? userStatus, +// File? voiceFile, +// required bool isVoiceAttached, +// required List userList}) async { +// Uuid uuid = const Uuid(); +// String contentNo = uuid.v4(); +// String msg; +// if (isVoiceAttached) { +// msg = voiceFile!.path.split("/").last; +// } else { +// msg = message.text; +// logger.w(msg); +// } +// groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( +// //userChatHistoryId: 0, +// chatEventId: chatEventId, +// chatSource: 1, +// contant: msg, +// contantNo: contentNo, +// conversationId: chatCID, +// createdDate: DateTime.now().toString(), +// currentUserId: AppState().chatDetails!.response!.id, +// currentUserName: AppState().chatDetails!.response!.userName, +// groupId: targetGroupId, +// groupName: targetUserName, +// isReplied: false, +// fileTypeId: fileTypeId, +// fileTypeResponse: isAttachment +// ? groupchathistory.FileTypeResponse( +// fileTypeId: fileTypeId, +// fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), +// fileKind: "file", +// fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, +// fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) +// : null, +// image: image, +// isImageLoaded: isImageLoaded, +// voice: isVoiceMsg ? voiceFile! : null, +// voiceController: isVoiceMsg ? AudioPlayer() : null); +// if (kDebugMode) { +// logger.i("model data: " + jsonEncode(data)); +// } +// groupChatHistory.insert(0, data); +// isTextMsg = false; +// isReplyMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// sFileType = ""; +// message.clear(); +// notifyListeners(); +// +// List targetUsers = []; +// +// for (GroupUserList element in userList) { +// targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); +// } +// +// String chatData = +// '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; +// +// await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); +// } - String? getFileExtension(String fileName) { - try { - if (kDebugMode) { - // logger.i("ext: " + "." + fileName.split('.').last); - } - return "." + fileName.split('.').last; - } catch (e) { - return null; +// void sendGroupChatMessage( +// BuildContext context, { +// required int targetUserId, +// required int userStatus, +// required String userEmail, +// required String targetUserName, +// required List userList, +// }) async { +// if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Text Message"); +// if (message.text.isEmpty) { +// return; +// } +// sendGroupChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: false, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: false, +// image: null, +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Text Message as Reply"); +// if (message.text.isEmpty) { +// return; +// } +// sendGroupChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: groupChatReplyData.first.groupChatHistoryId, +// isAttachment: false, +// isReply: true, +// isImageLoaded: groupChatReplyData.first.isImageLoaded!, +// image: groupChatReplyData.first.image, +// isVoiceAttached: false, +// voiceFile: null, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } +// // Attachment +// else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Image Message"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Image as Reply Msg"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: repliedMsg.first.userChatHistoryId, +// isReply: true, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// } +// //Voice +// +// else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Voice Message"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// //, +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// notifyListeners(); +// } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { +// logger.d("// Voice as Reply Msg"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendGroupChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetGroupId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus, +// userList: userList); +// notifyListeners(); +// } +// if (searchedChats != null) { +// dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); +// if (contain.isEmpty) { +// List emails = []; +// emails.add(await EmailImageEncryption().encrypt(val: userEmail)); +// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// searchedChats!.add( +// ChatUser( +// id: targetUserId, +// userName: targetUserName, +// unreadMessageCount: 0, +// email: userEmail, +// isImageLoading: false, +// image: chatImages.first.profilePicture ?? "", +// isImageLoaded: true, +// isTyping: false, +// isFav: false, +// userStatus: userStatus, +// // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), +// ), +// ); +// notifyListeners(); +// } +// } +// } + +// void sendChatMessage( +// BuildContext context, { +// required int targetUserId, +// required int userStatus, +// required String userEmail, +// required String targetUserName, +// }) async { +// if (kDebugMode) { +// print("====================== Values ============================"); +// print("Is Text " + isTextMsg.toString()); +// print("isReply " + isReplyMsg.toString()); +// print("isAttachment " + isAttachmentMsg.toString()); +// print("isVoice " + isVoiceMsg.toString()); +// } +// //Text +// if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// // logger.d("// Normal Text Message"); +// if (message.text.isEmpty) { +// return; +// } +// sendChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: false, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: false, +// image: null, +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus); +// } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Text Message as Reply"); +// if (message.text.isEmpty) { +// return; +// } +// sendChatToServer( +// chatEventId: 1, +// fileTypeId: null, +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: repliedMsg.first.userChatHistoryId, +// isAttachment: false, +// isReply: true, +// isImageLoaded: repliedMsg.first.isImageLoaded!, +// image: repliedMsg.first.image, +// isVoiceAttached: false, +// voiceFile: null, +// userEmail: userEmail, +// userStatus: userStatus); +// } +// // Attachment +// else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Image Message"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: null, +// isReply: false, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus); +// } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { +// logger.d("// Image as Reply Msg"); +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); +// String? ext = getFileExtension(selectedFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// isAttachment: true, +// chatReplyId: repliedMsg.first.userChatHistoryId, +// isReply: true, +// isImageLoaded: true, +// image: selectedFile.readAsBytesSync(), +// isVoiceAttached: false, +// userEmail: userEmail, +// userStatus: userStatus); +// } +// //Voice +// +// else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { +// logger.d("// Normal Voice Message"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus); +// notifyListeners(); +// } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { +// logger.d("// Voice as Reply Msg"); +// +// if (!isPause) { +// path = await recorderController.stop(false); +// } +// if (kDebugMode) { +// logger.i("path:" + path!); +// } +// File voiceFile = File(path!); +// voiceFile.readAsBytesSync(); +// _timer?.cancel(); +// isPause = false; +// isPlaying = false; +// isRecoding = false; +// +// Utils.showLoading(context); +// dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); +// String? ext = getFileExtension(voiceFile.path); +// Utils.hideLoading(context); +// sendChatToServer( +// chatEventId: 2, +// fileTypeId: getFileType(ext.toString()), +// targetUserId: targetUserId, +// targetUserName: targetUserName, +// chatReplyId: null, +// isAttachment: true, +// isReply: isReplyMsg, +// isImageLoaded: false, +// voiceFile: voiceFile, +// isVoiceAttached: true, +// userEmail: userEmail, +// userStatus: userStatus); +// notifyListeners(); +// } +// if (searchedChats != null) { +// dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); +// if (contain.isEmpty) { +// List emails = []; +// emails.add(await EmailImageEncryption().encrypt(val: userEmail)); +// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// searchedChats!.add( +// ChatUser( +// id: targetUserId, +// userName: targetUserName, +// unreadMessageCount: 0, +// email: userEmail, +// isImageLoading: false, +// image: chatImages.first.profilePicture ?? "", +// isImageLoaded: true, +// isTyping: false, +// isFav: false, +// userStatus: userStatus, +// userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), +// ), +// ); +// notifyListeners(); +// } +// } +// // else { +// // List emails = []; +// // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); +// // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// // searchedChats!.add( +// // ChatUser( +// // id: targetUserId, +// // userName: targetUserName, +// // unreadMessageCount: 0, +// // email: userEmail, +// // isImageLoading: false, +// // image: chatImages.first.profilePicture ?? "", +// // isImageLoaded: true, +// // isTyping: false, +// // isFav: false, +// // userStatus: userStatus, +// // userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), +// // ), +// // ); +// // notifyListeners(); +// // } +// } + +// void selectImageToUpload(BuildContext context) { +// ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { +// if (checkFileSize(file.path)) { +// selectedFile = file; +// isAttachmentMsg = true; +// isTextMsg = false; +// sFileType = getFileExtension(file.path)!; +// message.text = file.path.split("/").last; +// Navigator.of(context).pop(); +// } else { +// Utils.showToast("Max 1 mb size is allowed to upload"); +// } +// notifyListeners(); +// }); +// } + +// void removeAttachment() { +// isAttachmentMsg = false; +// sFileType = ""; +// message.text = ''; +// notifyListeners(); +// } + +String? getFileExtension(String fileName) { + try { + if (kDebugMode) { + // logger.i("ext: " + "." + fileName.split('.').last); } + return "." + fileName.split('.').last; + } catch (e) { + return null; } +} - bool checkFileSize(String path) { - int fileSizeLimit = 5120; - File f = File(path); - double fileSizeInKB = f.lengthSync() / 5000; - double fileSizeInMB = fileSizeInKB / 5000; - if (fileSizeInKB > fileSizeLimit) { - return false; - } else { - return true; - } +bool checkFileSize(String path) { + int fileSizeLimit = 5120; + File f = File(path); + double fileSizeInKB = f.lengthSync() / 5000; + double fileSizeInMB = fileSizeInKB / 5000; + if (fileSizeInKB > fileSizeLimit) { + return false; + } else { + return true; } +} - String getType(String type) { - switch (type) { - case ".pdf": - return "assets/images/pdf.svg"; - case ".png": - return "assets/images/png.svg"; - case ".txt": - return "assets/icons/chat/txt.svg"; - case ".jpg": - return "assets/images/jpg.svg"; - case ".jpeg": - return "assets/images/jpg.svg"; - case ".xls": - return "assets/icons/chat/xls.svg"; - case ".xlsx": - return "assets/icons/chat/xls.svg"; - case ".doc": - return "assets/icons/chat/doc.svg"; - case ".docx": - return "assets/icons/chat/doc.svg"; - case ".ppt": - return "assets/icons/chat/ppt.svg"; - case ".pptx": - return "assets/icons/chat/ppt.svg"; - case ".zip": - return "assets/icons/chat/zip.svg"; - case ".rar": - return "assets/icons/chat/zip.svg"; - case ".aac": - return "assets/icons/chat/aac.svg"; - case ".mp3": - return "assets/icons/chat/zip.mp3"; - default: - return "assets/images/thumb.svg"; - } +String getType(String type) { + switch (type) { + case ".pdf": + return "assets/images/pdf.svg"; + case ".png": + return "assets/images/png.svg"; + case ".txt": + return "assets/icons/chat/txt.svg"; + case ".jpg": + return "assets/images/jpg.svg"; + case ".jpeg": + return "assets/images/jpg.svg"; + case ".xls": + return "assets/icons/chat/xls.svg"; + case ".xlsx": + return "assets/icons/chat/xls.svg"; + case ".doc": + return "assets/icons/chat/doc.svg"; + case ".docx": + return "assets/icons/chat/doc.svg"; + case ".ppt": + return "assets/icons/chat/ppt.svg"; + case ".pptx": + return "assets/icons/chat/ppt.svg"; + case ".zip": + return "assets/icons/chat/zip.svg"; + case ".rar": + return "assets/icons/chat/zip.svg"; + case ".aac": + return "assets/icons/chat/aac.svg"; + case ".mp3": + return "assets/icons/chat/zip.mp3"; + default: + return "assets/images/thumb.svg"; } +} - // void chatReply(SingleUserChatModel data) { - // repliedMsg = []; - // data.isReplied = true; - // isReplyMsg = true; - // repliedMsg.add(data); - // notifyListeners(); - // } - - // void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { - // groupChatReplyData = []; - // data.isReplied = true; - // isReplyMsg = true; - // groupChatReplyData.add(data); - // notifyListeners(); - // } +// void chatReply(SingleUserChatModel data) { +// repliedMsg = []; +// data.isReplied = true; +// isReplyMsg = true; +// repliedMsg.add(data); +// notifyListeners(); +// } - // void closeMe() { - // repliedMsg = []; - // isReplyMsg = false; - // notifyListeners(); - // } +// void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { +// groupChatReplyData = []; +// data.isReplied = true; +// isReplyMsg = true; +// groupChatReplyData.add(data); +// notifyListeners(); +// } - String dateFormte(DateTime data) { - DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); - f.format(data); - return f.format(data); - } +// void closeMe() { +// repliedMsg = []; +// isReplyMsg = false; +// notifyListeners(); +// } - // Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { - // fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); - // if (favoriteChatUser.response != null) { - // for (ChatUser user in searchedChats!) { - // if (user.id == favoriteChatUser.response!.targetUserId!) { - // user.isFav = favoriteChatUser.response!.isFav; - // dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); - // if (contain.isEmpty) { - // favUsersList.add(user); - // } - // } - // } - // - // for (ChatUser user in chatUsersList!) { - // if (user.id == favoriteChatUser.response!.targetUserId!) { - // user.isFav = favoriteChatUser.response!.isFav; - // dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); - // if (contain.isEmpty) { - // favUsersList.add(user); - // } - // } - // } - // } - // if (fromSearch) { - // for (ChatUser user in favUsersList) { - // if (user.id == targetUserID) { - // user.userLocalDownlaodedImage = null; - // user.isImageLoading = false; - // user.isImageLoaded = false; - // } - // } - // } - // notifyListeners(); - // } - // - // Future unFavoriteUser({required int userID, required int targetUserID}) async { - // fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); - // - // if (favoriteChatUser.response != null) { - // for (ChatUser user in searchedChats!) { - // if (user.id == favoriteChatUser.response!.targetUserId!) { - // user.isFav = favoriteChatUser.response!.isFav; - // } - // } - // favUsersList.removeWhere( - // (ChatUser element) => element.id == targetUserID, - // ); - // } - // - // for (ChatUser user in chatUsersList!) { - // if (user.id == favoriteChatUser.response!.targetUserId!) { - // user.isFav = favoriteChatUser.response!.isFav; - // } - // } - // - // notifyListeners(); - // } +String dateFormte(DateTime data) { + DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); + f.format(data); + return f.format(data); +} - // void clearSelections() { - // searchedChats = pChatHistory; - // search.clear(); - // isChatScreenActive = false; - // receiverID = 0; - // paginationVal = 0; - // message.text = ''; - // isAttachmentMsg = false; - // repliedMsg = []; - // sFileType = ""; - // isReplyMsg = false; - // isTextMsg = false; - // isVoiceMsg = false; - // notifyListeners(); - // } - // - // void clearAll() { - // searchedChats = pChatHistory; - // search.clear(); - // isChatScreenActive = false; - // receiverID = 0; - // paginationVal = 0; - // message.text = ''; - // isTextMsg = false; - // isAttachmentMsg = false; - // isVoiceMsg = false; - // isReplyMsg = false; - // repliedMsg = []; - // sFileType = ""; - // } - // - // void disposeData() { - // if (!disbaleChatForThisUser) { - // search.clear(); - // isChatScreenActive = false; - // receiverID = 0; - // paginationVal = 0; - // message.text = ''; - // isTextMsg = false; - // isAttachmentMsg = false; - // isVoiceMsg = false; - // isReplyMsg = false; - // repliedMsg = []; - // sFileType = ""; - // deleteData(); - // favUsersList.clear(); - // searchedChats?.clear(); - // pChatHistory?.clear(); - // // uGroups?.clear(); - // searchGroup?.clear(); - // chatHubConnection.stop(); - // // AppState().chatDetails = null; - // } - // } - // - // void deleteData() { - // List exists = [], unique = []; - // if (searchedChats != null) exists.addAll(searchedChats!); - // exists.addAll(favUsersList!); - // Map profileMap = {}; - // for (ChatUser item in exists) { - // profileMap[item.email!] = item; - // } - // unique = profileMap.values.toList(); - // for (ChatUser element in unique!) { - // deleteFile(element.id.toString()); - // } - // } +// Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { +// fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); +// if (favoriteChatUser.response != null) { +// for (ChatUser user in searchedChats!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); +// if (contain.isEmpty) { +// favUsersList.add(user); +// } +// } +// } +// +// for (ChatUser user in chatUsersList!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); +// if (contain.isEmpty) { +// favUsersList.add(user); +// } +// } +// } +// } +// if (fromSearch) { +// for (ChatUser user in favUsersList) { +// if (user.id == targetUserID) { +// user.userLocalDownlaodedImage = null; +// user.isImageLoading = false; +// user.isImageLoaded = false; +// } +// } +// } +// notifyListeners(); +// } +// +// Future unFavoriteUser({required int userID, required int targetUserID}) async { +// fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); +// +// if (favoriteChatUser.response != null) { +// for (ChatUser user in searchedChats!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// } +// } +// favUsersList.removeWhere( +// (ChatUser element) => element.id == targetUserID, +// ); +// } +// +// for (ChatUser user in chatUsersList!) { +// if (user.id == favoriteChatUser.response!.targetUserId!) { +// user.isFav = favoriteChatUser.response!.isFav; +// } +// } +// +// notifyListeners(); +// } - // void getUserImages() async { - // List emails = []; - // List exists = [], unique = []; - // exists.addAll(searchedChats!); - // exists.addAll(favUsersList!); - // Map profileMap = {}; - // for (ChatUser item in exists) { - // profileMap[item.email!] = item; - // } - // unique = profileMap.values.toList(); - // for (ChatUser element in unique!) { - // emails.add(await EmailImageEncryption().encrypt(val: element.email!)); - // } - // - // List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); - // for (ChatUser user in searchedChats!) { - // for (ChatUserImageModel uImage in chatImages) { - // if (user.email == uImage.email) { - // user.image = uImage.profilePicture ?? ""; - // user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); - // user.isImageLoading = false; - // user.isImageLoaded = true; - // } - // } - // } - // for (ChatUser favUser in favUsersList) { - // for (ChatUserImageModel uImage in chatImages) { - // if (favUser.email == uImage.email) { - // favUser.image = uImage.profilePicture ?? ""; - // favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); - // favUser.isImageLoading = false; - // favUser.isImageLoaded = true; - // } - // } - // } - // - // notifyListeners(); - // } +// void clearSelections() { +// searchedChats = pChatHistory; +// search.clear(); +// isChatScreenActive = false; +// receiverID = 0; +// paginationVal = 0; +// message.text = ''; +// isAttachmentMsg = false; +// repliedMsg = []; +// sFileType = ""; +// isReplyMsg = false; +// isTextMsg = false; +// isVoiceMsg = false; +// notifyListeners(); +// } +// +// void clearAll() { +// searchedChats = pChatHistory; +// search.clear(); +// isChatScreenActive = false; +// receiverID = 0; +// paginationVal = 0; +// message.text = ''; +// isTextMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// isReplyMsg = false; +// repliedMsg = []; +// sFileType = ""; +// } +// +// void disposeData() { +// if (!disbaleChatForThisUser) { +// search.clear(); +// isChatScreenActive = false; +// receiverID = 0; +// paginationVal = 0; +// message.text = ''; +// isTextMsg = false; +// isAttachmentMsg = false; +// isVoiceMsg = false; +// isReplyMsg = false; +// repliedMsg = []; +// sFileType = ""; +// deleteData(); +// favUsersList.clear(); +// searchedChats?.clear(); +// pChatHistory?.clear(); +// // uGroups?.clear(); +// searchGroup?.clear(); +// chatHubConnection.stop(); +// // AppState().chatDetails = null; +// } +// } +// +// void deleteData() { +// List exists = [], unique = []; +// if (searchedChats != null) exists.addAll(searchedChats!); +// exists.addAll(favUsersList!); +// Map profileMap = {}; +// for (ChatUser item in exists) { +// profileMap[item.email!] = item; +// } +// unique = profileMap.values.toList(); +// for (ChatUser element in unique!) { +// deleteFile(element.id.toString()); +// } +// } - Future downloadImageLocal(String? encodedBytes, String userID) async { - File? myfile; - if (encodedBytes == null) { - return myfile; - } else { - await deleteFile(userID); - Uint8List decodedBytes = base64Decode(encodedBytes); - Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); - String dirPath = '${appDocumentsDirectory.path}/chat_images'; - if (!await Directory(dirPath).exists()) { - await Directory(dirPath).create(); - await File('$dirPath/.nomedia').create(); - } - late File imageFile = File("$dirPath/$userID.jpg"); - imageFile.writeAsBytesSync(decodedBytes); - return imageFile; - } - } +// void getUserImages() async { +// List emails = []; +// List exists = [], unique = []; +// exists.addAll(searchedChats!); +// exists.addAll(favUsersList!); +// Map profileMap = {}; +// for (ChatUser item in exists) { +// profileMap[item.email!] = item; +// } +// unique = profileMap.values.toList(); +// for (ChatUser element in unique!) { +// emails.add(await EmailImageEncryption().encrypt(val: element.email!)); +// } +// +// List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); +// for (ChatUser user in searchedChats!) { +// for (ChatUserImageModel uImage in chatImages) { +// if (user.email == uImage.email) { +// user.image = uImage.profilePicture ?? ""; +// user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); +// user.isImageLoading = false; +// user.isImageLoaded = true; +// } +// } +// } +// for (ChatUser favUser in favUsersList) { +// for (ChatUserImageModel uImage in chatImages) { +// if (favUser.email == uImage.email) { +// favUser.image = uImage.profilePicture ?? ""; +// favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); +// favUser.isImageLoading = false; +// favUser.isImageLoaded = true; +// } +// } +// } +// +// notifyListeners(); +// } - Future deleteFile(String userID) async { +Future downloadImageLocal(String? encodedBytes, String userID) async { + File? myfile; + if (encodedBytes == null) { + return myfile; + } else { + await deleteFile(userID); + Uint8List decodedBytes = base64Decode(encodedBytes); Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); String dirPath = '${appDocumentsDirectory.path}/chat_images'; - late File imageFile = File('$dirPath/$userID.jpg'); - if (await imageFile.exists()) { - await imageFile.delete(); + if (!await Directory(dirPath).exists()) { + await Directory(dirPath).create(); + await File('$dirPath/.nomedia').create(); } + late File imageFile = File("$dirPath/$userID.jpg"); + imageFile.writeAsBytesSync(decodedBytes); + return imageFile; } +} - Future downChatMedia(Uint8List bytes, String ext) async { - String dir = (await getApplicationDocumentsDirectory()).path; - File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); - await file.writeAsBytes(bytes); - return file.path; +Future deleteFile(String userID) async { + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); + String dirPath = '${appDocumentsDirectory.path}/chat_images'; + late File imageFile = File('$dirPath/$userID.jpg'); + if (await imageFile.exists()) { + await imageFile.delete(); } +} - void setMsgTune() async { - JustAudio.AudioPlayer player = JustAudio.AudioPlayer(); - await player.setVolume(1.0); - String audioAsset = ""; - if (Platform.isAndroid) { - audioAsset = "assets/audio/pulse_tone_android.mp3"; - } else { - audioAsset = "assets/audio/pulse_tune_ios.caf"; - } - try { - await player.setAsset(audioAsset); - await player.load(); - player.play(); - } catch (e) { - print("Error: $e"); - } +Future downChatMedia(Uint8List bytes, String ext) async { + String dir = (await getApplicationDocumentsDirectory()).path; + File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + await file.writeAsBytes(bytes); + return file.path; +} + +void setMsgTune() async { + JustAudio.AudioPlayer player = JustAudio.AudioPlayer(); + await player.setVolume(1.0); + String audioAsset = ""; + if (Platform.isAndroid) { + audioAsset = "assets/audio/pulse_tone_android.mp3"; + } else { + audioAsset = "assets/audio/pulse_tune_ios.caf"; + } + try { + await player.setAsset(audioAsset); + await player.load(); + player.play(); + } catch (e) { + print("Error: $e"); } +} - // Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { - // Utils.showLoading(context); - // if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { - // Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); - // try { - // String path = await downChatMedia(encodedString, fileTypeName ?? ""); - // Utils.hideLoading(context); - // OpenFilex.open(path); - // } catch (e) { - // Utils.showToast("Cannot open file."); - // } - // } - // } +// Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { +// Utils.showLoading(context); +// if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { +// Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); +// try { +// String path = await downChatMedia(encodedString, fileTypeName ?? ""); +// Utils.hideLoading(context); +// OpenFilex.open(path); +// } catch (e) { +// Utils.showToast("Cannot open file."); +// } +// } +// } - // void onNewChatConversion(List? params) { - // dynamic items = params!.toList(); - // chatUConvCounter = items[0]["singleChatCount"] ?? 0; - // notifyListeners(); - // } +// void onNewChatConversion(List? params) { +// dynamic items = params!.toList(); +// chatUConvCounter = items[0]["singleChatCount"] ?? 0; +// notifyListeners(); +// } - Future invokeChatCounter({required int userId}) async { - await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); - return ""; - } +Future invokeChatCounter({required int userId}) async { + await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); + return ""; +} - void userTypingInvoke({required int currentUser, required int reciptUser}) async { - await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); - } +void userTypingInvoke({required int currentUser, required int reciptUser}) async { + await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); +} - // void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { - // var data = json.decode(json.encode(groupDetails.groupUserList)); - // await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); - // } +// void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { +// var data = json.decode(json.encode(groupDetails.groupUserList)); +// await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); +// } //////// Audio Recoding Work //////////////////// - // Future initAudio({required int receiverId}) async { - // // final dir = Directory((Platform.isAndroid - // // ? await getExternalStorageDirectory() //FOR ANDROID - // // : await getApplicationSupportDirectory() //FOR IOS - // // )! - // appDirectory = await getApplicationDocumentsDirectory(); - // String dirPath = '${appDirectory.path}/chat_audios'; - // if (!await Directory(dirPath).exists()) { - // await Directory(dirPath).create(); - // await File('$dirPath/.nomedia').create(); - // } - // path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; - // recorderController = RecorderController() - // ..androidEncoder = AndroidEncoder.aac - // ..androidOutputFormat = AndroidOutputFormat.mpeg4 - // ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC - // ..sampleRate = 6000 - // ..updateFrequency = const Duration(milliseconds: 100) - // ..bitRate = 18000; - // playerController = PlayerController(); - // } +// Future initAudio({required int receiverId}) async { +// // final dir = Directory((Platform.isAndroid +// // ? await getExternalStorageDirectory() //FOR ANDROID +// // : await getApplicationSupportDirectory() //FOR IOS +// // )! +// appDirectory = await getApplicationDocumentsDirectory(); +// String dirPath = '${appDirectory.path}/chat_audios'; +// if (!await Directory(dirPath).exists()) { +// await Directory(dirPath).create(); +// await File('$dirPath/.nomedia').create(); +// } +// path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; +// recorderController = RecorderController() +// ..androidEncoder = AndroidEncoder.aac +// ..androidOutputFormat = AndroidOutputFormat.mpeg4 +// ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC +// ..sampleRate = 6000 +// ..updateFrequency = const Duration(milliseconds: 100) +// ..bitRate = 18000; +// playerController = PlayerController(); +// } - // void disposeAudio() { - // isRecoding = false; - // isPlaying = false; - // isPause = false; - // isVoiceMsg = false; - // recorderController.dispose(); - // playerController.dispose(); - // } +// void disposeAudio() { +// isRecoding = false; +// isPlaying = false; +// isPause = false; +// isVoiceMsg = false; +// recorderController.dispose(); +// playerController.dispose(); +// } - // void startRecoding(BuildContext context) async { - // await Permission.microphone.request().then((PermissionStatus status) { - // if (status.isPermanentlyDenied) { - // Utils.confirmDialog( - // context, - // "The app needs microphone access to be able to record audio.", - // onTap: () { - // Navigator.of(context).pop(); - // openAppSettings(); - // }, - // ); - // } else if (status.isDenied) { - // Utils.confirmDialog( - // context, - // "The app needs microphone access to be able to record audio.", - // onTap: () { - // Navigator.of(context).pop(); - // openAppSettings(); - // }, - // ); - // } else if (status.isGranted) { - // sRecoding(); - // } else { - // startRecoding(context); - // } - // }); - // } - // - // void sRecoding() async { - // isVoiceMsg = true; - // recorderController.reset(); - // await recorderController.record(path: path); - // _recodeDuration = 0; - // _startTimer(); - // isRecoding = !isRecoding; - // notifyListeners(); - // } - // - // Future _startTimer() async { - // _timer?.cancel(); - // _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { - // _recodeDuration++; - // if (_recodeDuration <= 59) { - // applyCounter(); - // } else { - // pauseRecoding(); - // } - // }); - // } - // - // void applyCounter() { - // buildTimer(); - // notifyListeners(); - // } - // - // Future pauseRecoding() async { - // isPause = true; - // isPlaying = true; - // recorderController.pause(); - // path = await recorderController.stop(false); - // File file = File(path!); - // file.readAsBytesSync(); - // path = file.path; - // await playerController.preparePlayer(path: file.path, volume: 1.0); - // _timer?.cancel(); - // notifyListeners(); - // } - // - // Future deleteRecoding() async { - // _recodeDuration = 0; - // _timer?.cancel(); - // if (path == null) { - // path = await recorderController.stop(true); - // } else { - // await recorderController.stop(true); - // } - // if (path != null && path!.isNotEmpty) { - // File delFile = File(path!); - // double fileSizeInKB = delFile.lengthSync() / 1024; - // double fileSizeInMB = fileSizeInKB / 1024; - // if (kDebugMode) { - // debugPrint("Deleted file size: ${delFile.lengthSync()}"); - // debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); - // debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); - // } - // if (await delFile.exists()) { - // delFile.delete(); - // } - // isPause = false; - // isRecoding = false; - // isPlaying = false; - // isVoiceMsg = false; - // notifyListeners(); - // } - // } - // - // String buildTimer() { - // String minutes = _formatNum(_recodeDuration ~/ 60); - // String seconds = _formatNum(_recodeDuration % 60); - // return '$minutes : $seconds'; - // } +// void startRecoding(BuildContext context) async { +// await Permission.microphone.request().then((PermissionStatus status) { +// if (status.isPermanentlyDenied) { +// Utils.confirmDialog( +// context, +// "The app needs microphone access to be able to record audio.", +// onTap: () { +// Navigator.of(context).pop(); +// openAppSettings(); +// }, +// ); +// } else if (status.isDenied) { +// Utils.confirmDialog( +// context, +// "The app needs microphone access to be able to record audio.", +// onTap: () { +// Navigator.of(context).pop(); +// openAppSettings(); +// }, +// ); +// } else if (status.isGranted) { +// sRecoding(); +// } else { +// startRecoding(context); +// } +// }); +// } +// +// void sRecoding() async { +// isVoiceMsg = true; +// recorderController.reset(); +// await recorderController.record(path: path); +// _recodeDuration = 0; +// _startTimer(); +// isRecoding = !isRecoding; +// notifyListeners(); +// } +// +// Future _startTimer() async { +// _timer?.cancel(); +// _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { +// _recodeDuration++; +// if (_recodeDuration <= 59) { +// applyCounter(); +// } else { +// pauseRecoding(); +// } +// }); +// } +// +// void applyCounter() { +// buildTimer(); +// notifyListeners(); +// } +// +// Future pauseRecoding() async { +// isPause = true; +// isPlaying = true; +// recorderController.pause(); +// path = await recorderController.stop(false); +// File file = File(path!); +// file.readAsBytesSync(); +// path = file.path; +// await playerController.preparePlayer(path: file.path, volume: 1.0); +// _timer?.cancel(); +// notifyListeners(); +// } +// +// Future deleteRecoding() async { +// _recodeDuration = 0; +// _timer?.cancel(); +// if (path == null) { +// path = await recorderController.stop(true); +// } else { +// await recorderController.stop(true); +// } +// if (path != null && path!.isNotEmpty) { +// File delFile = File(path!); +// double fileSizeInKB = delFile.lengthSync() / 1024; +// double fileSizeInMB = fileSizeInKB / 1024; +// if (kDebugMode) { +// debugPrint("Deleted file size: ${delFile.lengthSync()}"); +// debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); +// debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); +// } +// if (await delFile.exists()) { +// delFile.delete(); +// } +// isPause = false; +// isRecoding = false; +// isPlaying = false; +// isVoiceMsg = false; +// notifyListeners(); +// } +// } +// +// String buildTimer() { +// String minutes = _formatNum(_recodeDuration ~/ 60); +// String seconds = _formatNum(_recodeDuration % 60); +// return '$minutes : $seconds'; +// } - String _formatNum(int number) { - String numberStr = number.toString(); - if (number < 10) { - numberStr = '0' + numberStr; - } - return numberStr; +String _formatNum(int number) { + String numberStr = number.toString(); + if (number < 10) { + numberStr = '0' + numberStr; } + return numberStr; +} - Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { - File file; - try { - String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; - if (!await Directory(dirPath).exists()) { - await Directory(dirPath).create(); - await File('$dirPath/.nomedia').create(); - } - file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); - await file.writeAsBytes(bytes); - } catch (e) { - if (kDebugMode) { - print(e); - } - file = File(""); +Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { + File file; + try { + String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; + if (!await Directory(dirPath).exists()) { + await Directory(dirPath).create(); + await File('$dirPath/.nomedia').create(); } - return file; + file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); + await file.writeAsBytes(bytes); + } catch (e) { + if (kDebugMode) { + print(e); + } + file = File(""); } + return file; +} - // void scrollToMsg(SingleUserChatModel data) { - // if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { - // int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); - // if (index >= 1) { - // double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; - // double target = contentSize * index / userChatHistory.length; - // scrollController.position.animateTo( - // target, - // duration: const Duration(seconds: 1), - // curve: Curves.easeInOut, - // ); - // } - // } - // } +// void scrollToMsg(SingleUserChatModel data) { +// if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { +// int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); +// if (index >= 1) { +// double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; +// double target = contentSize * index / userChatHistory.length; +// scrollController.position.animateTo( +// target, +// duration: const Duration(seconds: 1), +// curve: Curves.easeInOut, +// ); +// } +// } +// } - // - // Future getTeamMembers() async { - // teamMembersList = []; - // isLoading = true; - // if (AppState().getemployeeSubordinatesList.isNotEmpty) { - // getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; - // for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { - // if (element.eMPLOYEEEMAILADDRESS != null) { - // if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { - // teamMembersList.add( - // ChatUser( - // id: int.parse(element.eMPLOYEENUMBER!), - // email: element.eMPLOYEEEMAILADDRESS, - // userName: element.eMPLOYEENAME, - // phone: element.eMPLOYEEMOBILENUMBER, - // userStatus: 0, - // unreadMessageCount: 0, - // isFav: false, - // isTyping: false, - // isImageLoading: false, - // image: element.eMPLOYEEIMAGE ?? "", - // isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - // userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), - // ), - // ); - // } - // } - // } - // } else { - // getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); - // AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; - // for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { - // if (element.eMPLOYEEEMAILADDRESS != null) { - // if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { - // teamMembersList.add( - // ChatUser( - // id: int.parse(element.eMPLOYEENUMBER!), - // email: element.eMPLOYEEEMAILADDRESS, - // userName: element.eMPLOYEENAME, - // phone: element.eMPLOYEEMOBILENUMBER, - // userStatus: 0, - // unreadMessageCount: 0, - // isFav: false, - // isTyping: false, - // isImageLoading: false, - // image: element.eMPLOYEEIMAGE ?? "", - // isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - // userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), - // ), - // ); - // } - // } - // } - // } - // - // for (ChatUser user in searchedChats!) { - // for (ChatUser teamUser in teamMembersList!) { - // if (user.id == teamUser.id) { - // teamUser.userStatus = user.userStatus; - // } - // } - // } - // - // isLoading = false; - // notifyListeners(); - // } +// +// Future getTeamMembers() async { +// teamMembersList = []; +// isLoading = true; +// if (AppState().getemployeeSubordinatesList.isNotEmpty) { +// getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; +// for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { +// if (element.eMPLOYEEEMAILADDRESS != null) { +// if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { +// teamMembersList.add( +// ChatUser( +// id: int.parse(element.eMPLOYEENUMBER!), +// email: element.eMPLOYEEEMAILADDRESS, +// userName: element.eMPLOYEENAME, +// phone: element.eMPLOYEEMOBILENUMBER, +// userStatus: 0, +// unreadMessageCount: 0, +// isFav: false, +// isTyping: false, +// isImageLoading: false, +// image: element.eMPLOYEEIMAGE ?? "", +// isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, +// userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), +// ), +// ); +// } +// } +// } +// } else { +// getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); +// AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; +// for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { +// if (element.eMPLOYEEEMAILADDRESS != null) { +// if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { +// teamMembersList.add( +// ChatUser( +// id: int.parse(element.eMPLOYEENUMBER!), +// email: element.eMPLOYEEEMAILADDRESS, +// userName: element.eMPLOYEENAME, +// phone: element.eMPLOYEEMOBILENUMBER, +// userStatus: 0, +// unreadMessageCount: 0, +// isFav: false, +// isTyping: false, +// isImageLoading: false, +// image: element.eMPLOYEEIMAGE ?? "", +// isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, +// userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), +// ), +// ); +// } +// } +// } +// } +// +// for (ChatUser user in searchedChats!) { +// for (ChatUser teamUser in teamMembersList!) { +// if (user.id == teamUser.id) { +// teamUser.userStatus = user.userStatus; +// } +// } +// } +// +// isLoading = false; +// notifyListeners(); +// } - // void inputBoxDirection(String val) { - // if (val.isNotEmpty) { - // isTextMsg = true; - // } else { - // isTextMsg = false; - // } - // msgText = val; - // notifyListeners(); - // } - // - // void onDirectionChange(bool val) { - // isRTL = val; - // notifyListeners(); - // } +// void inputBoxDirection(String val) { +// if (val.isNotEmpty) { +// isTextMsg = true; +// } else { +// isTextMsg = false; +// } +// msgText = val; +// notifyListeners(); +// } +// +// void onDirectionChange(bool val) { +// isRTL = val; +// notifyListeners(); +// } - Material.TextDirection getTextDirection(String v) { - String str = v.trim(); - if (str.isEmpty) return Material.TextDirection.ltr; - int firstUnit = str.codeUnitAt(0); - if (firstUnit > 0x0600 && firstUnit < 0x06FF || - firstUnit > 0x0750 && firstUnit < 0x077F || - firstUnit > 0x07C0 && firstUnit < 0x07EA || - firstUnit > 0x0840 && firstUnit < 0x085B || - firstUnit > 0x08A0 && firstUnit < 0x08B4 || - firstUnit > 0x08E3 && firstUnit < 0x08FF || - firstUnit > 0xFB50 && firstUnit < 0xFBB1 || - firstUnit > 0xFBD3 && firstUnit < 0xFD3D || - firstUnit > 0xFD50 && firstUnit < 0xFD8F || - firstUnit > 0xFD92 && firstUnit < 0xFDC7 || - firstUnit > 0xFDF0 && firstUnit < 0xFDFC || - firstUnit > 0xFE70 && firstUnit < 0xFE74 || - firstUnit > 0xFE76 && firstUnit < 0xFEFC || - firstUnit > 0x10800 && firstUnit < 0x10805 || - firstUnit > 0x1B000 && firstUnit < 0x1B0FF || - firstUnit > 0x1D165 && firstUnit < 0x1D169 || - firstUnit > 0x1D16D && firstUnit < 0x1D172 || - firstUnit > 0x1D17B && firstUnit < 0x1D182 || - firstUnit > 0x1D185 && firstUnit < 0x1D18B || - firstUnit > 0x1D1AA && firstUnit < 0x1D1AD || - firstUnit > 0x1D242 && firstUnit < 0x1D244) { - return Material.TextDirection.rtl; - } - return Material.TextDirection.ltr; +Material.TextDirection getTextDirection(String v) { + String str = v.trim(); + if (str.isEmpty) return Material.TextDirection.ltr; + int firstUnit = str.codeUnitAt(0); + if (firstUnit > 0x0600 && firstUnit < 0x06FF || + firstUnit > 0x0750 && firstUnit < 0x077F || + firstUnit > 0x07C0 && firstUnit < 0x07EA || + firstUnit > 0x0840 && firstUnit < 0x085B || + firstUnit > 0x08A0 && firstUnit < 0x08B4 || + firstUnit > 0x08E3 && firstUnit < 0x08FF || + firstUnit > 0xFB50 && firstUnit < 0xFBB1 || + firstUnit > 0xFBD3 && firstUnit < 0xFD3D || + firstUnit > 0xFD50 && firstUnit < 0xFD8F || + firstUnit > 0xFD92 && firstUnit < 0xFDC7 || + firstUnit > 0xFDF0 && firstUnit < 0xFDFC || + firstUnit > 0xFE70 && firstUnit < 0xFE74 || + firstUnit > 0xFE76 && firstUnit < 0xFEFC || + firstUnit > 0x10800 && firstUnit < 0x10805 || + firstUnit > 0x1B000 && firstUnit < 0x1B0FF || + firstUnit > 0x1D165 && firstUnit < 0x1D169 || + firstUnit > 0x1D16D && firstUnit < 0x1D172 || + firstUnit > 0x1D17B && firstUnit < 0x1D182 || + firstUnit > 0x1D185 && firstUnit < 0x1D18B || + firstUnit > 0x1D1AA && firstUnit < 0x1D1AD || + firstUnit > 0x1D242 && firstUnit < 0x1D244) { + return Material.TextDirection.rtl; } + return Material.TextDirection.ltr; +} // void openChatByNoti(BuildContext context) async { // SingleUserChatModel nUser = SingleUserChatModel(); @@ -2066,4 +2156,3 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // isLoading = false; // notifyListeners(); // } -} diff --git a/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart b/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart index 3722c093..06e3da34 100644 --- a/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart +++ b/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart @@ -41,10 +41,10 @@ class SingleUserChatModel { int? userChatHistoryLineId; String? contant; String? contantNo; - int? currentUserId; + String? currentUserId; String? currentUserName; String? currentUserEmail; - int? targetUserId; + String? targetUserId; String? targetUserName; String? targetUserEmail; String? encryptedTargetUserId; @@ -69,9 +69,9 @@ class SingleUserChatModel { userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"], contant: json["contant"] == null ? null : json["contant"], contantNo: json["contantNo"] == null ? null : json["contantNo"], - currentUserId: json["currentUserId"] == null ? null : json["currentUserId"], + currentUserId: json["currentUserId"] == null ? null : json["currentUserId"].toString(), currentUserName: json["currentUserName"] == null ? null : json["currentUserName"], - targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], + targetUserId: json["targetUserId"] == null ? null : json["targetUserId"].toString(), targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], targetUserEmail: json["targetUserEmail"] == null ? null : json["targetUserEmail"], currentUserEmail: json["currentUserEmail"] == null ? null : json["currentUserEmail"], diff --git a/lib/modules/cx_module/chat/model/user_chat_history_model.dart b/lib/modules/cx_module/chat/model/user_chat_history_model.dart index 84d8a257..7ec1e9c3 100644 --- a/lib/modules/cx_module/chat/model/user_chat_history_model.dart +++ b/lib/modules/cx_module/chat/model/user_chat_history_model.dart @@ -1,224 +1,224 @@ -class UserChatHistoryModel { - List? response; - bool? isSuccess; - List? onlineUserConnId; - - UserChatHistoryModel({this.response, this.isSuccess, this.onlineUserConnId}); - - UserChatHistoryModel.fromJson(Map json) { - if (json['response'] != null) { - response = []; - json['response'].forEach((v) { - response!.add(new ChatResponse.fromJson(v)); - }); - } - isSuccess = json['isSuccess']; - onlineUserConnId = json['onlineUserConnId'].cast(); - } - - Map toJson() { - final Map data = new Map(); - if (this.response != null) { - data['response'] = this.response!.map((v) => v.toJson()).toList(); - } - data['isSuccess'] = this.isSuccess; - data['onlineUserConnId'] = this.onlineUserConnId; - return data; - } -} - -class ChatResponse { - int? id; - int? conversationId; - String? userId; - int? userIdInt; - String? userName; - String? content; - String? messageType; - String? createdAt; - - ChatResponse({this.id, this.conversationId, this.userId, this.userIdInt, this.userName, this.content, this.messageType, this.createdAt}); - - ChatResponse.fromJson(Map json) { - id = json['id']; - conversationId = json['conversationId']; - userId = json['userId']; - userIdInt = json['userIdInt']; - userName = json['userName']; - content = json['content']; - messageType = json['messageType']; - createdAt = json['createdAt']; - } - - Map toJson() { - final Map data = new Map(); - data['id'] = this.id; - data['conversationId'] = this.conversationId; - data['userId'] = this.userId; - data['userIdInt'] = this.userIdInt; - data['userName'] = this.userName; - data['content'] = this.content; - data['messageType'] = this.messageType; - data['createdAt'] = this.createdAt; - return data; - } -} - -class ChatHistoryResponse { - int? userChatHistoryId; - int? userChatHistoryLineId; - String? contant; - String? contantNo; - String? currentUserId; - String? currentEmployeeNumber; - String? currentUserName; - String? currentUserEmail; - String? currentFullName; - String? targetUserId; - String? targetEmployeeNumber; - String? targetUserName; - String? targetUserEmail; - String? targetFullName; - String? encryptedTargetUserId; - String? encryptedTargetUserName; - int? chatEventId; - String? fileTypeId; - bool? isSeen; - bool? isDelivered; - String? createdDate; - int? chatSource; - String? conversationId; - FileTypeResponse? fileTypeResponse; - String? userChatReplyResponse; - String? deviceToken; - bool? isHuaweiDevice; - String? platform; - String? voipToken; - - ChatHistoryResponse( - {this.userChatHistoryId, - this.userChatHistoryLineId, - this.contant, - this.contantNo, - this.currentUserId, - this.currentEmployeeNumber, - this.currentUserName, - this.currentUserEmail, - this.currentFullName, - this.targetUserId, - this.targetEmployeeNumber, - this.targetUserName, - this.targetUserEmail, - this.targetFullName, - this.encryptedTargetUserId, - this.encryptedTargetUserName, - this.chatEventId, - this.fileTypeId, - this.isSeen, - this.isDelivered, - this.createdDate, - this.chatSource, - this.conversationId, - this.fileTypeResponse, - this.userChatReplyResponse, - this.deviceToken, - this.isHuaweiDevice, - this.platform, - this.voipToken}); - - ChatHistoryResponse.fromJson(Map json) { - userChatHistoryId = json['userChatHistoryId']; - userChatHistoryLineId = json['userChatHistoryLineId']; - contant = json['contant']; - contantNo = json['contantNo']; - currentUserId = json['currentUserId']; - currentEmployeeNumber = json['currentEmployeeNumber']; - currentUserName = json['currentUserName']; - currentUserEmail = json['currentUserEmail']; - currentFullName = json['currentFullName']; - targetUserId = json['targetUserId']; - targetEmployeeNumber = json['targetEmployeeNumber']; - targetUserName = json['targetUserName']; - targetUserEmail = json['targetUserEmail']; - targetFullName = json['targetFullName']; - encryptedTargetUserId = json['encryptedTargetUserId']; - encryptedTargetUserName = json['encryptedTargetUserName']; - chatEventId = json['chatEventId']; - fileTypeId = json['fileTypeId']; - isSeen = json['isSeen']; - isDelivered = json['isDelivered']; - createdDate = json['createdDate']; - chatSource = json['chatSource']; - conversationId = json['conversationId']; - fileTypeResponse = json['fileTypeResponse'] != null ? new FileTypeResponse.fromJson(json['fileTypeResponse']) : null; - userChatReplyResponse = json['userChatReplyResponse']; - deviceToken = json['deviceToken']; - isHuaweiDevice = json['isHuaweiDevice']; - platform = json['platform']; - voipToken = json['voipToken']; - } - - Map toJson() { - final Map data = new Map(); - data['userChatHistoryId'] = this.userChatHistoryId; - data['userChatHistoryLineId'] = this.userChatHistoryLineId; - data['contant'] = this.contant; - data['contantNo'] = this.contantNo; - data['currentUserId'] = this.currentUserId; - data['currentEmployeeNumber'] = this.currentEmployeeNumber; - data['currentUserName'] = this.currentUserName; - data['currentUserEmail'] = this.currentUserEmail; - data['currentFullName'] = this.currentFullName; - data['targetUserId'] = this.targetUserId; - data['targetEmployeeNumber'] = this.targetEmployeeNumber; - data['targetUserName'] = this.targetUserName; - data['targetUserEmail'] = this.targetUserEmail; - data['targetFullName'] = this.targetFullName; - data['encryptedTargetUserId'] = this.encryptedTargetUserId; - data['encryptedTargetUserName'] = this.encryptedTargetUserName; - data['chatEventId'] = this.chatEventId; - data['fileTypeId'] = this.fileTypeId; - data['isSeen'] = this.isSeen; - data['isDelivered'] = this.isDelivered; - data['createdDate'] = this.createdDate; - data['chatSource'] = this.chatSource; - data['conversationId'] = this.conversationId; - if (this.fileTypeResponse != null) { - data['fileTypeResponse'] = this.fileTypeResponse!.toJson(); - } - data['userChatReplyResponse'] = this.userChatReplyResponse; - data['deviceToken'] = this.deviceToken; - data['isHuaweiDevice'] = this.isHuaweiDevice; - data['platform'] = this.platform; - data['voipToken'] = this.voipToken; - return data; - } -} - -class FileTypeResponse { - int? fileTypeId; - String? fileTypeName; - String? fileTypeDescription; - String? fileKind; - String? fileName; - - FileTypeResponse({this.fileTypeId, this.fileTypeName, this.fileTypeDescription, this.fileKind, this.fileName}); - - FileTypeResponse.fromJson(Map json) { - fileTypeId = json['fileTypeId']; - fileTypeName = json['fileTypeName']; - fileTypeDescription = json['fileTypeDescription']; - fileKind = json['fileKind']; - fileName = json['fileName']; - } - - Map toJson() { - final Map data = new Map(); - data['fileTypeId'] = this.fileTypeId; - data['fileTypeName'] = this.fileTypeName; - data['fileTypeDescription'] = this.fileTypeDescription; - data['fileKind'] = this.fileKind; - data['fileName'] = this.fileName; - return data; - } -} +// class UserChatHistoryModel { +// List? response; +// bool? isSuccess; +// List? onlineUserConnId; +// +// UserChatHistoryModel({this.response, this.isSuccess, this.onlineUserConnId}); +// +// UserChatHistoryModel.fromJson(Map json) { +// if (json['response'] != null) { +// response = []; +// json['response'].forEach((v) { +// response!.add(new ChatResponse.fromJson(v)); +// }); +// } +// isSuccess = json['isSuccess']; +// onlineUserConnId = json['onlineUserConnId'].cast(); +// } +// +// Map toJson() { +// final Map data = new Map(); +// if (this.response != null) { +// data['response'] = this.response!.map((v) => v.toJson()).toList(); +// } +// data['isSuccess'] = this.isSuccess; +// data['onlineUserConnId'] = this.onlineUserConnId; +// return data; +// } +// } +// +// class ChatResponse { +// int? id; +// int? conversationId; +// String? userId; +// int? userIdInt; +// String? userName; +// String? content; +// String? messageType; +// String? createdAt; +// +// ChatResponse({this.id, this.conversationId, this.userId, this.userIdInt, this.userName, this.content, this.messageType, this.createdAt}); +// +// ChatResponse.fromJson(Map json) { +// id = json['id']; +// conversationId = json['conversationId']; +// userId = json['userId']; +// userIdInt = json['userIdInt']; +// userName = json['userName']; +// content = json['content']; +// messageType = json['messageType']; +// createdAt = json['createdAt']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// data['id'] = this.id; +// data['conversationId'] = this.conversationId; +// data['userId'] = this.userId; +// data['userIdInt'] = this.userIdInt; +// data['userName'] = this.userName; +// data['content'] = this.content; +// data['messageType'] = this.messageType; +// data['createdAt'] = this.createdAt; +// return data; +// } +// } +// +// class ChatHistoryResponse { +// int? userChatHistoryId; +// int? userChatHistoryLineId; +// String? contant; +// String? contantNo; +// String? currentUserId; +// String? currentEmployeeNumber; +// String? currentUserName; +// String? currentUserEmail; +// String? currentFullName; +// String? targetUserId; +// String? targetEmployeeNumber; +// String? targetUserName; +// String? targetUserEmail; +// String? targetFullName; +// String? encryptedTargetUserId; +// String? encryptedTargetUserName; +// int? chatEventId; +// String? fileTypeId; +// bool? isSeen; +// bool? isDelivered; +// String? createdDate; +// int? chatSource; +// String? conversationId; +// FileTypeResponse? fileTypeResponse; +// String? userChatReplyResponse; +// String? deviceToken; +// bool? isHuaweiDevice; +// String? platform; +// String? voipToken; +// +// ChatHistoryResponse( +// {this.userChatHistoryId, +// this.userChatHistoryLineId, +// this.contant, +// this.contantNo, +// this.currentUserId, +// this.currentEmployeeNumber, +// this.currentUserName, +// this.currentUserEmail, +// this.currentFullName, +// this.targetUserId, +// this.targetEmployeeNumber, +// this.targetUserName, +// this.targetUserEmail, +// this.targetFullName, +// this.encryptedTargetUserId, +// this.encryptedTargetUserName, +// this.chatEventId, +// this.fileTypeId, +// this.isSeen, +// this.isDelivered, +// this.createdDate, +// this.chatSource, +// this.conversationId, +// this.fileTypeResponse, +// this.userChatReplyResponse, +// this.deviceToken, +// this.isHuaweiDevice, +// this.platform, +// this.voipToken}); +// +// ChatHistoryResponse.fromJson(Map json) { +// userChatHistoryId = json['userChatHistoryId']; +// userChatHistoryLineId = json['userChatHistoryLineId']; +// contant = json['contant']; +// contantNo = json['contantNo']; +// currentUserId = json['currentUserId']; +// currentEmployeeNumber = json['currentEmployeeNumber']; +// currentUserName = json['currentUserName']; +// currentUserEmail = json['currentUserEmail']; +// currentFullName = json['currentFullName']; +// targetUserId = json['targetUserId']; +// targetEmployeeNumber = json['targetEmployeeNumber']; +// targetUserName = json['targetUserName']; +// targetUserEmail = json['targetUserEmail']; +// targetFullName = json['targetFullName']; +// encryptedTargetUserId = json['encryptedTargetUserId']; +// encryptedTargetUserName = json['encryptedTargetUserName']; +// chatEventId = json['chatEventId']; +// fileTypeId = json['fileTypeId']; +// isSeen = json['isSeen']; +// isDelivered = json['isDelivered']; +// createdDate = json['createdDate']; +// chatSource = json['chatSource']; +// conversationId = json['conversationId']; +// fileTypeResponse = json['fileTypeResponse'] != null ? new FileTypeResponse.fromJson(json['fileTypeResponse']) : null; +// userChatReplyResponse = json['userChatReplyResponse']; +// deviceToken = json['deviceToken']; +// isHuaweiDevice = json['isHuaweiDevice']; +// platform = json['platform']; +// voipToken = json['voipToken']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// data['userChatHistoryId'] = this.userChatHistoryId; +// data['userChatHistoryLineId'] = this.userChatHistoryLineId; +// data['contant'] = this.contant; +// data['contantNo'] = this.contantNo; +// data['currentUserId'] = this.currentUserId; +// data['currentEmployeeNumber'] = this.currentEmployeeNumber; +// data['currentUserName'] = this.currentUserName; +// data['currentUserEmail'] = this.currentUserEmail; +// data['currentFullName'] = this.currentFullName; +// data['targetUserId'] = this.targetUserId; +// data['targetEmployeeNumber'] = this.targetEmployeeNumber; +// data['targetUserName'] = this.targetUserName; +// data['targetUserEmail'] = this.targetUserEmail; +// data['targetFullName'] = this.targetFullName; +// data['encryptedTargetUserId'] = this.encryptedTargetUserId; +// data['encryptedTargetUserName'] = this.encryptedTargetUserName; +// data['chatEventId'] = this.chatEventId; +// data['fileTypeId'] = this.fileTypeId; +// data['isSeen'] = this.isSeen; +// data['isDelivered'] = this.isDelivered; +// data['createdDate'] = this.createdDate; +// data['chatSource'] = this.chatSource; +// data['conversationId'] = this.conversationId; +// if (this.fileTypeResponse != null) { +// data['fileTypeResponse'] = this.fileTypeResponse!.toJson(); +// } +// data['userChatReplyResponse'] = this.userChatReplyResponse; +// data['deviceToken'] = this.deviceToken; +// data['isHuaweiDevice'] = this.isHuaweiDevice; +// data['platform'] = this.platform; +// data['voipToken'] = this.voipToken; +// return data; +// } +// } +// +// class FileTypeResponse { +// int? fileTypeId; +// String? fileTypeName; +// String? fileTypeDescription; +// String? fileKind; +// String? fileName; +// +// FileTypeResponse({this.fileTypeId, this.fileTypeName, this.fileTypeDescription, this.fileKind, this.fileName}); +// +// FileTypeResponse.fromJson(Map json) { +// fileTypeId = json['fileTypeId']; +// fileTypeName = json['fileTypeName']; +// fileTypeDescription = json['fileTypeDescription']; +// fileKind = json['fileKind']; +// fileName = json['fileName']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// data['fileTypeId'] = this.fileTypeId; +// data['fileTypeName'] = this.fileTypeName; +// data['fileTypeDescription'] = this.fileTypeDescription; +// data['fileKind'] = this.fileKind; +// data['fileName'] = this.fileName; +// return data; +// } +// } From c5b4325aecdbdfa765287c32fd044e651d60890a Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 17 Nov 2025 14:00:54 +0300 Subject: [PATCH 21/31] survey notification finalized. --- .../notification/firebase_notification_manger.dart | 4 ++++ lib/models/system_notification_model.dart | 4 ++-- .../views/service_request_detail_main_view.dart | 6 ------ lib/modules/cx_module/survey/survey_page.dart | 8 +++++--- .../pages/user/notifications/notifications_page.dart | 9 ++++----- lib/views/widgets/notifications/notification_item.dart | 10 +++++----- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart index 16abd263..7a8a67f9 100644 --- a/lib/controllers/notification/firebase_notification_manger.dart +++ b/lib/controllers/notification/firebase_notification_manger.dart @@ -9,6 +9,7 @@ import 'package:test_sa/controllers/notification/notification_manger.dart'; import 'package:test_sa/models/device/device_transfer.dart'; import 'package:test_sa/models/new_models/gas_refill_model.dart'; import 'package:test_sa/modules/cm_module/views/service_request_detail_main_view.dart'; +import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart'; import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart'; import 'package:test_sa/views/pages/device_transfer/device_transfer_details.dart'; @@ -120,6 +121,9 @@ class FirebaseNotificationManger { break; case "12": serviceClass = RecurrentWorkOrderView(taskId: int.parse(messageData["requestNumber"].toString())); + case "17": + serviceClass = SurveyPage(surveyId: int.parse(messageData["requestNumber"].toString())); + //Didn't handle task request yet... // case 6: // serviceClass = TaskRequestDetailsView( diff --git a/lib/models/system_notification_model.dart b/lib/models/system_notification_model.dart index f307b289..e2cf4b39 100644 --- a/lib/models/system_notification_model.dart +++ b/lib/models/system_notification_model.dart @@ -13,7 +13,7 @@ class SystemNotificationModel { String? modifiedOn; String? priorityName; String? statusName; - int ? transactionType; + int? transactionType; SystemNotificationModel( {this.userId, @@ -29,7 +29,7 @@ class SystemNotificationModel { this.createdOn, this.modifiedOn, this.priorityName, - this.transactionType, + this.transactionType, this.statusName}); SystemNotificationModel.fromJson(Map? json) { diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index e13d41eb..65b93daf 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -85,12 +85,6 @@ class _ServiceRequestDetailMainState extends State { Navigator.pop(context); }, actions: [ - IconButton( - icon: const Icon(Icons.feedback_rounded), - onPressed: () { - Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId, surveyId: 5))); - }, - ), Selector( selector: (_, myModel) => myModel.isLoading, // Selects only the userName builder: (_, isLoading, __) { diff --git a/lib/modules/cx_module/survey/survey_page.dart b/lib/modules/cx_module/survey/survey_page.dart index 1975eef3..e061050c 100644 --- a/lib/modules/cx_module/survey/survey_page.dart +++ b/lib/modules/cx_module/survey/survey_page.dart @@ -18,11 +18,13 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'survey_provider.dart'; class SurveyPage extends StatefulWidget { - int moduleId; - int requestId; + // int moduleId; + // int requestId; int surveyId; - SurveyPage({Key? key, required this.moduleId, required this.requestId, required this.surveyId}) : super(key: key); + SurveyPage({Key? key, + // required this.moduleId, required this.requestId, + required this.surveyId}) : super(key: key); @override _SurveyPageState createState() { diff --git a/lib/views/pages/user/notifications/notifications_page.dart b/lib/views/pages/user/notifications/notifications_page.dart index 47b64d00..8c551b45 100644 --- a/lib/views/pages/user/notifications/notifications_page.dart +++ b/lib/views/pages/user/notifications/notifications_page.dart @@ -37,12 +37,11 @@ class _NotificationsPageState extends State with TickerProvid stateCode: _notificationsProvider.stateCode, onRefresh: () async { _notificationsProvider.reset(); - await _notificationsProvider.getSystemNotifications( - user: _userProvider.user!,resetProvider: true + await _notificationsProvider.getSystemNotifications(user: _userProvider.user!, resetProvider: true - // host: _settingProvider.host, - // hospitalId: _userProvider.user.clientId, - ); + // host: _settingProvider.host, + // hospitalId: _userProvider.user.clientId, + ); }, child: NotificationsList( nextPage: _notificationsProvider.nextPage, diff --git a/lib/views/widgets/notifications/notification_item.dart b/lib/views/widgets/notifications/notification_item.dart index 89fef4b5..71135557 100644 --- a/lib/views/widgets/notifications/notification_item.dart +++ b/lib/views/widgets/notifications/notification_item.dart @@ -28,14 +28,14 @@ class NotificationItem extends StatelessWidget { label: notification.priorityName, textColor: AppColor.getRequestStatusTextColorByName(context, notification.priorityName!), backgroundColor: AppColor.getRequestStatusColorByName(context, notification.priorityName!), - ).toShimmer(isShow: isLoading,context: context), + ).toShimmer(isShow: isLoading, context: context), 8.width, if ((notification.statusName ?? "").isNotEmpty && notification.sourceName != "Asset Transfer") StatusLabel( label: notification.statusName ?? "", textColor: AppColor.getRequestStatusTextColorByName(context, notification.statusName ?? ""), backgroundColor: AppColor.getRequestStatusColorByName(context, notification.statusName ?? ""), - ).toShimmer(isShow: isLoading,context: context), + ).toShimmer(isShow: isLoading, context: context), ], ), 8.height, @@ -47,7 +47,7 @@ class NotificationItem extends StatelessWidget { style: AppTextStyles.heading6.copyWith( color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, ), - ).toShimmer(isShow: isLoading,context: context).expanded, + ).toShimmer(isShow: isLoading, context: context).expanded, 8.width, Text( notification.createdOn?.toServiceRequestCardFormat ?? "", @@ -55,7 +55,7 @@ class NotificationItem extends StatelessWidget { style: AppTextStyles.tinyFont.copyWith( color: context.isDark ? AppColor.neutral20 : AppColor.neutral50, ), - ).toShimmer(isShow: isLoading,context: context), + ).toShimmer(isShow: isLoading, context: context), ], ), Text( @@ -63,7 +63,7 @@ class NotificationItem extends StatelessWidget { style: AppTextStyles.bodyText2.copyWith( color: context.isDark ? AppColor.neutral10 : const Color(0xFF757575), ), - ).toShimmer(isShow: isLoading,context: context), + ).toShimmer(isShow: isLoading, context: context), ], ).onPress(() { onPressed(notification); From 7445902564ef898c2ab453a09645aac93e304e0a Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 18 Nov 2025 10:51:10 +0300 Subject: [PATCH 22/31] chat attachment added. --- lib/controllers/api_routes/urls.dart | 8 +- lib/helper/utils.dart | 69 ++- .../forms/asset_retired/asset_retired.dart | 8 +- .../service_request_detail_main_view.dart | 2 +- .../cx_module/chat/chat_api_client.dart | 125 ++++- lib/modules/cx_module/chat/chat_page.dart | 178 +++++-- lib/modules/cx_module/chat/chat_provider.dart | 166 ++++--- .../chat/helper/chat_audio_player.dart | 138 ++++++ .../chat/helper/chat_file_picker.dart | 436 ++++++++++++++++++ .../chat/helper/chat_file_viewer.dart | 137 ++++++ .../get_single_user_chat_list_model.dart | 4 + .../chat/view_all_attachment_page.dart | 56 +++ lib/views/widgets/dialogs/loading_dialog.dart | 36 ++ lib/views/widgets/sound/sound_player.dart | 4 +- 14 files changed, 1221 insertions(+), 146 deletions(-) create mode 100644 lib/modules/cx_module/chat/helper/chat_audio_player.dart create mode 100644 lib/modules/cx_module/chat/helper/chat_file_picker.dart create mode 100644 lib/modules/cx_module/chat/helper/chat_file_viewer.dart create mode 100644 lib/modules/cx_module/chat/view_all_attachment_page.dart create mode 100644 lib/views/widgets/dialogs/loading_dialog.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 563de659..cfead080 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,13 +4,13 @@ class URLs { static const String appReleaseBuildNumber = "28"; // static const host1 = "https://atomsm.hmg.com"; // production url - static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url - static String _baseUrl = "$_host/mobile"; + // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM diff --git a/lib/helper/utils.dart b/lib/helper/utils.dart index b56c7474..f4db3acd 100644 --- a/lib/helper/utils.dart +++ b/lib/helper/utils.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_api_availability/google_api_availability.dart'; + // import 'package:mohem_flutter_app/app_state/app_state.dart'; // import 'package:mohem_flutter_app/classes/colors.dart'; // import 'package:mohem_flutter_app/config/routes.dart'; @@ -23,6 +24,7 @@ import 'package:nfc_manager/platform_tags.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart'; +import 'package:test_sa/views/widgets/dialogs/loading_dialog.dart'; // ignore_for_file: avoid_annotating_with_dynamic @@ -49,19 +51,21 @@ class Utils { return null; } } -static String getOrdinal(int number) { - if (number >= 11 && number <= 13) return "${number}th"; - switch (number % 10) { - case 1: - return "${number}st"; - case 2: - return "${number}nd"; - case 3: - return "${number}rd"; - default: - return "${number}th"; + + static String getOrdinal(int number) { + if (number >= 11 && number <= 13) return "${number}th"; + switch (number % 10) { + case 1: + return "${number}st"; + case 2: + return "${number}nd"; + case 3: + return "${number}rd"; + default: + return "${number}th"; + } } -} + static int stringToHex(String colorCode) { try { return int.parse(colorCode.replaceAll("#", "0xff")); @@ -73,7 +77,8 @@ static String getOrdinal(int number) { static Future delay(int millis) async { return await Future.delayed(Duration(milliseconds: millis)); } - static bool isBeforeOrEqualCurrentTime(TimeOfDay t1, TimeOfDay t2) { + + static bool isBeforeOrEqualCurrentTime(TimeOfDay t1, TimeOfDay t2) { return t1.hour < t2.hour || (t1.hour == t2.hour && t1.minute <= t2.minute); } @@ -102,6 +107,21 @@ static String getOrdinal(int number) { _isLoadingVisible = false; } + static void showUploadingDialog(BuildContext context) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _isLoadingVisible = true; + + showDialog( + context: context, + barrierColor: Colors.black.withOpacity(0.5), + useRootNavigator: false, + builder: (BuildContext context) => const UploadingDialog(), + ).then((value) { + _isLoadingVisible = false; + }); + }); + } + static Future getStringFromPrefs(String key) async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getString(key) ?? ""; @@ -176,6 +196,7 @@ static String getOrdinal(int number) { ), ); } + // // static Widget getNoDataWidget(BuildContext context) { // return Column( @@ -421,15 +442,15 @@ static String getOrdinal(int number) { } return false; } - // - // static bool isDate(String input, String format) { - // try { - // DateTime d = DateFormat(format).parseStrict(input); - // //print(d); - // return true; - // } catch (e) { - // //print(e); - // return false; - // } - // } +// +// static bool isDate(String input, String format) { +// try { +// DateTime d = DateFormat(format).parseStrict(input); +// //print(d); +// return true; +// } catch (e) { +// //print(e); +// return false; +// } +// } } diff --git a/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart b/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart index 34416d06..e36e430a 100644 --- a/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart +++ b/lib/modules/cm_module/views/forms/asset_retired/asset_retired.dart @@ -55,8 +55,6 @@ class _AssetRetiredState extends State with TickerProviderStateMix @override Widget build(BuildContext context) { - - return Scaffold( key: _scaffoldKey, appBar: DefaultAppBar(title: context.translation.assetToBeRetired), @@ -125,9 +123,9 @@ class _AssetRetiredState extends State with TickerProviderStateMix onPressed: () async { requestDetailProvider.assetRetiredHelperModel?.activityAssetToBeRetiredAttachments = []; for (var item in _attachments) { - String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; - requestDetailProvider.assetRetiredHelperModel?.activityAssetToBeRetiredAttachments - ?.add(ActivityAssetToBeRetiredAttachments(id: item.id, name: fileName)); + String fileName = + ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + requestDetailProvider.assetRetiredHelperModel?.activityAssetToBeRetiredAttachments?.add(ActivityAssetToBeRetiredAttachments(id: item.id, name: fileName)); } int status = await requestDetailProvider.createActivityAssetToBeRetired(); if (status == 200) { diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 65b93daf..1f2008d8 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -176,7 +176,7 @@ class _ServiceRequestDetailMainState extends State { void getChatToken(int moduleId, String title) { ChatProvider cProvider = Provider.of(context, listen: false); - if (cProvider.chatLoginResponse != null) return; + if (cProvider.chatLoginResponse != null && cProvider.referenceID == widget.requestId) return; String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; String myEmployeeId = context.userProvider.user!.username!; diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 929f9946..37add788 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -5,6 +5,7 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/string_extensions.dart'; @@ -75,6 +76,16 @@ class ChatApiClient { } } + Future viewAllDocuments(int moduleId, int referenceId) async { + Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token); + + if (response.statusCode == 200) { + return ChatParticipantModel.fromJson(jsonDecode(response.body)); + } else { + return null; + } + } + Future> loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async { Response response = await ApiClient().postJsonForResponse( "${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()}, @@ -203,26 +214,25 @@ class ChatApiClient { // } // Upload Chat Media -// Future uploadMedia(String userId, File file, String fileSource) async { -// if (kDebugMode) { -// print("${ApiConsts.chatMediaImageUploadUrl}upload"); -// print(AppState().chatDetails!.response!.token); -// } -// -// dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); -// request.fields.addAll({'userId': userId, 'fileSource': fileSource}); -// request.files.add(await MultipartFile.fromPath('files', file.path)); -// request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); -// StreamedResponse response = await request.send(); -// String data = await response.stream.bytesToString(); -// if (!kReleaseMode) { -// logger.i("res: " + data); -// } -// return jsonDecode(data); -// } + Future uploadMedia(String userId, File file, String fileSource, {Map? jsonData}) async { + dynamic request = MultipartRequest('POST', Uri.parse('${URLs.chatHubUrlApi}/attachments/upload')); + request.fields.addAll({'userId': userId, 'fileSource': fileSource}); + if (jsonData != null) { + request.fields.addAll(jsonData); + } -// Download File For Chat -// Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { + request.files.add(await MultipartFile.fromPath('file', file.path)); + request.headers.addAll({'Authorization': 'Bearer ${chatLoginResponse!.token}'}); + StreamedResponse response = await request.send(); + String data = await response.stream.bytesToString(); + if (!kReleaseMode) { + print("uploadMedia: $data"); + } + return jsonDecode(data); + } + +// // Download File For Chat +// Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource,required String url}) async { // Response response = await ApiClient().postJsonForResponse( // "${ApiConsts.chatMediaImageUploadUrl}download", // {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, @@ -232,6 +242,83 @@ class ChatApiClient { // return data; // } +// Download File For Chat + Future downloadURL(String url, {required String fileName, required String fileTypeDescription, required int fileSource}) async { + Response response = await ApiClient().postJsonForResponse( + url, + {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, + token: chatLoginResponse!.token, + ); + Uint8List data = Uint8List.fromList(response.bodyBytes); + return data; + } + + /// Downloads a file from a secure URL that uses a 302 redirect. + /// + /// [url]: The initial URL that requires the authorization token. + /// [token]: The Bearer token for authorization. + /// [saveFileName]: The name to give the downloaded file (e.g., 'my-document.pdf'). + Future downloadFileWithHttp(String url, {required String fileName, required String fileTypeDescription, required int fileSource}) async { + final client = http.Client(); + File? file; + try { + final request = http.Request('GET', Uri.parse(url)); + request.headers['Authorization'] = 'Bearer ${chatLoginResponse!.token}'; + + // This is the most important part: prevent automatic redirection. + request.followRedirects = false; + + print("Making initial request to: $url"); + final streamedResponse = await client.send(request); + + // --- Step 2: Check the response and handle the redirect --- + + // Check for a 302 redirect status. + if (streamedResponse.statusCode == 302) { + // Get the new URL from the 'Location' header. + final redirectUrl = streamedResponse.headers['location']; + + if (redirectUrl == null) { + throw Exception('302 Redirect did not contain a Location header.'); + } + + final fileResponse = await http.get(Uri.parse(redirectUrl), headers: {'Authorization': 'Bearer ${chatLoginResponse!.token}'}); + + if (fileResponse.statusCode == 200) { + // Get a safe directory to save the file. + final dir = await getTemporaryDirectory(); + file = File('${dir.path}/$fileName'); + + // Write the file to disk. + await file.writeAsBytes(fileResponse.bodyBytes); + print("File downloaded successfully and saved to: ${file.path}"); + } else { + // The download from the final URL failed. + throw Exception('Failed to download from redirect URL. Status: ${fileResponse.statusCode}'); + } + } + // Handle cases where the server might just send the file directly. + else if (streamedResponse.statusCode == 200) { + print("Server sent file directly without redirect."); + final dir = await getTemporaryDirectory(); + file = File('${dir.path}/$fileName'); + await file.writeAsBytes(await streamedResponse.stream.toBytes()); + print("File downloaded successfully and saved to: ${file.path}"); + } + // Handle other error statuses. + else { + throw Exception('Failed to initiate download. Status: ${streamedResponse.statusCode}'); + } + } catch (e) { + print("An error occurred during download: $e"); + } finally { + // Always close the client to free up resources. + client.close(); + } + + return file; + } + // //Get Chat Users & Favorite Images // Future> getUsersImages({required List encryptedEmails}) async { // List imagesData = []; diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index c1196027..4bab968c 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -1,6 +1,9 @@ import 'dart:convert'; +import 'dart:io'; import 'package:audio_waveforms/audio_waveforms.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -8,15 +11,21 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart'; import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; +import 'package:test_sa/modules/cx_module/chat/view_all_attachment_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/sound/sound_player.dart'; +import 'helper/chat_audio_player.dart'; +import 'helper/chat_file_picker.dart'; +import 'helper/chat_file_viewer.dart'; import 'model/get_single_user_chat_list_model.dart'; import 'model/user_chat_history_model.dart'; @@ -74,6 +83,7 @@ class _ChatPageState extends State { @override void dispose() { + chatHubConnection.stop(); playerController.dispose(); recorderController.dispose(); super.dispose(); @@ -113,14 +123,37 @@ class _ChatPageState extends State { Container( color: AppColor.neutral50, constraints: const BoxConstraints(maxHeight: 56), - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 8), + alignment: Alignment.center, child: Row( children: [ - Text( - chatProvider.recipient?.userName ?? "", - overflow: TextOverflow.ellipsis, - maxLines: 2, - style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + chatProvider.recipient?.userName ?? "", + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), + ), + AnimatedSize( + duration: const Duration(milliseconds: 250), + child: SizedBox( + height: chatProvider.isTyping ? null : 0, + child: Text( + "Typing...", + maxLines: 1, + style: AppTextStyles.overline.copyWith(color: AppColor.white10), + ), + )), + // if (chatProvider.isTyping) + // Text( + // "Typing...", + // maxLines: 1, + // style: AppTextStyles.tinyFont2.copyWith(color: AppColor.white10), + // ), + ], ).expanded, 4.width, Text( @@ -130,7 +163,9 @@ class _ChatPageState extends State { decoration: TextDecoration.underline, decorationColor: AppColor.white10, ), - ), + ).onPress(() { + Navigator.push(context, CupertinoPageRoute(builder: (context) => ViewAllAttachmentPage(moduleId: 1, requestId: widget.requestId))); + }), ], ), ), @@ -196,8 +231,14 @@ class _ChatPageState extends State { maxLines: 3, textInputAction: TextInputAction.none, keyboardType: TextInputType.multiline, + onTap: () { + chatHubConnection.invoke("SendTypingAsync", args: [receiver]); + }, + onTapOutside: (PointerDownEvent event) { + chatHubConnection.invoke("SendStopTypingAsync", args: [receiver]); + }, onChanged: (text) { - chatHubConnection.invoke("SendTypingAsync", args: [context.userProvider.user!.username!]); + chatHubConnection.invoke("SendTypingAsync", args: [receiver]); }, decoration: InputDecoration( enabledBorder: InputBorder.none, @@ -214,7 +255,23 @@ class _ChatPageState extends State { ), ).expanded, IconButton( - onPressed: () {}, + onPressed: () async { + FocusScope.of(context).unfocus(); + File? file = (await showModalBottomSheet( + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(20), + ), + ), + clipBehavior: Clip.antiAliasWithSaveLayer, + builder: (BuildContext context) => ChatFilePicker())) as File?; + if (file != null) { + Utils.showUploadingDialog(context); + await chatProvider.uploadAttachments(context.userProvider.user!.username!, file, "1"); + Utils.hideLoading(context); + } + }, style: const ButtonStyle( tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded ), @@ -458,24 +515,41 @@ class _ChatPageState extends State { splashColor: Colors.transparent, highlightColor: Colors.transparent, hoverColor: Colors.transparent, - onPressed: () { - chatProvider.invokeSendMessage({ - "Contant": textEditingController.text, - // "ContantNo": "0cc8b126-6180-4f91-a64d-2f62443b3f3f", - // "CreatedDate": "2025-11-09T18:58:12.502Z", - "CurrentEmployeeNumber": context.userProvider.user!.username!, - "ChatEventId": 1, - "ConversationId": chatProvider.chatParticipantModel!.id!.toString(), - "ModuleCode": widget.moduleId.toString(), - "ReferenceNumber": widget.requestId.toString(), - "UserChatHistoryLineRequestList": [ - {"TargetEmployeeNumber": receiver, "TargetUserStatus": 1, "IsSeen": false, "IsDelivered": true, "SeenOn": null, "DeliveredOn": null} - ] - }).then((success) { - if (success) { - textEditingController.clear(); + onPressed: () async { + if (chatState == ChatState.voiceRecordingCompleted) { + Utils.showUploadingDialog(context); + try { + await chatProvider.uploadAttachments(context.userProvider.user!.username!, File(recordedFilePath!), "1"); + Utils.hideLoading(context); + + await playerController.stopPlayer(); + recorderController.reset(); + recordedFilePath = null; + chatState = ChatState.idle; + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); } - }); + } else { + if (textEditingController.text.isEmpty) return; + chatProvider.invokeSendMessage({ + "Contant": textEditingController.text, + // "ContantNo": "0cc8b126-6180-4f91-a64d-2f62443b3f3f", + // "CreatedDate": "2025-11-09T18:58:12.502Z", + "CurrentEmployeeNumber": context.userProvider.user!.username!, + "ChatEventId": 1, + "ConversationId": chatProvider.chatParticipantModel!.id!.toString(), + "ModuleCode": widget.moduleId.toString(), + "ReferenceNumber": widget.requestId.toString(), + "UserChatHistoryLineRequestList": [ + {"TargetEmployeeNumber": receiver, "TargetUserStatus": 1, "IsSeen": false, "IsDelivered": true, "SeenOn": null, "DeliveredOn": null} + ] + }).then((success) { + if (success) { + textEditingController.clear(); + } + }); + } }, style: const ButtonStyle( tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded @@ -555,10 +629,51 @@ class _ChatPageState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text( - chatResponse?.contant ?? msg, - style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), - ).toShimmer(context: context, isShow: loading), + if (chatResponse?.downloadUrl != null) ...[ + // if (chatResponse!.fileTypeResponse!.fileKind.toString().toLowerCase() == "audio") + // // ASoundPlayer(audio: chatResponse.downloadUrl!) + // + // ChatAudioPlayer(chatResponse!.fileTypeResponse!, chatResponse.downloadUrl!) + // // if ( + // // + // // chatResponse!.fileTypeResponse!.fileKind.toString().toLowerCase() == "image" + // // + // // ) + // + // else + ChatFileViewer(chatResponse!.downloadUrl!, chatResponse.fileTypeResponse!), + + // Container( + // width: 250, + // height: 250, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(12), + // border: Border.all(color: Colors.grey.withOpacity(.5), width: 1), + // image: DecorationImage( + // image: NetworkImage(chatResponse.downloadUrl!, headers: {'Authorization': "Bearer ${Provider.of(context, listen: false).chatLoginResponse!.token!}"}), + // ), + // ), + // // child: CachedNetworkImage( + // // imageUrl: chatResponse.downloadUrl! ?? "", + // // // fit: boxFit ?? BoxFit.cover, + // // // alignment: Alignment.center, + // // // width: width, + // // // height: height, + // // httpHeaders: {'Authorization': "Bearer ${Provider.of(context, listen: false).chatLoginResponse!.token!}"}, + // // placeholder: (context, url) => const Center(child: CircularProgressIndicator()), + // // // errorWidget: (context, url, error) => Icon(showDefaultIcon ? Icons.image_outlined : Icons.broken_image_rounded), + // // ), + // + // // Image.network( + // // chatResponse.downloadUrl!, + // // headers: {'Authorization': "Bearer ${Provider.of(context, listen: false).chatLoginResponse!.token!}"}, + // // ), + // ) + ] else + Text( + chatResponse?.contant ?? msg, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), + ).toShimmer(context: context, isShow: loading), if (loading) 4.height, Text( chatResponse?.createdDate?.toString().chatMsgTime ?? "2:00 PM", @@ -628,6 +743,9 @@ class _ChatPageState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ + if (chatResponse?.downloadUrl != null) ...[ + if (chatResponse!.fileTypeResponse!.fileKind.toString().toLowerCase() == "audio") ChatAudioPlayer(chatResponse!.fileTypeResponse!, chatResponse.downloadUrl!) + ], Text( contentMsg, style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 84384087..5ad5d1d5 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -106,6 +106,8 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // // bool disbaleChatForThisUser = false; + bool isTyping = false; + bool chatLoginTokenLoading = false; ChatLoginResponse? chatLoginResponse; @@ -125,6 +127,10 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { Participants? sender; Participants? recipient; + late String receiverID; + late int moduleID; + int? referenceID; + void reset() { chatLoginTokenLoading = false; chatParticipantLoading = false; @@ -153,6 +159,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { Future getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async { reset(); + receiverID = assigneeEmployeeNumber; chatLoginTokenLoading = true; notifyListeners(); try { @@ -186,9 +193,17 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } catch (e) {} // } + Future viewAllDocuments(int moduleId, int requestId) async { + try { + await ChatApiClient().viewAllDocuments(moduleId, requestId); + } catch (ex) {} + } + Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { userChatHistoryLoading = true; notifyListeners(); + moduleID = moduleId; + referenceID = requestId; await buildHubConnection(chatParticipantModel!.id!.toString()); userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); chatResponseList = userChatHistory ?? []; @@ -239,22 +254,6 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // return returnStatus; // } - void sendMsgSignalR() { - var abc = { - "Contant": "Follow-up: Test results look good.", - "ContantNo": "0cc8b126-6180-4f91-a64d-2f62443b3f3f", - "CreatedDate": "2025-11-09T18:58:12.502Z", - "CurrentEmployeeNumber": "EMP123456", - "ChatEventId": 1, - "ConversationId": "15521", - "ModuleCode": "CRM", - "ReferenceNumber": "CASE-55231", - "UserChatHistoryLineRequestList": [ - {"TargetEmployeeNumber": "EMP654321", "TargetUserStatus": 1, "IsSeen": false, "IsDelivered": true, "SeenOn": null, "DeliveredOn": null} - ] - }; - } - // List? uGroups = [], searchGroups = []; // Future getUserAutoLoginToken() async { @@ -287,6 +286,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { chatHubConnection.on("OnMessageReceivedAsync", onMsgReceived); chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); chatHubConnection.on("OnTypingAsync", OnTypingAsync); + chatHubConnection.on("OnStopTypingAsync", OnStopTypingAsync); //group On message @@ -389,34 +389,28 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // chatCID = uuid.v4(); // } - // void markRead(List data, int receiverID) { - // for (SingleUserChatModel element in data!) { - // if (AppState().chatDetails!.response!.id! == element.targetUserId) { - // if (element.isSeen != null) { - // if (!element.isSeen!) { - // element.isSeen = true; - // dynamic data = [ - // { - // "userChatHistoryId": element.userChatHistoryId, - // "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, - // "isDelivered": true, - // "isSeen": true, - // } - // ]; - // updateUserChatHistoryStatusAsync(data); - // notifyListeners(); - // } - // } - // for (ChatUser element in searchedChats!) { - // if (element.id == receiverID) { - // element.unreadMessageCount = 0; - // chatUConvCounter = 0; - // } - // } - // } - // } - // notifyListeners(); - // } + void markRead(List data, String receiverID) { + for (SingleUserChatModel element in data) { + // if (AppState().chatDetails!.response!.id! == element.targetUserId) { + if (element.isSeen != null) { + if (!element.isSeen!) { + element.isSeen = true; + dynamic data = [ + { + "userChatHistoryId": element.userChatHistoryId, + "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, + "isDelivered": true, + "isSeen": true, + } + ]; + updateUserChatHistoryStatusAsync(data); + notifyListeners(); + } + // } + } + } + // notifyListeners(); + } void updateUserChatHistoryStatusAsync(List data) { try { @@ -434,25 +428,51 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { } } - List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); + // List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); + List getSingleUserChatModel(String str) { + final dynamic decodedJson = json.decode(str); + + // Check if the decoded JSON is already a List + if (decodedJson is List) { + return List.from(decodedJson.map((x) => SingleUserChatModel.fromJson(x))); + } + // If it's a Map (a single object), wrap it in a list + else if (decodedJson is Map) { + return [SingleUserChatModel.fromJson(decodedJson)]; + } + // Handle unexpected types + else { + throw const FormatException('Expected a JSON object or a list of JSON objects.'); + } + } // List getGroupChatHistoryAsync(String str) => // List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); // - // Future uploadAttachments(String userId, File file, String fileSource) async { - // dynamic result; - // try { - // Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); - // if (response != null) { - // result = response; - // } else { - // result = []; - // } - // } catch (e) { - // throw e; - // } - // return result; - // } + Future uploadAttachments(String userId, File file, String fileSource) async { + dynamic result; + try { + Map jsonData = { + "IsContextual": true.toString(), + "ModuleCode": moduleID.toString(), + "ReferenceId": referenceID.toString(), + "ReferenceType": "ticket", + "ConversationId": chatParticipantModel!.id.toString(), + "TargetUserId": receiverID, + "SendMessage": true.toString(), + }; + + Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource, jsonData: jsonData); + if (response != null) { + result = response; + } else { + result = []; + } + } catch (e) { + throw e; + } + return result; + } // void updateUserChatStatus(List? args) { // dynamic items = args!.toList(); @@ -555,8 +575,27 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // notifyListeners(); // } + Timer? timer; + Future OnTypingAsync(List? parameters) async { - print("OnTypingAsync:$parameters"); + // String empId = parameters!.first as String; + isTyping = true; + notifyListeners(); + if (timer?.isActive ?? false) { + timer!.cancel(); + } + timer = Timer(const Duration(milliseconds: 2500), () { + isTyping = false; + notifyListeners(); + }); + } + + Future OnStopTypingAsync(List? parameters) async { + if (timer?.isActive ?? false) { + timer!.cancel(); + } + isTyping = false; + notifyListeners(); } // Future OnSubmitChatAsync(List? parameters) async { @@ -632,11 +671,13 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // ); // } // } - setMsgTune(); + // setMsgTune(); // userChatHistory = userChatHistory! + data; // chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); userChatHistory?.insert(0, data.first); notifyListeners(); + + // markRead(data, data.first.targetUserId!); // if (isChatScreenActive && data.first.currentUserId == receiverID) { // // } else { @@ -760,6 +801,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } void OnSubmitChatAsync(List? parameters) { + print("OnSubmitChatAsync:$parameters"); List data = []; for (dynamic msg in parameters!) { data = getSingleUserChatModel(jsonEncode(msg)); @@ -1215,7 +1257,7 @@ String getFileTypeDescription(String value) { // } // } // } - +// // void sendChatMessage( // BuildContext context, { // required int targetUserId, diff --git a/lib/modules/cx_module/chat/helper/chat_audio_player.dart b/lib/modules/cx_module/chat/helper/chat_audio_player.dart new file mode 100644 index 00000000..f32fcc06 --- /dev/null +++ b/lib/modules/cx_module/chat/helper/chat_audio_player.dart @@ -0,0 +1,138 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:audio_waveforms/audio_waveforms.dart'; +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cx_module/chat/api_client.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart'; +import 'package:test_sa/modules/cx_module/chat/model/get_single_user_chat_list_model.dart'; + +import '../../../../new_views/app_style/app_color.dart'; + +class ChatAudioPlayer extends StatefulWidget { + String downloadURl; + FileTypeResponse file; + bool isLocalFile; + + ChatAudioPlayer(this.file, this.downloadURl, {Key? key, this.isLocalFile = false}) : super(key: key); + + @override + _ChatAudioPlayerState createState() { + return _ChatAudioPlayerState(); + } +} + +class _ChatAudioPlayerState extends State { + bool downloading = false; + + PlayerController playerController = PlayerController(); + + @override + void initState() { + super.initState(); + checkFileInLocalStorage(); + } + + File? audioFile; + List waveformData = []; + + void checkFileInLocalStorage() async { + Directory tempDir = await getTemporaryDirectory(); + String tempPath = '${tempDir.path}/${widget.file.fileName}'; + File tempFile = File(tempPath); + bool exists = await tempFile.exists(); + if (exists) { + audioFile = tempFile; + playerController = PlayerController(); + await playerController.preparePlayer(path: tempPath); + waveformData = await playerController.extractWaveformData(path: tempPath); + } else { + downloadFile(); + } + } + + void downloadFile() async { + downloading = true; + setState(() {}); + try { + // Uint8List list = await ChatApiClient().downloadFileWithHttp(widget.downloadURl, fileName: widget.file.fileName, fileTypeDescription: widget.file.fileTypeDescription, fileSource: widget.file.fileTypeId!); + // audioFile = File.fromRawPath(list); + + audioFile = + await ChatApiClient().downloadFileWithHttp(widget.downloadURl, fileName: widget.file.fileName, fileTypeDescription: widget.file.fileTypeDescription, fileSource: widget.file.fileTypeId!); + + playerController = PlayerController(); + await playerController.preparePlayer(path: audioFile!.path); + waveformData = await playerController.extractWaveformData(path: audioFile!.path); + } catch (ex) { + print(ex); + audioFile = null; + } + downloading = false; + setState(() {}); + } + + @override + void dispose() { + playerController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 56, + child: Row( + children: [ + if (downloading) + const SizedBox( + height: 24, + width: 24, + child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2), + ) + else if (playerController.playerState == PlayerState.playing) + IconButton( + onPressed: () async { + await playerController.pausePlayer(); + await playerController.stopPlayer(); + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.stop_circle_outlined, size: 20), + constraints: const BoxConstraints(), + ) + else + IconButton( + onPressed: () async { + await playerController.startPlayer(); + setState(() {}); + }, + style: const ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded + ), + icon: const Icon(Icons.play_circle_fill_rounded, size: 20), + constraints: const BoxConstraints(), + ), + AudioFileWaveforms( + playerController: playerController, + waveformData: waveformData, + enableSeekGesture: false, + continuousWaveform: false, + waveformType: WaveformType.long, + playerWaveStyle: const PlayerWaveStyle( + fixedWaveColor: AppColor.neutral50, + liveWaveColor: AppColor.primary10, + showSeekLine: true, + ), + size: Size(MediaQuery.of(context).size.width, 56.0), + ).expanded, + ], + ), + ); + } +} diff --git a/lib/modules/cx_module/chat/helper/chat_file_picker.dart b/lib/modules/cx_module/chat/helper/chat_file_picker.dart new file mode 100644 index 00000000..63e19d71 --- /dev/null +++ b/lib/modules/cx_module/chat/helper/chat_file_picker.dart @@ -0,0 +1,436 @@ +import 'dart:io'; + +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:image_cropper/image_cropper.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; + +class ChatFilePicker extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Attach File".heading4(context), + 12.height, + GridView( + padding: const EdgeInsets.all(0), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), + children: [ + gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() async { + await fromMediaPicker(context, ImageSource.camera); + }), + gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() async { + await fromMediaPicker(context, ImageSource.gallery); + }), + gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async { + await fromFilePicker(context); + }), + ], + ), + 12.height, + ], + ).paddingAll(21); + } + + fromMediaPicker(BuildContext context, ImageSource imageSource) async { + XFile? pickedFile = await ImagePicker().pickImage(source: imageSource, imageQuality: 70, maxWidth: 800, maxHeight: 800); + if (pickedFile != null) { + CroppedFile? croppedFile = await ImageCropper().cropImage( + sourcePath: pickedFile.path, + aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), + uiSettings: [ + AndroidUiSettings( + toolbarTitle: 'ATOMS', + toolbarColor: Colors.white, + toolbarWidgetColor: context.settingProvider.theme == "dark" ? AppColor.neutral10 : AppColor.neutral50, + initAspectRatio: CropAspectRatioPreset.square, + lockAspectRatio: false, + ), + IOSUiSettings(title: 'ATOMS'), + ], + ); + if (croppedFile != null) { + Navigator.pop(context, File(croppedFile.path)); + return; + } + } + Navigator.pop(context); + } + + fromFilePicker(BuildContext context) async { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], + ); + if ((result?.paths ?? []).isNotEmpty) { + Navigator.pop(context, File(result!.paths.first!)); + } else { + Navigator.pop(context); + } + } + + Widget gridItem(IconData iconData, String title) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xffF1F1F1), width: 1), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon(iconData, color: const Color(0xff7D859A), size: 36), + Text( + title, + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), + ), + ], + ), + ); + } + +// static Future selectFile(BuildContext context) async { +// ImageSource source = (await showModalBottomSheet( +// context: context, +// shape: const RoundedRectangleBorder( +// borderRadius: BorderRadius.vertical( +// top: Radius.circular(20), +// ), +// ), +// clipBehavior: Clip.antiAliasWithSaveLayer, +// builder: (BuildContext context) => ChatFilePicker())) as ImageSource; +// +// final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); +// } +} + +// class AttachmentPicker extends StatefulWidget { +// final String label; +// final bool error; +// final List attachment; +// +// final bool enabled, onlyImages; +// double? buttonHeight; +// Widget? buttonIcon; +// Color? buttonColor; +// final Function(List)? onChange; +// final bool showAsGrid; +// +// AttachmentPicker( +// {Key? key, +// this.attachment = const [], +// required this.label, +// this.error = false, +// this.buttonHeight, +// this.buttonIcon, +// this.enabled = true, +// this.onlyImages = false, +// this.onChange, +// this.showAsGrid = false, +// this.buttonColor}) +// : super(key: key); +// +// @override +// State createState() => _AttachmentPickerState(); +// } +// +// class _AttachmentPickerState extends State { +// @override +// Widget build(BuildContext context) { +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// AppDashedButton( +// title: widget.label, +// height: widget.buttonHeight, +// buttonColor: widget.buttonColor, +// icon: widget.buttonIcon, +// onPressed: (widget.enabled == false) +// ? () {} +// : widget.showAsGrid +// ? showFileSourceSheet +// : onFilePicker), +// 16.height, +// if (widget.attachment.isNotEmpty) +// Wrap( +// spacing: 8.toScreenWidth, +// children: List.generate( +// widget.attachment.length, +// (index) { +// File image = File(widget.attachment[index].name!); +// return MultiFilesPickerItem( +// file: image, +// enabled: widget.enabled, +// onRemoveTap: (image) { +// if (!widget.enabled) { +// return; +// } +// widget.attachment.removeAt(index); +// if (widget.onChange != null) { +// widget.onChange!(widget.attachment); +// } +// setState(() {}); +// }, +// ); +// }, +// ), +// ), +// ], +// ); +// } +// +// fromFilePicker() async { +// FilePickerResult? result = await FilePicker.platform.pickFiles( +// type: FileType.custom, +// allowMultiple: true, +// allowedExtensions: widget.onlyImages ? ['jpg', 'jpeg', 'png'] : ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], +// ); +// if (result != null) { +// for (var path in result.paths) { +// widget.attachment.add(GenericAttachmentModel(id: 0, name: File(path!).path)); +// } +// if (widget.onChange != null) { +// widget.onChange!(widget.attachment); +// } +// setState(() {}); +// } +// } +// +// void showFileSourceSheet() async { +// // if (widget.attachment.length >= 5) { +// // Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); +// // return; +// // } +// +// ImageSource source = (await showModalBottomSheet( +// context: context, +// shape: const RoundedRectangleBorder( +// borderRadius: BorderRadius.vertical( +// top: Radius.circular(20), +// ), +// ), +// clipBehavior: Clip.antiAliasWithSaveLayer, +// builder: (BuildContext context) => Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// "Attach File".heading4(context), +// 12.height, +// GridView( +// padding: const EdgeInsets.all(0), +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), +// children: [ +// gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)), +// gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)), +// gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async { +// await fromFilePicker(); +// Navigator.pop(context); +// }), +// ], +// ), +// 12.height, +// ], +// ).paddingAll(21), +// )) as ImageSource; +// +// final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); +// +// if (pickedFile != null) { +// File fileImage = File(pickedFile.path); +// widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path)); +// if (widget.onChange != null) { +// widget.onChange!(widget.attachment); +// } +// setState(() {}); +// } +// } +// +// Widget gridItem(IconData iconData, String title) { +// return Container( +// padding: const EdgeInsets.all(12), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(12), +// border: Border.all(color: const Color(0xffF1F1F1), width: 1), +// ), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// Icon(iconData, color: const Color(0xff7D859A), size: 36), +// Text( +// title, +// style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), +// ), +// ], +// ), +// ); +// } +// +// onFilePicker() async { +// //TODO removed on request by Backend as they don't have anyissue with large number of files +// // if (widget.attachment.length >= 5) { +// // Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); +// // return; +// // } +// ImageSource? source = await showModalBottomSheet( +// context: context, +// builder: (BuildContext context) { +// Widget listCard({required String icon, required String label, required VoidCallback onTap}) { +// return Container( +// padding: const EdgeInsets.all(12), +// decoration: BoxDecoration( +// color: AppColor.background(context), +// // color: Colors.white, +// borderRadius: BorderRadius.circular(12), +// border: Border.all(color: const Color(0xffF1F1F1), width: 1), +// ), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// icon.toSvgAsset(color: AppColor.iconColor(context), width: 36, height: 36), +// // Icon(iconData, color: const Color(0xff7D859A), size: 36), +// Text( +// label, +// style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), +// ), +// ], +// ), +// ).onPress(onTap); +// } +// +// return SafeArea( +// top: false, +// child: Container( +// width: double.infinity, +// color: AppColor.background(context), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// "Attach File".heading4(context), +// 12.height, +// GridView( +// padding: const EdgeInsets.all(0), +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), +// children: [ +// listCard( +// icon: 'camera_icon', +// label: '${context.translation.open}\n${context.translation.camera}', +// onTap: () { +// Navigator.of(context).pop(ImageSource.camera); +// }, +// ), +// listCard( +// icon: 'gallery_icon', +// label: '${context.translation.open}\n${context.translation.gallery}', +// onTap: () { +// Navigator.of(context).pop(ImageSource.gallery); +// }, +// ), +// listCard( +// icon: 'file_icon', +// label: '${context.translation.open}\n${context.translation.files}', +// onTap: () async { +// await fromFilePicker(); +// Navigator.pop(context); +// }, +// ), +// ], +// ), +// // Container( +// // padding: const EdgeInsets.all(16.0), +// // child: Row( +// // mainAxisAlignment: MainAxisAlignment.spaceBetween, +// // children: [ +// // listCard( +// // icon: 'camera_icon', +// // label: '${context.translation.open}\n${context.translation.camera}', +// // onTap: () { +// // Navigator.of(context).pop(ImageSource.camera); +// // }, +// // ), +// // listCard( +// // icon: 'gallery_icon', +// // label: '${context.translation.open}\n${context.translation.gallery}', +// // onTap: () { +// // Navigator.of(context).pop(ImageSource.gallery); +// // }, +// // ), +// // listCard( +// // icon: 'file_icon', +// // label: '${context.translation.open}\n${context.translation.files}', +// // onTap: () async { +// // await fromFilePicker(); +// // Navigator.pop(context); +// // }, +// // ), +// // ], +// // ), +// // ), +// ], +// ).paddingAll(16), +// ), +// ); +// }, +// ); +// // ImageSource source = await showDialog( +// // context: context, +// // builder: (dialogContext) => CupertinoAlertDialog( +// // actions: [ +// // TextButton( +// // child: Text(context.translation.pickFromCamera), +// // onPressed: () { +// // Navigator.of(dialogContext).pop(ImageSource.camera); +// // }, +// // ), +// // TextButton( +// // child: Text(context.translation.pickFromGallery), +// // onPressed: () { +// // Navigator.of(dialogContext).pop(ImageSource.gallery); +// // }, +// // ), +// // TextButton( +// // child: Text(context.translation.pickFromFiles), +// // onPressed: () async { +// // await fromFilePicker(); +// // Navigator.pop(context); +// // }, +// // ), +// // ], +// // ), +// // ); +// if (source == null) return; +// +// final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); +// +// if (pickedFile != null) { +// File fileImage = File(pickedFile.path); +// widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path)); +// if (widget.onChange != null) { +// widget.onChange!(widget.attachment); +// } +// setState(() {}); +// } +// +// setState(() {}); +// } +// } diff --git a/lib/modules/cx_module/chat/helper/chat_file_viewer.dart b/lib/modules/cx_module/chat/helper/chat_file_viewer.dart new file mode 100644 index 00000000..fbd53eec --- /dev/null +++ b/lib/modules/cx_module/chat/helper/chat_file_viewer.dart @@ -0,0 +1,137 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; +import 'package:test_sa/modules/cx_module/chat/model/get_single_user_chat_list_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/app_style/app_text_style.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; +import 'package:test_sa/views/widgets/sound/sound_player.dart'; + +class ChatFileViewer extends StatelessWidget { + String downloadUrl; + FileTypeResponse fileTypeResponse; + + ChatFileViewer(this.downloadUrl, this.fileTypeResponse, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: checkFileInLocalStorage(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState != ConnectionState.waiting && snapshot.hasData) {} + + if (fileTypeResponse!.fileKind.toString().toLowerCase() == "audio") { + if (snapshot.connectionState == ConnectionState.waiting) { + return Container( + width: 48, + height: 48, + decoration: ShapeDecoration( + color: AppColor.background(context), + shape: RoundedRectangleBorder( + side: BorderSide(width: 1, color: (context.isDark ? AppColor.neutral20 : AppColor.neutral30)), + borderRadius: BorderRadius.circular(32), + ), + ), + child: const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2).center, + ); + } + if (snapshot.data == null) { + return Text("Failed to load", style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60)); + } + return ASoundPlayer(audio: snapshot.data!.path); + } + return Container( + width: 180, + height: 180, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.withOpacity(.5), width: 1), + image: snapshot.hasData ? DecorationImage(fit: BoxFit.contain, image: getImage(snapshot.data!)) : null, + ), + child: snapshot.connectionState == ConnectionState.waiting + ? const SizedBox( + height: 24, + width: 24, + child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2), + ).center + : snapshot.hasData + ? getFile(context, snapshot.data!) + : const Icon(Icons.broken_image_rounded), + ); + }); + } + + Widget getFile(BuildContext context, File file) { + bool isImage = file.path.split(".").last.toLowerCase() == "png" || file.path.split(".").last.toLowerCase() == "jpg" || file.path.split(".").last.toLowerCase() == "jpeg"; + bool isPdf = file.path.split(".").last.toLowerCase() == "pdf"; + bool isExcel = file.path.split(".").last.toLowerCase() == "xlsx"; + + return MaterialButton( + padding: EdgeInsets.zero, + onPressed: () async { + if (isImage) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + appBar: const DefaultAppBar(), + body: SafeArea( + child: InteractiveViewer(child: Image.file(file)).center, + ), + ), + ), + ); + } else { + OpenFile.open(file.path); + } + // else { + // // if (!await launchUrl(Uri.parse(URLs.getFileUrl(file.path)!), mode: LaunchMode.externalApplication)) { + // // Fluttertoast.showToast(msg: "UnExpected Error with file."); + // // throw Exception('Could not launch'); + // // } + // } + }, + ); + } + + ImageProvider getImage(File file) { + bool isImage = file.path.split(".").last.toLowerCase() == "png" || file.path.split(".").last.toLowerCase() == "jpg" || file.path.split(".").last.toLowerCase() == "jpeg"; + bool isPdf = file.path.split(".").last.toLowerCase() == "pdf"; + bool isExcel = file.path.split(".").last.toLowerCase() == "xlsx"; + + if (isImage) { + return FileImage(file); + } + return AssetImage("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png"); + } + + Future checkFileInLocalStorage() async { + Directory tempDir = await getTemporaryDirectory(); + String tempPath = '${tempDir.path}/${fileTypeResponse.fileName}'; + File tempFile = File(tempPath); + bool exists = await tempFile.exists(); + if (exists) { + return tempFile; + } else { + return downloadFile(); + } + } + + Future downloadFile() async { + try { + return await ChatApiClient() + .downloadFileWithHttp(downloadUrl, fileName: fileTypeResponse.fileName, fileTypeDescription: fileTypeResponse.fileTypeDescription, fileSource: fileTypeResponse.fileTypeId!); + } catch (ex) { + print("downloadFile:$ex"); + return null; + } + } +} diff --git a/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart b/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart index 06e3da34..7d87aca2 100644 --- a/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart +++ b/lib/modules/cx_module/chat/model/get_single_user_chat_list_model.dart @@ -29,6 +29,7 @@ class SingleUserChatModel { this.createdDate, this.chatSource, this.conversationId, + this.downloadUrl, this.fileTypeResponse, this.userChatReplyResponse, this.isReplied, @@ -56,6 +57,7 @@ class SingleUserChatModel { DateTime? createdDate; int? chatSource; String? conversationId; + String? downloadUrl; FileTypeResponse? fileTypeResponse; UserChatReplyResponse? userChatReplyResponse; bool? isReplied; @@ -84,6 +86,7 @@ class SingleUserChatModel { createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), chatSource: json["chatSource"] == null ? null : json["chatSource"], conversationId: json["conversationId"] == null ? null : json["conversationId"], + downloadUrl: json["downloadUrl"] == null ? null : json["downloadUrl"], fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]), isReplied: false, @@ -112,6 +115,7 @@ class SingleUserChatModel { "createdDate": createdDate == null ? null : createdDate!.toIso8601String(), "chatSource": chatSource == null ? null : chatSource, "conversationId": conversationId == null ? null : conversationId, + "downloadUrl": downloadUrl == null ? null : downloadUrl, "fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(), "userChatReplyResponse": userChatReplyResponse == null ? null : userChatReplyResponse!.toJson(), }; diff --git a/lib/modules/cx_module/chat/view_all_attachment_page.dart b/lib/modules/cx_module/chat/view_all_attachment_page.dart new file mode 100644 index 00000000..a92d9831 --- /dev/null +++ b/lib/modules/cx_module/chat/view_all_attachment_page.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; + +class ViewAllAttachmentPage extends StatefulWidget { + int moduleId; + int requestId; + + ViewAllAttachmentPage({required this.moduleId, required this.requestId, Key? key}) : super(key: key); + + @override + _ViewAllAttachmentPageState createState() { + return _ViewAllAttachmentPageState(); + } +} + +class _ViewAllAttachmentPageState extends State { + @override + void initState() { + super.initState(); + Provider.of(context, listen: false).viewAllDocuments(widget.moduleId, widget.requestId); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColor.neutral100, + appBar: const DefaultAppBar(title: "Documents"), + body: FutureBuilder( + future: Provider.of(context, listen: false).viewAllDocuments(widget.moduleId, widget.requestId), + builder: (BuildContext context, AsyncSnapshot snapshot) { + bool isLoading = false; + if (snapshot.connectionState == ConnectionState.waiting) { + isLoading = true; + } + return GridView.builder( + itemCount: 9, //isLoading? 9: 2, + padding: const EdgeInsets.all(16), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: context.isTablet() ? 4 : 3, childAspectRatio: 1, crossAxisSpacing: 8, mainAxisSpacing: 8), + itemBuilder: (BuildContext context, int index) { + return Container().toShimmer(context: context, isShow: isLoading); + }, + ); + }), + ); + } +} diff --git a/lib/views/widgets/dialogs/loading_dialog.dart b/lib/views/widgets/dialogs/loading_dialog.dart new file mode 100644 index 00000000..1a72e452 --- /dev/null +++ b/lib/views/widgets/dialogs/loading_dialog.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + +class UploadingDialog extends StatelessWidget { + const UploadingDialog({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + height: 150.toScreenWidth, + width: 200.toScreenWidth, + alignment: Alignment.center, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: AppColor.neutral30, + borderRadius: BorderRadius.circular(20.0), + boxShadow: [AppStyle.boxShadow], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircularProgressIndicator(strokeWidth: 3), + 16.height, + Text( + "Uploading...", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: AppColor.textColor(context), height: 35 / 24, letterSpacing: -0.96), + ) + ], + ), + ), + ); + } +} diff --git a/lib/views/widgets/sound/sound_player.dart b/lib/views/widgets/sound/sound_player.dart index edf8b377..a9368299 100644 --- a/lib/views/widgets/sound/sound_player.dart +++ b/lib/views/widgets/sound/sound_player.dart @@ -7,8 +7,9 @@ import 'package:test_sa/new_views/app_style/app_text_style.dart'; class ASoundPlayer extends StatefulWidget { final String audio; + final bool showLoading; - const ASoundPlayer({Key? key, required this.audio}) : super(key: key); + const ASoundPlayer({Key? key, required this.audio, this.showLoading = false}) : super(key: key); @override _ASoundPlayerState createState() => _ASoundPlayerState(); @@ -161,6 +162,7 @@ class _ASoundPlayerState extends State { if (_isLocalFile) { await _audioPlayer.setSourceDeviceFile(_audio); } else { + // await _audioPlayer.setSource(UrlSource(_audio, headers: widget.headers)); await _audioPlayer.setSourceUrl(_audio); } _audioPlayer.seek(const Duration(milliseconds: 0)); From f3aa929cb14c03bd8babb345fbc5e830d5117f72 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 18 Nov 2025 12:15:04 +0300 Subject: [PATCH 23/31] view all attachments added. --- .../cx_module/chat/chat_api_client.dart | 8 +- lib/modules/cx_module/chat/chat_page.dart | 2 +- lib/modules/cx_module/chat/chat_provider.dart | 6 +- .../chat/model/chat_attachment_model.dart | 60 ++++ .../chat/view_all_attachment_page.dart | 269 +++++++++++++++++- 5 files changed, 328 insertions(+), 17 deletions(-) create mode 100644 lib/modules/cx_module/chat/model/chat_attachment_model.dart diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 37add788..d7f42e9a 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -10,6 +10,7 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:http/http.dart' as http; +import 'package:test_sa/modules/cx_module/chat/model/chat_attachment_model.dart'; import 'api_client.dart'; import 'model/chat_login_response_model.dart'; import 'model/chat_participant_model.dart'; @@ -76,13 +77,14 @@ class ChatApiClient { } } - Future viewAllDocuments(int moduleId, int referenceId) async { + Future> viewAllDocuments(int moduleId, int referenceId) async { Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token); if (response.statusCode == 200) { - return ChatParticipantModel.fromJson(jsonDecode(response.body)); + List data = jsonDecode(response.body)["response"]; + return data.map((elemet) => ChatAttachment.fromJson(elemet)).toList(); } else { - return null; + return []; } } diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 4bab968c..aff8bceb 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -641,7 +641,7 @@ class _ChatPageState extends State { // // ) // // else - ChatFileViewer(chatResponse!.downloadUrl!, chatResponse.fileTypeResponse!), + ChatFileViewer(chatResponse!.downloadUrl!, chatResponse.fileTypeResponse!), // Container( // width: 250, diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 5ad5d1d5..0d00a6f3 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -47,6 +47,7 @@ import 'package:uuid/uuid.dart'; import 'package:flutter/material.dart' as Material; import 'chat_api_client.dart'; +import 'model/chat_attachment_model.dart'; import 'model/chat_participant_model.dart'; import 'model/get_search_user_chat_model.dart'; import 'model/get_single_user_chat_list_model.dart'; @@ -193,11 +194,6 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } catch (e) {} // } - Future viewAllDocuments(int moduleId, int requestId) async { - try { - await ChatApiClient().viewAllDocuments(moduleId, requestId); - } catch (ex) {} - } Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { userChatHistoryLoading = true; diff --git a/lib/modules/cx_module/chat/model/chat_attachment_model.dart b/lib/modules/cx_module/chat/model/chat_attachment_model.dart new file mode 100644 index 00000000..3705ae05 --- /dev/null +++ b/lib/modules/cx_module/chat/model/chat_attachment_model.dart @@ -0,0 +1,60 @@ +class ChatAttachment { + String? id; + String? originalFileName; + String? storedFileName; + String? contentType; + int? sizeBytes; + String? downloadUrl; + String? relativePath; + String? createdOn; + bool? isContextual; + String? moduleCode; + String? referenceId; + String? conversationId; + + ChatAttachment( + {this.id, + this.originalFileName, + this.storedFileName, + this.contentType, + this.sizeBytes, + this.downloadUrl, + this.relativePath, + this.createdOn, + this.isContextual, + this.moduleCode, + this.referenceId, + this.conversationId}); + + ChatAttachment.fromJson(Map json) { + id = json['id']; + originalFileName = json['originalFileName']; + storedFileName = json['storedFileName']; + contentType = json['contentType']; + sizeBytes = json['sizeBytes']; + downloadUrl = json['downloadUrl']; + relativePath = json['relativePath']; + createdOn = json['createdOn']; + isContextual = json['isContextual']; + moduleCode = json['moduleCode']; + referenceId = json['referenceId']; + conversationId = json['conversationId']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['originalFileName'] = this.originalFileName; + data['storedFileName'] = this.storedFileName; + data['contentType'] = this.contentType; + data['sizeBytes'] = this.sizeBytes; + data['downloadUrl'] = this.downloadUrl; + data['relativePath'] = this.relativePath; + data['createdOn'] = this.createdOn; + data['isContextual'] = this.isContextual; + data['moduleCode'] = this.moduleCode; + data['referenceId'] = this.referenceId; + data['conversationId'] = this.conversationId; + return data; + } +} diff --git a/lib/modules/cx_module/chat/view_all_attachment_page.dart b/lib/modules/cx_module/chat/view_all_attachment_page.dart index a92d9831..331997ee 100644 --- a/lib/modules/cx_module/chat/view_all_attachment_page.dart +++ b/lib/modules/cx_module/chat/view_all_attachment_page.dart @@ -1,10 +1,23 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; +import 'package:test_sa/modules/cx_module/chat/model/chat_attachment_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/app_style/app_text_style.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import 'package:test_sa/views/widgets/sound/sound_player.dart'; + +import 'chat_api_client.dart'; class ViewAllAttachmentPage extends StatefulWidget { int moduleId; @@ -19,10 +32,11 @@ class ViewAllAttachmentPage extends StatefulWidget { } class _ViewAllAttachmentPageState extends State { + List? attachments; + @override void initState() { super.initState(); - Provider.of(context, listen: false).viewAllDocuments(widget.moduleId, widget.requestId); } @override @@ -30,27 +44,266 @@ class _ViewAllAttachmentPageState extends State { super.dispose(); } + Future> viewAllDocuments(int moduleId, int requestId) async { + try { + attachments ??= await ChatApiClient().viewAllDocuments(moduleId, requestId); + return attachments!; + } catch (ex) {} + return []; + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.neutral100, appBar: const DefaultAppBar(title: "Documents"), - body: FutureBuilder( - future: Provider.of(context, listen: false).viewAllDocuments(widget.moduleId, widget.requestId), - builder: (BuildContext context, AsyncSnapshot snapshot) { + body: FutureBuilder>( + future: viewAllDocuments(widget.moduleId, widget.requestId), + builder: (BuildContext context, AsyncSnapshot> snapshot) { bool isLoading = false; if (snapshot.connectionState == ConnectionState.waiting) { isLoading = true; } - return GridView.builder( - itemCount: 9, //isLoading? 9: 2, + if (snapshot.hasData && snapshot.data!.isEmpty) { + return NoDataFound(message: context.translation.noDataFound).center; + } + + return ListView.separated( + itemCount: isLoading ? 9 : snapshot.data!.length, padding: const EdgeInsets.all(16), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: context.isTablet() ? 4 : 3, childAspectRatio: 1, crossAxisSpacing: 8, mainAxisSpacing: 8), + separatorBuilder: (cxt, index) => 12.height, itemBuilder: (BuildContext context, int index) { - return Container().toShimmer(context: context, isShow: isLoading); + if (isLoading) { + return Container(height: 48).toShimmer(context: context, isShow: isLoading); + } + return AttachmentFileViewer(snapshot.data![index]); }, ); }), ); } } + +class AttachmentFileViewer extends StatelessWidget { + ChatAttachment chatAttachment; + + AttachmentFileViewer(this.chatAttachment, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: checkFileInLocalStorage(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + bool isImage = chatAttachment.storedFileName!.split(".").last.toLowerCase() == "png" || + chatAttachment.storedFileName!.split(".").last.toLowerCase() == "jpg" || + chatAttachment.storedFileName!.split(".").last.toLowerCase() == "jpeg"; + bool isPdf = chatAttachment.storedFileName!.split(".").last.toLowerCase() == "pdf"; + bool isExcel = chatAttachment.storedFileName!.split(".").last.toLowerCase() == "xlsx"; + bool isAudio = chatAttachment.storedFileName!.split(".").last.toLowerCase() == "m4a" || chatAttachment.storedFileName!.split(".").last.toLowerCase() == "mp3"; + + bool isLoading = snapshot.connectionState == ConnectionState.waiting; + + Widget widget; + if (isLoading) { + if (isAudio) { + return Container( + width: double.infinity, + height: 48, + decoration: ShapeDecoration( + color: AppColor.background(context), + shape: RoundedRectangleBorder( + side: BorderSide(width: 1, color: (context.isDark ? AppColor.neutral20 : AppColor.neutral30)), + borderRadius: BorderRadius.circular(32), + ), + ), + child: SizedBox(width: 24, height: 24, child: const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2).center), + ); + } + widget = const SizedBox(width: 24, height: 24, child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2)); + } else { + if (isImage) { + widget = Image.file(snapshot.data!, width: 48, height: 48, fit: BoxFit.contain); + } else { + widget = Image.asset( + "assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png", + fit: BoxFit.contain, + width: 48, + height: 48); + } + } + if (isAudio) { + if (snapshot.data == null) { + return Text("Failed to load", style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60)); + } + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ASoundPlayer(audio: snapshot.data!.path), + 4.height, + Text( + chatAttachment.createdOn!.toServiceRequestDetailsFormat, + style: AppTextStyles.textFieldLabelStyle.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ).paddingOnly(start: 60), + ], + )); + } + + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.all(8), + child: Row( + children: [ + ClipRRect(borderRadius: BorderRadius.circular(8.0), child: widget), + 12.width, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + chatAttachment.storedFileName!, + style: AppTextStyles.textFieldLabelStyle.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 4.height, + Text( + chatAttachment.createdOn!.toServiceRequestDetailsFormat, + style: AppTextStyles.textFieldLabelStyle.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + ], + ).expanded + ], + ), + ).onPress(() { + if (isImage) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + appBar: const DefaultAppBar(), + body: SafeArea( + child: InteractiveViewer(child: Image.file(snapshot.data!)).center, + ), + ), + ), + ); + } else { + OpenFile.open(snapshot.data!.path); + } + }); + return Container( + width: double.infinity, + height: 48, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.white, + ), + child: snapshot.connectionState == ConnectionState.waiting + ? const SizedBox( + height: 24, + width: 24, + child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2), + ).center + : snapshot.hasData + ? Row( + children: [ + getImage(snapshot.data!), + getFile(context, snapshot.data!), + ], + ) + : const Icon(Icons.broken_image_rounded), + ); + + return Container( + width: double.infinity, + height: 48, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.white, + ), + child: snapshot.connectionState == ConnectionState.waiting + ? const SizedBox( + height: 24, + width: 24, + child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2), + ).center + : snapshot.hasData + ? Row( + children: [ + getImage(snapshot.data!), + getFile(context, snapshot.data!), + ], + ) + : const Icon(Icons.broken_image_rounded), + ); + }); + } + + Widget getFile(BuildContext context, File file) { + bool isImage = file.path.split(".").last.toLowerCase() == "png" || file.path.split(".").last.toLowerCase() == "jpg" || file.path.split(".").last.toLowerCase() == "jpeg"; + bool isPdf = file.path.split(".").last.toLowerCase() == "pdf"; + bool isExcel = file.path.split(".").last.toLowerCase() == "xlsx"; + + return MaterialButton( + padding: EdgeInsets.zero, + onPressed: () async { + if (isImage) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + appBar: const DefaultAppBar(), + body: SafeArea( + child: InteractiveViewer(child: Image.file(file)).center, + ), + ), + ), + ); + } else { + OpenFile.open(file.path); + } + // else { + // // if (!await launchUrl(Uri.parse(URLs.getFileUrl(file.path)!), mode: LaunchMode.externalApplication)) { + // // Fluttertoast.showToast(msg: "UnExpected Error with file."); + // // throw Exception('Could not launch'); + // // } + // } + }, + ); + } + + Widget getImage(File file) { + bool isImage = file.path.split(".").last.toLowerCase() == "png" || file.path.split(".").last.toLowerCase() == "jpg" || file.path.split(".").last.toLowerCase() == "jpeg"; + bool isPdf = file.path.split(".").last.toLowerCase() == "pdf"; + bool isExcel = file.path.split(".").last.toLowerCase() == "xlsx"; + + if (isImage) { + return Image.file(file); + } + return Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png"); + } + + Future checkFileInLocalStorage() async { + Directory tempDir = await getTemporaryDirectory(); + String tempPath = '${tempDir.path}/${chatAttachment.storedFileName}'; + File tempFile = File(tempPath); + bool exists = await tempFile.exists(); + if (exists) { + return tempFile; + } else { + return downloadFile(); + } + } + + Future downloadFile() async { + try { + return await ChatApiClient().downloadFileWithHttp(chatAttachment.downloadUrl!, fileName: chatAttachment.storedFileName!, fileTypeDescription: "", fileSource: 0); + } catch (ex) { + return null; + } + } +} From e52caee730047cecdfd03438a6d8b2c81ed7d16b Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 18 Nov 2025 12:30:15 +0300 Subject: [PATCH 24/31] chat improvements --- .../views/service_request_detail_main_view.dart | 7 +++++-- lib/modules/cx_module/chat/chat_page.dart | 14 +++++++------- lib/modules/cx_module/chat/chat_provider.dart | 1 - 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 1f2008d8..3d0c6688 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -34,10 +34,13 @@ class ServiceRequestDetailMain extends StatefulWidget { class _ServiceRequestDetailMainState extends State { late ServiceRequestDetailProvider _requestProvider; + static const int moduleId = 3; + @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).reset(); getInitialData(); }); } @@ -93,7 +96,7 @@ class _ServiceRequestDetailMainState extends State { } else { ServiceRequestDetailProvider provider = Provider.of(context, listen: false); if (provider.currentWorkOrder?.data?.status?.value == 2) { - getChatToken(1, provider.currentWorkOrder?.data?.workOrderNo ?? ""); + getChatToken(moduleId, provider.currentWorkOrder?.data?.workOrderNo ?? ""); return Consumer(builder: (pContext, requestProvider, _) { return IconButton( icon: const Icon(Icons.chat_bubble), @@ -102,7 +105,7 @@ class _ServiceRequestDetailMainState extends State { context, CupertinoPageRoute( builder: (context) => ChatPage( - moduleId: 1, + moduleId: 3, requestId: widget.requestId, title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? "", readOnly: _requestProvider.isReadOnlyRequest, diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index aff8bceb..84f85c75 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -164,7 +164,7 @@ class _ChatPageState extends State { decorationColor: AppColor.white10, ), ).onPress(() { - Navigator.push(context, CupertinoPageRoute(builder: (context) => ViewAllAttachmentPage(moduleId: 1, requestId: widget.requestId))); + Navigator.push(context, CupertinoPageRoute(builder: (context) => ViewAllAttachmentPage(moduleId: widget.moduleId, requestId: widget.requestId))); }), ], ), @@ -744,12 +744,12 @@ class _ChatPageState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ if (chatResponse?.downloadUrl != null) ...[ - if (chatResponse!.fileTypeResponse!.fileKind.toString().toLowerCase() == "audio") ChatAudioPlayer(chatResponse!.fileTypeResponse!, chatResponse.downloadUrl!) - ], - Text( - contentMsg, - style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), - ).paddingOnly(end: 6 * length).toShimmer(context: context, isShow: loading), + ChatFileViewer(chatResponse!.downloadUrl!, chatResponse.fileTypeResponse!), + ] else + Text( + contentMsg, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), + ).paddingOnly(end: 6 * length).toShimmer(context: context, isShow: loading), if (loading) 4.height, Align( alignment: Alignment.centerRight, diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 0d00a6f3..043369d7 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -194,7 +194,6 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } catch (e) {} // } - Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { userChatHistoryLoading = true; notifyListeners(); From c31771aaa7972116690cf81a7ffc3b0ad93c3e61 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 18 Nov 2025 13:08:46 +0300 Subject: [PATCH 25/31] chat improvements --- .../views/service_request_detail_main_view.dart | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 3d0c6688..93a8aaa9 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -34,7 +34,7 @@ class ServiceRequestDetailMain extends StatefulWidget { class _ServiceRequestDetailMainState extends State { late ServiceRequestDetailProvider _requestProvider; - static const int moduleId = 3; + static const int moduleId = 1; @override void initState() { @@ -95,7 +95,8 @@ class _ServiceRequestDetailMainState extends State { return const SizedBox(); } else { ServiceRequestDetailProvider provider = Provider.of(context, listen: false); - if (provider.currentWorkOrder?.data?.status?.value == 2) { + int? statusValue = provider.currentWorkOrder?.data?.status?.value; + if (statusValue == 2 || statusValue == 3 || statusValue == 5 || statusValue == 6) { getChatToken(moduleId, provider.currentWorkOrder?.data?.workOrderNo ?? ""); return Consumer(builder: (pContext, requestProvider, _) { return IconButton( @@ -183,14 +184,10 @@ class _ServiceRequestDetailMainState extends State { String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; String myEmployeeId = context.userProvider.user!.username!; - // String sender = context.settingProvider.username; String receiver = context.userProvider.isNurse ? assigneeEmployeeNumber : (context.userProvider.isEngineer ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId! : ""); - // assigneeEmployeeNumber - // ChatProvider cProvider = Provider.of(context, listen: false); - // Provider.of(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId, widget.title, myEmployeeId, assigneeEmployeeNumber); cProvider.getUserAutoLoginTokenSilent(moduleId, widget.requestId, title, myEmployeeId, receiver); } } From 1f074b33e561c51742ce9d056ac569b88e9a9f94 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 18 Nov 2025 16:06:37 +0300 Subject: [PATCH 26/31] chat finalized. --- .../service_request_detail_main_view.dart | 59 +++++++------- .../cx_module/chat/chat_api_client.dart | 7 +- lib/modules/cx_module/chat/chat_provider.dart | 60 ++------------ .../chat/helper/chat_file_picker.dart | 2 +- .../chat/model/chat_login_response_model.dart | 79 ++++++++++++++++++- 5 files changed, 116 insertions(+), 91 deletions(-) diff --git a/lib/modules/cm_module/views/service_request_detail_main_view.dart b/lib/modules/cm_module/views/service_request_detail_main_view.dart index 93a8aaa9..7f9ad154 100644 --- a/lib/modules/cm_module/views/service_request_detail_main_view.dart +++ b/lib/modules/cm_module/views/service_request_detail_main_view.dart @@ -88,36 +88,37 @@ class _ServiceRequestDetailMainState extends State { Navigator.pop(context); }, actions: [ - Selector( - selector: (_, myModel) => myModel.isLoading, // Selects only the userName - builder: (_, isLoading, __) { - if (isLoading) { - return const SizedBox(); - } else { - ServiceRequestDetailProvider provider = Provider.of(context, listen: false); - int? statusValue = provider.currentWorkOrder?.data?.status?.value; - if (statusValue == 2 || statusValue == 3 || statusValue == 5 || statusValue == 6) { - getChatToken(moduleId, provider.currentWorkOrder?.data?.workOrderNo ?? ""); - return Consumer(builder: (pContext, requestProvider, _) { - return IconButton( - icon: const Icon(Icons.chat_bubble), - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ChatPage( - moduleId: 3, - requestId: widget.requestId, - title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? "", - readOnly: _requestProvider.isReadOnlyRequest, - ))); - }, - ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); - }); + if (context.userProvider.isEngineer || context.userProvider.isNurse) + Selector( + selector: (_, myModel) => myModel.isLoading, // Selects only the userName + builder: (_, isLoading, __) { + if (isLoading) { + return const SizedBox(); + } else { + ServiceRequestDetailProvider provider = Provider.of(context, listen: false); + int? statusValue = provider.currentWorkOrder?.data?.status?.value; + if (statusValue == 2 || statusValue == 3 || statusValue == 5 || statusValue == 6) { + getChatToken(moduleId, provider.currentWorkOrder?.data?.workOrderNo ?? ""); + return Consumer(builder: (pContext, requestProvider, _) { + return IconButton( + icon: const Icon(Icons.chat_bubble), + onPressed: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ChatPage( + moduleId: moduleId, + requestId: widget.requestId, + title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? "", + readOnly: _requestProvider.isReadOnlyRequest, + ))); + }, + ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); + }); + } + return const SizedBox(); } - return const SizedBox(); - } - }), + }), isNurse ? IconButton( icon: 'qr'.toSvgAsset( diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index d7f42e9a..8466a596 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -43,15 +43,16 @@ class ChatApiClient { ChatLoginResponse? chatLoginResponse; - Future getChatLoginToken(int moduleId, int requestId, String title, String employeeNumber) async { + Future getChatLoginToken(int moduleId, int requestId, String title, String employeeNumber, String assigneeEmployeeNumber) async { Response response = await ApiClient().postJsonForResponse(URLs.chatSdkToken, { "apiKey": URLs.chatApiKey, "employeeNumber": employeeNumber, + "assigneeEmployeeNumber": assigneeEmployeeNumber, "userDetails": {"userName": ApiManager.instance.user?.username, "email": ApiManager.instance.user?.email}, "contextEnabled": true, "moduleCode": moduleId.toString(), "referenceId": requestId.toString(), - "referenceType": "ticket", + // "referenceType": "ticket", "title": title }); @@ -65,7 +66,7 @@ class ChatApiClient { } Future loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async { - Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId", token: chatLoginResponse!.token); + Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); if (!kReleaseMode) { // logger.i("login-res: " + response.body); diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 043369d7..6aadcc44 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -57,56 +57,6 @@ import 'model/user_chat_history_model.dart'; late HubConnection chatHubConnection; class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { - // ScrollController scrollController = ScrollController(); - // - // TextEditingController message = TextEditingController(); - // TextEditingController search = TextEditingController(); - // TextEditingController searchGroup = TextEditingController(); - // - // List? pChatHistory, searchedChats; - // String chatCID = ''; - // bool isLoading = true; - // bool isChatScreenActive = false; - // int receiverID = 0; - // late File selectedFile; - // String sFileType = ""; - // - // List favUsersList = []; - // int paginationVal = 0; - // int? cTypingUserId = 0; - // bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; - // - // // Audio Recoding Work - // Timer? _timer; - // int _recodeDuration = 0; - // bool isRecoding = false; - // bool isPause = false; - // bool isPlaying = false; - // String? path; - // String? musicFile; - // late Directory appDirectory; - // late RecorderController recorderController; - // late PlayerController playerController; - // - // // List getEmployeeSubordinatesList = []; - // List teamMembersList = []; - // - // // groups.GetUserGroups userGroups = groups.GetUserGroups(); - // Material.TextDirection textDirection = Material.TextDirection.ltr; - // bool isRTL = false; - // String msgText = ""; - // - // //Chat Home Page Counter - // int chatUConvCounter = 0; - // - // // late List groupChatHistory, groupChatReplyData; - // - // /// Search Provider - // List? chatUsersList = []; - // int pageNo = 1; - // - // bool disbaleChatForThisUser = false; - bool isTyping = false; bool chatLoginTokenLoading = false; @@ -164,11 +114,13 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { chatLoginTokenLoading = true; notifyListeners(); try { - chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId); + chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId, assigneeEmployeeNumber); chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); - sender = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == myId); - recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); - } catch (ex) {} + sender = chatParticipantModel?.participants?.firstWhere((participant) => participant.employeeNumber == myId); + recipient = chatParticipantModel?.participants?.firstWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber); + } catch (ex) { + print(ex); + } chatLoginTokenLoading = false; notifyListeners(); } diff --git a/lib/modules/cx_module/chat/helper/chat_file_picker.dart b/lib/modules/cx_module/chat/helper/chat_file_picker.dart index 63e19d71..9d928521 100644 --- a/lib/modules/cx_module/chat/helper/chat_file_picker.dart +++ b/lib/modules/cx_module/chat/helper/chat_file_picker.dart @@ -71,7 +71,7 @@ class ChatFilePicker extends StatelessWidget { fromFilePicker(BuildContext context) async { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, - allowedExtensions: ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], + allowedExtensions: ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx', 'txt'], ); if ((result?.paths ?? []).isNotEmpty) { Navigator.pop(context, File(result!.paths.first!)); diff --git a/lib/modules/cx_module/chat/model/chat_login_response_model.dart b/lib/modules/cx_module/chat/model/chat_login_response_model.dart index 3fde6c54..a8612818 100644 --- a/lib/modules/cx_module/chat/model/chat_login_response_model.dart +++ b/lib/modules/cx_module/chat/model/chat_login_response_model.dart @@ -4,9 +4,15 @@ class ChatLoginResponse { String? userName; int? applicationId; int? expiresIn; - String? context; + Context? context; - ChatLoginResponse({this.token, this.userId, this.userName, this.applicationId, this.expiresIn, this.context}); + ChatLoginResponse( + {this.token, + this.userId, + this.userName, + this.applicationId, + this.expiresIn, + this.context}); ChatLoginResponse.fromJson(Map json) { token = json['token']; @@ -14,7 +20,8 @@ class ChatLoginResponse { userName = json['userName']; applicationId = json['applicationId']; expiresIn = json['expiresIn']; - context = json['context']; + context = + json['context'] != null ? new Context.fromJson(json['context']) : null; } Map toJson() { @@ -24,7 +31,71 @@ class ChatLoginResponse { data['userName'] = this.userName; data['applicationId'] = this.applicationId; data['expiresIn'] = this.expiresIn; - data['context'] = this.context; + if (this.context != null) { + data['context'] = this.context!.toJson(); + } + return data; + } +} + +class Context { + String? conversationId; + String? moduleCode; + String? referenceId; + String? title; + List? deepLinks; + + Context( + {this.conversationId, + this.moduleCode, + this.referenceId, + this.title, + this.deepLinks}); + + Context.fromJson(Map json) { + conversationId = json['conversationId']; + moduleCode = json['moduleCode']; + referenceId = json['referenceId']; + title = json['title']; + if (json['deepLinks'] != null) { + deepLinks = []; + json['deepLinks'].forEach((v) { + deepLinks!.add(new DeepLinks.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['conversationId'] = this.conversationId; + data['moduleCode'] = this.moduleCode; + data['referenceId'] = this.referenceId; + data['title'] = this.title; + if (this.deepLinks != null) { + data['deepLinks'] = this.deepLinks!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class DeepLinks { + String? employeeNumber; + int? userId; + String? userName; + + DeepLinks({this.employeeNumber, this.userId, this.userName}); + + DeepLinks.fromJson(Map json) { + employeeNumber = json['employeeNumber']; + userId = json['userId']; + userName = json['userName']; + } + + Map toJson() { + final Map data = new Map(); + data['employeeNumber'] = this.employeeNumber; + data['userId'] = this.userId; + data['userName'] = this.userName; return data; } } From e3857149e7181d3837b2ebae040e5dc5a75d526c Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 19 Nov 2025 07:46:27 +0300 Subject: [PATCH 27/31] improvements --- .../cx_module/chat/chat_api_client.dart | 21 +++--- lib/modules/cx_module/chat/chat_page.dart | 16 +++- lib/modules/cx_module/chat/chat_widget.dart | 73 +++++++++++++++++++ .../chat/helper/chat_file_picker.dart | 2 +- .../user/gas_refill/gas_refill_details.dart | 13 +++- 5 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 lib/modules/cx_module/chat/chat_widget.dart diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index 8466a596..c01e5d05 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -66,7 +66,8 @@ class ChatApiClient { } Future loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async { - Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); + Response response = + await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); if (!kReleaseMode) { // logger.i("login-res: " + response.body); @@ -93,18 +94,18 @@ class ChatApiClient { Response response = await ApiClient().postJsonForResponse( "${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()}, token: chatLoginResponse!.token); - // try { - if (response.statusCode == 200) { - List data = jsonDecode(response.body); - return data.map((elemet) => SingleUserChatModel.fromJson(elemet)).toList(); + try { + if (response.statusCode == 200) { + List data = jsonDecode(response.body); + return data.map((elemet) => SingleUserChatModel.fromJson(elemet)).toList(); - // return UserChatHistoryModel.fromJson(jsonDecode(response.body)); - } else { + // return UserChatHistoryModel.fromJson(jsonDecode(response.body)); + } else { + return []; + } + } catch (ex) { return []; } - // } catch (ex) { - // return []; - // } } /* Future sendTextMessage(String message, int conversationId) async { diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 84f85c75..8a22fd1b 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -34,10 +34,12 @@ enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } class ChatPage extends StatefulWidget { int moduleId; int requestId; + String assigneeEmployeeNumber; + String myEmployeeID; String title; bool readOnly; - ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false}) : super(key: key); + ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false, this.assigneeEmployeeNumber = "", this.myEmployeeID = ""}) : super(key: key); @override _ChatPageState createState() { @@ -72,6 +74,18 @@ class _ChatPageState extends State { } void loadChatHistory() { + // // String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + // // String myEmployeeId = context.userProvider.user!.username!; + // // + // + // receiver = context.userProvider.isNurse ? widget.assigneeEmployeeNumber : widget.myEmployeeID; + // + // Provider.of(context, listen: false).connectToHub(widget.moduleId, widget.requestId, widget.myEmployeeID, widget.assigneeEmployeeNumber); + // + // receiver = context.userProvider.isNurse + // ? assigneeEmployeeNumber + // :myEmployeeId; + String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; String myEmployeeId = context.userProvider.user!.username!; diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart new file mode 100644 index 00000000..b9bc111b --- /dev/null +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -0,0 +1,73 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; + +import 'chat_page.dart'; +import 'chat_provider.dart'; + +class ChatWidget extends StatefulWidget { + int moduleId; + int requestId; + String assigneeEmployeeNumber; + String myEmployeeID; + bool isReadOnly; + String title; + + ChatWidget({Key? key, this.isReadOnly = false, this.title = "Chat", required this.moduleId, required this.requestId, required this.assigneeEmployeeNumber, required this.myEmployeeID}) + : super(key: key); + + @override + _ChatWidgetState createState() { + return _ChatWidgetState(); + } +} + +class _ChatWidgetState extends State { + @override + void initState() { + super.initState(); + Provider.of(context, listen: false).reset(); + getChatToken(); + } + + void getChatToken() { + ChatProvider cProvider = Provider.of(context, listen: false); + if (cProvider.chatLoginResponse != null && cProvider.referenceID == widget.requestId) return; + // String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + String myEmployeeId = widget.myEmployeeID; + + String receiver = context.userProvider.isNurse ? widget.assigneeEmployeeNumber : widget.myEmployeeID; + + cProvider.getUserAutoLoginTokenSilent(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (pContext, requestProvider, _) { + return IconButton( + icon: const Icon(Icons.chat_bubble), + onPressed: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ChatPage( + moduleId: widget.moduleId, + requestId: widget.requestId, + title: widget.title, + readOnly: widget.isReadOnly, + assigneeEmployeeNumber: widget.assigneeEmployeeNumber, + myEmployeeID: widget.myEmployeeID, + ))); + }, + ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); + }); + ; + } +} diff --git a/lib/modules/cx_module/chat/helper/chat_file_picker.dart b/lib/modules/cx_module/chat/helper/chat_file_picker.dart index 9d928521..1070e3db 100644 --- a/lib/modules/cx_module/chat/helper/chat_file_picker.dart +++ b/lib/modules/cx_module/chat/helper/chat_file_picker.dart @@ -48,7 +48,7 @@ class ChatFilePicker extends StatelessWidget { if (pickedFile != null) { CroppedFile? croppedFile = await ImageCropper().cropImage( sourcePath: pickedFile.path, - aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), + // aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), uiSettings: [ AndroidUiSettings( toolbarTitle: 'ATOMS', diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index e5964bc5..16aac3d5 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -11,6 +11,7 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/views/pages/user/gas_refill/update_gas_refill_request.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; @@ -55,7 +56,17 @@ class _GasRefillDetailsPageState extends State { gasRefillProvider = Provider.of(context); return Scaffold( - appBar: DefaultAppBar(title: context.translation.gasRefillDetails), + appBar: DefaultAppBar( + title: context.translation.gasRefillDetails, + // actions: [ + // if (context.userProvider.isEngineer || context.userProvider.isNurse) ...[ + // if (context.userProvider.isEngineer) + // ChatWidget(moduleId: 4, requestId: 1, assigneeEmployeeNumber: "123456", myEmployeeID: "1234") + // else + // ChatWidget(moduleId: 4, requestId: 1, assigneeEmployeeNumber: "123456", myEmployeeID: "123456") + // ] + // ], + ), key: _scaffoldKey, body: FutureBuilder( future: gasRefillProvider.getGasRefillObjectById(widget.model.id!), From 542070c7913f9442530f6e14e788f4056b2e8a8c Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Wed, 19 Nov 2025 11:24:04 +0300 Subject: [PATCH 28/31] improvements --- lib/models/user.dart | 6 ++---- .../update_equipment_internal_audit_page.dart | 1 + .../update_system_internal_audit_page.dart | 2 ++ .../land_page/my_request/all_requests_filter_page.dart | 8 +++++--- lib/views/widgets/timer/app_timer.dart | 5 ++++- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/models/user.dart b/lib/models/user.dart index 2c4f3e19..de6f88b8 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -98,8 +98,6 @@ class User { UsersTypes? get type { switch (userRoles?.first.value) { - case "R-7": // Head Nurse Role - return UsersTypes.qualityUser; case "R-6": return UsersTypes.engineer; case "R-7": // Nurse Role @@ -110,8 +108,8 @@ class User { return UsersTypes.assessor; case "R-19": // Head Nurse Role return UsersTypes.assessorTl; - //TODO need to replace with actual data when confirm - + case "R-3": // Quality User + return UsersTypes.qualityUser; default: return null; } diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart index e5d3072f..f69e4a10 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart @@ -292,6 +292,7 @@ class _UpdateEquipmentInternalAuditPageState extends State { if (isEngineer) { types[context.translation.recurrentWo] = 5; - types["Internal Audit".addTranslation] = 10; + types["Equipment Internal Audit".addTranslation] = 10; + types["System Internal Audit".addTranslation] = 11; } if (context.settingProvider.isUserFlowMedical) { @@ -83,8 +84,9 @@ class _AllRequestsFilterPageState extends State { if (context.userProvider.isAssessor) { types = {"TRAF": 9}; - }if (context.userProvider.isQualityUser) { - types = {"Internal Audit": 10}; + } + if (context.userProvider.isQualityUser) { + types = {'Equipment Internal Audit': 10, 'System Internal Audit': 11}; } final statuses = { diff --git a/lib/views/widgets/timer/app_timer.dart b/lib/views/widgets/timer/app_timer.dart index 84179d92..629ad60c 100644 --- a/lib/views/widgets/timer/app_timer.dart +++ b/lib/views/widgets/timer/app_timer.dart @@ -22,6 +22,7 @@ class AppTimer extends StatefulWidget { final TextStyle? style; final BoxDecoration? decoration; final bool enabled; + final bool showPicker; final String? label; final double? width; @@ -40,6 +41,7 @@ class AppTimer extends StatefulWidget { this.onPick, this.timerProgress, this.enabled = true, + this.showPicker = true, }) : super(key: key); @override @@ -126,7 +128,8 @@ class _AppTimerState extends State { @override void initState() { - canPickTime = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + ///this is temp check for internal audit + canPickTime = widget.showPicker == false ? false : ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; _startAt = widget.timer?.startAt; _endAt = widget.timer?.endAt; _running = _startAt != null && _endAt == null; From 4f78e23922ab90016c5b5642498f25d22d03b086 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 19 Nov 2025 12:31:10 +0300 Subject: [PATCH 29/31] chat widget finalized. --- .../providers/api/gas_refill_provider.dart | 8 ++- lib/modules/cx_module/chat/chat_page.dart | 26 +++++---- lib/modules/cx_module/chat/chat_provider.dart | 58 ++++++++++++------- lib/modules/cx_module/chat/chat_widget.dart | 40 ++++++++++--- .../user/gas_refill/gas_refill_details.dart | 27 ++++++--- 5 files changed, 107 insertions(+), 52 deletions(-) diff --git a/lib/controllers/providers/api/gas_refill_provider.dart b/lib/controllers/providers/api/gas_refill_provider.dart index 40d6327a..8b522790 100644 --- a/lib/controllers/providers/api/gas_refill_provider.dart +++ b/lib/controllers/providers/api/gas_refill_provider.dart @@ -47,12 +47,16 @@ class GasRefillProvider extends ChangeNotifier { // failed _loading = false bool isLoading = false; + GasRefillModel? gasRefillModel; + Future getGasRefillObjectById(num id) async { try { + gasRefillModel = null; Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gasRefillId=$id"); - if (response.statusCode >= 200 && response.statusCode < 300) { - return GasRefillModel.fromJson(json.decode(response.body)["data"]); + gasRefillModel = GasRefillModel.fromJson(json.decode(response.body)["data"]); + notifyListeners(); + return gasRefillModel; } else { return null; } diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 8a22fd1b..0ff1f567 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -34,12 +34,14 @@ enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } class ChatPage extends StatefulWidget { int moduleId; int requestId; - String assigneeEmployeeNumber; - String myEmployeeID; + String? assigneeEmployeeNumber; + String? myLoginUserID; + String? contactEmployeeINumber; String title; bool readOnly; - ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false, this.assigneeEmployeeNumber = "", this.myEmployeeID = ""}) : super(key: key); + ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false, this.assigneeEmployeeNumber, this.myLoginUserID, this.contactEmployeeINumber}) + : super(key: key); @override _ChatPageState createState() { @@ -86,18 +88,20 @@ class _ChatPageState extends State { // ? assigneeEmployeeNumber // :myEmployeeId; - String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; - String myEmployeeId = context.userProvider.user!.username!; + String assigneeEmployeeNumber = widget.assigneeEmployeeNumber ?? Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + String myEmployeeId = widget.myLoginUserID ?? context.userProvider.user!.username!; receiver = context.userProvider.isNurse ? assigneeEmployeeNumber - : (context.userProvider.isEngineer ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId! : ""); - Provider.of(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver); + : (context.userProvider.isEngineer + ? (widget.contactEmployeeINumber ?? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!) + : ""); + Provider.of(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted); } @override void dispose() { - chatHubConnection.stop(); + chatHubConnection?.stop(); playerController.dispose(); recorderController.dispose(); super.dispose(); @@ -246,13 +250,13 @@ class _ChatPageState extends State { textInputAction: TextInputAction.none, keyboardType: TextInputType.multiline, onTap: () { - chatHubConnection.invoke("SendTypingAsync", args: [receiver]); + chatHubConnection!.invoke("SendTypingAsync", args: [receiver]); }, onTapOutside: (PointerDownEvent event) { - chatHubConnection.invoke("SendStopTypingAsync", args: [receiver]); + chatHubConnection!.invoke("SendStopTypingAsync", args: [receiver]); }, onChanged: (text) { - chatHubConnection.invoke("SendTypingAsync", args: [receiver]); + chatHubConnection!.invoke("SendTypingAsync", args: [receiver]); }, decoration: InputDecoration( enabledBorder: InputBorder.none, diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 6aadcc44..136dd28b 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -54,7 +54,7 @@ import 'model/get_single_user_chat_list_model.dart'; import 'model/user_chat_history_model.dart'; // import 'get_single_user_chat_list_model.dart'; -late HubConnection chatHubConnection; +HubConnection? chatHubConnection; class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { bool isTyping = false; @@ -83,6 +83,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { int? referenceID; void reset() { + chatHubConnection?.stop().then((value) { + chatHubConnection = null; + }); chatLoginTokenLoading = false; chatParticipantLoading = false; userChatHistoryLoading = false; @@ -108,11 +111,13 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } // } - Future getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async { + Future getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber, {bool isMounted = true}) async { reset(); receiverID = assigneeEmployeeNumber; chatLoginTokenLoading = true; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } try { chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId, assigneeEmployeeNumber); chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); @@ -122,7 +127,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { print(ex); } chatLoginTokenLoading = false; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } } // Future getUserLoadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { @@ -146,17 +153,24 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } catch (e) {} // } - Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { + Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber, bool readOnly, {bool isMounted = true}) async { userChatHistoryLoading = true; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } moduleID = moduleId; referenceID = requestId; - await buildHubConnection(chatParticipantModel!.id!.toString()); + if (!readOnly) { + await buildHubConnection(chatParticipantModel!.id!.toString()); + } + userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); chatResponseList = userChatHistory ?? []; chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); userChatHistoryLoading = false; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } } // Future loadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { @@ -174,7 +188,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); bool returnStatus = false; try { - await chatHubConnection.invoke("AddChatUserAsync", args: [object]); + await chatHubConnection!.invoke("AddChatUserAsync", args: [object]); returnStatus = true; } catch (ex) {} @@ -223,17 +237,17 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { Future buildHubConnection(String conversationID) async { chatHubConnection = await getHubConnection(); - await chatHubConnection.start(); + await chatHubConnection!.start(); if (kDebugMode) { print("Hub Conn: Startedddddddd"); } - await chatHubConnection.invoke("JoinConversation", args: [conversationID]); - chatHubConnection.on("ReceiveMessage", onMsgReceived1); - chatHubConnection.on("OnMessageReceivedAsync", onMsgReceived); - chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); - chatHubConnection.on("OnTypingAsync", OnTypingAsync); - chatHubConnection.on("OnStopTypingAsync", OnStopTypingAsync); + await chatHubConnection!.invoke("JoinConversation", args: [conversationID]); + chatHubConnection!.on("ReceiveMessage", onMsgReceived1); + chatHubConnection!.on("OnMessageReceivedAsync", onMsgReceived); + chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync); + chatHubConnection!.on("OnTypingAsync", OnTypingAsync); + chatHubConnection!.on("OnStopTypingAsync", OnStopTypingAsync); //group On message @@ -255,7 +269,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); // chatHubConnection.on("OnUserTypingAsync", onUserTyping); - chatHubConnection.on("OnUserCountAsync", userCountAsync); + chatHubConnection?.on("OnUserCountAsync", userCountAsync); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); // chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); // chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); @@ -298,7 +312,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { - await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); + await chatHubConnection!.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); return ""; } @@ -361,7 +375,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryStatusAsync(List data) { try { - chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } @@ -369,7 +383,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryOnMsg(List data) { try { - chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } @@ -1766,12 +1780,12 @@ void setMsgTune() async { // } Future invokeChatCounter({required int userId}) async { - await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); + await chatHubConnection!.invoke("GetChatCounversationCount", args: [userId]); return ""; } void userTypingInvoke({required int currentUser, required int reciptUser}) async { - await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); + await chatHubConnection!.invoke("UserTypingAsync", args: [reciptUser, currentUser]); } // void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart index b9bc111b..9d7c8a36 100644 --- a/lib/modules/cx_module/chat/chat_widget.dart +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'chat_page.dart'; import 'chat_provider.dart'; @@ -10,12 +11,23 @@ import 'chat_provider.dart'; class ChatWidget extends StatefulWidget { int moduleId; int requestId; - String assigneeEmployeeNumber; - String myEmployeeID; + String? assigneeEmployeeNumber; + String? myLoginUserID; + String? contactEmployeeINumber; bool isReadOnly; + bool isShow; String title; - ChatWidget({Key? key, this.isReadOnly = false, this.title = "Chat", required this.moduleId, required this.requestId, required this.assigneeEmployeeNumber, required this.myEmployeeID}) + ChatWidget( + {Key? key, + this.isReadOnly = false, + this.title = "Chat", + required this.moduleId, + required this.requestId, + this.assigneeEmployeeNumber, + this.myLoginUserID, + this.contactEmployeeINumber, + this.isShow = false}) : super(key: key); @override @@ -33,14 +45,25 @@ class _ChatWidgetState extends State { } void getChatToken() { + // ChatProvider cProvider = Provider.of(context, listen: false); + // if (cProvider.chatLoginResponse != null && cProvider.referenceID == widget.requestId) return; + // // String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + // String myEmployeeId = widget.myLoginUserID; + // + // String receiver = context.userProvider.isNurse ? widget.assigneeEmployeeNumber : widget.myEmployeeID; + ChatProvider cProvider = Provider.of(context, listen: false); if (cProvider.chatLoginResponse != null && cProvider.referenceID == widget.requestId) return; - // String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; - String myEmployeeId = widget.myEmployeeID; + String assigneeEmployeeNumber = widget.assigneeEmployeeNumber ?? Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + String myEmployeeId = widget.myLoginUserID ?? context.userProvider.user!.username!; - String receiver = context.userProvider.isNurse ? widget.assigneeEmployeeNumber : widget.myEmployeeID; + String receiver = context.userProvider.isNurse + ? assigneeEmployeeNumber + : (context.userProvider.isEngineer + ? (widget.contactEmployeeINumber ?? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!) + : ""); - cProvider.getUserAutoLoginTokenSilent(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver); + cProvider.getUserAutoLoginTokenSilent(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver, isMounted: mounted); } @override @@ -63,7 +86,8 @@ class _ChatWidgetState extends State { title: widget.title, readOnly: widget.isReadOnly, assigneeEmployeeNumber: widget.assigneeEmployeeNumber, - myEmployeeID: widget.myEmployeeID, + contactEmployeeINumber: widget.contactEmployeeINumber, + myLoginUserID: widget.myLoginUserID, ))); }, ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index 16aac3d5..3773c898 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -53,19 +53,28 @@ class _GasRefillDetailsPageState extends State { @override Widget build(BuildContext context) { _userProvider = Provider.of(context); - gasRefillProvider = Provider.of(context); + gasRefillProvider = Provider.of(context, listen: false); return Scaffold( appBar: DefaultAppBar( title: context.translation.gasRefillDetails, - // actions: [ - // if (context.userProvider.isEngineer || context.userProvider.isNurse) ...[ - // if (context.userProvider.isEngineer) - // ChatWidget(moduleId: 4, requestId: 1, assigneeEmployeeNumber: "123456", myEmployeeID: "1234") - // else - // ChatWidget(moduleId: 4, requestId: 1, assigneeEmployeeNumber: "123456", myEmployeeID: "123456") - // ] - // ], + actions: [ + // if (context.userProvider.isEngineer || context.userProvider.isNurse) + // Selector( + // selector: (_, myModel) => myModel.gasRefillModel, // Selects only the userName + // builder: (_, _gasRefillModel, __) { + // if (_gasRefillModel == null) return const SizedBox(); + // return ChatWidget( + // moduleId: 2, + // isShow: _gasRefillModel.status!.value! == 1, + // // isReadOnly: _gasRefillModel.status!.value! == 1, + // requestId: widget.model.id!.toInt(), + // assigneeEmployeeNumber: _gasRefillModel.assignedEmployee!.name!, + // myLoginUserID: context.userProvider.user!.username!, + // contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!, + // ); + // }) + ], ), key: _scaffoldKey, body: FutureBuilder( From bbeabda38d4bdf8a9c8214c1870be28eb88d6167 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 19 Nov 2025 15:50:03 +0300 Subject: [PATCH 30/31] parameter added for push notifications. --- lib/modules/cx_module/chat/chat_api_client.dart | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/modules/cx_module/chat/chat_api_client.dart b/lib/modules/cx_module/chat/chat_api_client.dart index c01e5d05..b859e305 100644 --- a/lib/modules/cx_module/chat/chat_api_client.dart +++ b/lib/modules/cx_module/chat/chat_api_client.dart @@ -8,6 +8,7 @@ import 'package:http/http.dart'; import 'package:path_provider/path_provider.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:http/http.dart' as http; import 'package:test_sa/modules/cx_module/chat/model/chat_attachment_model.dart'; @@ -44,6 +45,16 @@ class ChatApiClient { ChatLoginResponse? chatLoginResponse; Future getChatLoginToken(int moduleId, int requestId, String title, String employeeNumber, String assigneeEmployeeNumber) async { + String platform; + if (Platform.isIOS) { + platform = "IOS"; + } else { + if (await FirebaseNotificationManger.isGoogleServicesAvailable()) { + platform = "GOOGLE"; + } else { + platform = "HUAWEI"; + } + } Response response = await ApiClient().postJsonForResponse(URLs.chatSdkToken, { "apiKey": URLs.chatApiKey, "employeeNumber": employeeNumber, @@ -53,7 +64,11 @@ class ChatApiClient { "moduleCode": moduleId.toString(), "referenceId": requestId.toString(), // "referenceType": "ticket", - "title": title + "title": title, + "deviceToken": FirebaseNotificationManger.token, + "isHuaweiDevice": platform == "HUAWEI", + "platform": platform, + "voIPToken": null }); if (!kReleaseMode) { From 92a94577d50d2d360825f89250025fa841348dfd Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 20 Nov 2025 11:51:42 +0300 Subject: [PATCH 31/31] merge conflict resolved. --- lib/controllers/api_routes/urls.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 47183ee1..9ff0dce7 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -346,14 +346,24 @@ class URLs { //internal Audit static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById"; + static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2"; + static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43"; + static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500"; + static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502"; + static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment"; + static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem"; + static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; + static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer"; + static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer"; + static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID"; }