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'; enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } class ChatPage extends StatefulWidget { ChatPage({Key? key}) : super(key: key); @override _ChatPageState createState() { return _ChatPageState(); } } class _ChatPageState extends State { bool isSender = false; bool isAudioRecording = false; String? recordedFilePath; 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(); } @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 (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. ).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(), // ), 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), ), ), ], )), ], ), ); } }