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: