import 'dart:io'; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/core/viewModels/feedback/feedback_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; import 'package:diplomaticquarterapp/services/robo_search/event_provider.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/avatar/large_avatar.dart'; import 'package:diplomaticquarterapp/widgets/bottom_options/BottomSheet.dart'; import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; import 'package:diplomaticquarterapp/widgets/data_display/medical/doctor_card.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; import 'package:diplomaticquarterapp/widgets/dialogs/radio_selection_dialog.dart'; import 'package:diplomaticquarterapp/widgets/others/StarRating.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/others/floating_button_search.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:speech_to_text/speech_recognition_error.dart'; import 'package:speech_to_text/speech_to_text.dart' as stt; class SendFeedbackPage extends StatefulWidget { final AppoitmentAllHistoryResultList appointment; final MessageType messageType; const SendFeedbackPage({Key key, this.appointment, this.messageType = MessageType.NON}) : super(key: key); @override _SendFeedbackPageState createState() => _SendFeedbackPageState(); } class _SendFeedbackPageState extends State { TextEditingController titleController = TextEditingController(); TextEditingController messageController = TextEditingController(); List images = []; String title; AppoitmentAllHistoryResultList appointHistory; bool isShowListAppointHistory = true; String message; final formKey = GlobalKey(); MessageType messageType = MessageType.NON; var _currentLocaleId; stt.SpeechToText speech = stt.SpeechToText(); var reconizedWord; int selectedStatusIndex = 5; var event = RobotProvider(); List appoList = []; String getSelected(BuildContext context) { switch (messageType) { case MessageType.ComplaintOnAnAppointment: return TranslationBase.of(context).complainAppo; break; case MessageType.ComplaintWithoutAppointment: return TranslationBase.of(context).complainWithoutAppo; break; case MessageType.Question: return TranslationBase.of(context).question; break; case MessageType.Compliment: return TranslationBase.of(context).compliment; break; case MessageType.Suggestion: return TranslationBase.of(context).suggestion; break; case MessageType.NON: return TranslationBase.of(context).notClassified; break; } return TranslationBase.of(context).notClassified; } setMessageType(MessageType messageType) { setState(() { this.messageType = messageType; this.appointHistory = widget.appointment; }); } @override void initState() { setState(() { this.messageType = widget.messageType; this.appointHistory = widget.appointment; }); requestPermissions(); super.initState(); } @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); return BaseView( allowAny: true, builder: (_, model, widget) => AppScaffold( baseViewModel: model, isShowDecPage: false, body: Column( children: [ Expanded( child: SingleChildScrollView( physics: BouncingScrollPhysics(), padding: EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), child: Form( key: formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( TranslationBase.of(context).likeToHear, // textAlign: TextAlign.center, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.64, height: 23 / 16), ), SizedBox(height: 21), InkWell( onTap: () { confirmBox(model); }, child: Container( padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15), alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all( color: Color(0xffefefef), width: 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( getSelected(context), style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, letterSpacing: -0.48, color: Color(0xff2B353E), ), ), Icon( Icons.keyboard_arrow_down, size: 22, color: Colors.grey, ) ], ), ), ), SizedBox(height: 12), if (appointHistory != null && messageType == MessageType.ComplaintOnAnAppointment) InkWell( onTap: () { setState(() { isShowListAppointHistory = true; }); }, child: DoctorCard( onTap: null, isInOutPatient: appointHistory.isInOutPatient, name: appointHistory.doctorTitle + " " + appointHistory.doctorNameObj, // billNo: _appointmentResult.invoiceNo, profileUrl: appointHistory.doctorImageURL, subName: appointHistory.projectName, isLiveCareAppointment: appointHistory.isLiveCareAppointment, date: DateUtil.convertStringToDate(appointHistory.appointmentDate), rating: appointHistory.actualDoctorRate + 0.0, appointmentTime: appointHistory.startTime.substring(0, 5), ), ), SizedBox(height: 12), if (messageType == MessageType.ComplaintOnAnAppointment && appoList.length != 0 && isShowListAppointHistory) Container( margin: EdgeInsets.only(bottom: 10.0), height: appoList.length > 2 ? MediaQuery.of(context).size.height * 0.35 : MediaQuery.of(context).size.height * 0.17, child: ListView.separated( itemCount: appoList.length, separatorBuilder: (ctx, index) => SizedBox(height: 12), itemBuilder: (context, index) => InkWell( onTap: () { setState(() { appointHistory = appoList[index]; isShowListAppointHistory = false; }); }, child: DoctorCard( onTap: null, isInOutPatient: appoList[index].isInOutPatient, name: appoList[index].doctorTitle + " " + appoList[index].doctorNameObj, profileUrl: appoList[index].doctorImageURL, subName: appoList[index].projectName, isLiveCareAppointment: appoList[index].isLiveCareAppointment, date: DateUtil.convertStringToDate(appoList[index].appointmentDate), rating: appoList[index].actualDoctorRate + 0.0, appointmentTime: appoList[index].startTime.substring(0, 5), ), ), ), ), inputWidget(TranslationBase.of(context).subject, "", titleController), SizedBox(height: 12), inputWidget(TranslationBase.of(context).message, "", messageController, lines: 11, suffixTap: () { openSpeechReco(); }), SizedBox(height: 12), InkWell( onTap: () { ImageOptions.showImageOptions(context, (String image, File file) { setState(() { images.add(image); }); }); }, child: Container( padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15), alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all( color: Color(0xffefefef), width: 1, ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.attach_file, color: Color(0xff2B353E), ), Text( TranslationBase.of(context).selectAttachment, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.64, height: 23 / 16), ), ], ), ), ), ...List.generate( images.length, (index) => Container( margin: EdgeInsets.all(10), padding: EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(FontAwesomeIcons.paperclip), SizedBox( width: 8, ), Texts( 'image ${index + 1}.png', ), ], ), InkWell( onTap: () { setState(() { images.remove(images[index]); }); }, child: Icon( FontAwesomeIcons.trashAlt, color: Colors.red[300], )) ], ), )), ], ), ), ), ), Container( color: Colors.white, padding: EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), child: DefaultButton( TranslationBase.of(context).send, (titleController.text.toString().isEmpty || messageController.text.toString().isEmpty) ? null : () { final form = formKey.currentState; if (form.validate()) { GifLoaderDialogUtils.showMyDialog(context); model .sendCOCItem( title: titleController.text, attachment: images.length > 0 ? images[0] : "", details: messageController.text, cOCTypeName: getCOCName(), appointHistory: messageType == MessageType.ComplaintOnAnAppointment ? appointHistory : null) .then((value) { if (value) { setState(() { titleController.text = ""; messageController.text = ""; images = []; }); selectedStatusIndex = 5; setMessageType(MessageType.NON); GifLoaderDialogUtils.hideDialog(context); AppToast.showSuccessToast(message: TranslationBase.of(context).yourFeedback); } else { AppToast.showErrorToast(message: model.error); GifLoaderDialogUtils.hideDialog(context); } }); } }, color: Color(0xffD02127), textColor: (titleController.text.toString().isEmpty || messageController.text.toString().isEmpty) ? Color(0xff000000) : Colors.white, disabledColor: Color(0xffEAEAEA), ), ), ], ), ), ); } Widget inputWidget(String _labelText, String _hintText, TextEditingController _controller, {VoidCallback suffixTap, bool isEnable = true, bool hasSelection = false, int lines}) { return Container( padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15), alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all( color: Color(0xffefefef), width: 1, ), ), child: InkWell( onTap: hasSelection ? () {} : null, child: Row( children: [ Expanded( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _labelText, style: TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44, ), ), TextField( enabled: isEnable, scrollPadding: EdgeInsets.zero, keyboardType: TextInputType.text, controller: _controller, maxLines: lines, onChanged: (value) => {setState(() {})}, style: TextStyle( fontSize: 14, height: 21 / 14, fontWeight: FontWeight.w400, color: Color(0xff2B353E), letterSpacing: -0.44, ), decoration: InputDecoration( isDense: true, hintText: _hintText, hintStyle: TextStyle( fontSize: 14, height: 21 / 14, fontWeight: FontWeight.w400, color: Color(0xff575757), letterSpacing: -0.56, ), suffixIconConstraints: BoxConstraints(minWidth: 50), suffixIcon: suffixTap == null ? null : IconButton(icon: Icon(Icons.mic, color: Color(0xff2E303A)), onPressed: suffixTap), contentPadding: EdgeInsets.zero, border: InputBorder.none, focusedBorder: InputBorder.none, enabledBorder: InputBorder.none, ), ), ], ), ), if (hasSelection) Icon(Icons.keyboard_arrow_down_outlined), ], ), ), ); } String getCOCName() { switch (messageType) { case MessageType.ComplaintOnAnAppointment: return "1"; break; case MessageType.ComplaintWithoutAppointment: return "2"; break; case MessageType.Question: return "3"; break; case MessageType.Compliment: return "4"; break; case MessageType.Suggestion: return "6"; break; case MessageType.NON: return "5"; break; } return ""; } // Show Dialog function void confirmBox(FeedbackViewModel model) { DoctorsListService service = new DoctorsListService(); List list = [ RadioSelectionDialogModel(TranslationBase.of(context).notClassified, 5), RadioSelectionDialogModel(TranslationBase.of(context).complainAppo, 1), RadioSelectionDialogModel(TranslationBase.of(context).complainWithoutAppo, 2), RadioSelectionDialogModel(TranslationBase.of(context).question, 3), RadioSelectionDialogModel(TranslationBase.of(context).compliment, 4), RadioSelectionDialogModel(TranslationBase.of(context).suggestion, 6), ]; showDialog( context: context, child: RadioSelectionDialog( listData: list, selectedIndex: selectedStatusIndex, onValueSelected: (index) { selectedStatusIndex = index; if (index == 1) { messageType = MessageType.ComplaintOnAnAppointment; } else if (index == 2) { messageType = MessageType.ComplaintWithoutAppointment; } else if (index == 3) { messageType = MessageType.Question; } else if (index == 4) { messageType = MessageType.Compliment; } else if (index == 5) { messageType = MessageType.NON; } else { messageType = MessageType.Suggestion; } if (messageType == MessageType.ComplaintOnAnAppointment) { appoList.clear(); GifLoaderDialogUtils.showMyDialog(context); service.getPatientAppointmentHistory(false, context, isForCOC: true).then((res) { GifLoaderDialogUtils.hideDialog(context); setState(() { if (res['MessageStatus'] == 1) { if (res['AppoimentAllHistoryResultList'].length != 0) { res['AppoimentAllHistoryResultList'].forEach((v) { appoList.add(new AppoitmentAllHistoryResultList.fromJson(v)); }); setState(() { appointHistory = null; isShowListAppointHistory = true; }); } else {} } else {} }); }).catchError((err) { GifLoaderDialogUtils.hideDialog(context); // print(err); // AppToast.showErrorToast(message: err); // Navigator.of(context).pop(); }); } else { isShowListAppointHistory = false; } setMessageType(messageType); }, ), ); return; // todo 'sikander' remove useless code // showDialog( // context: context, // child: FeedbackTypeDialog( // messageTypeDialog: messageType, // onValueSelected: (MessageType value) { // if (value == MessageType.ComplaintOnAnAppointment) { // appoList.clear(); // GifLoaderDialogUtils.showMyDialog(context); // service.getPatientAppointmentHistory(false, context, isForCOC: true).then((res) { // GifLoaderDialogUtils.hideDialog(context); // setState(() { // if (res['MessageStatus'] == 1) { // if (res['AppoimentAllHistoryResultList'].length != 0) { // res['AppoimentAllHistoryResultList'].forEach((v) { // appoList.add(new AppoitmentAllHistoryResultList.fromJson(v)); // }); // setState(() { // appointHistory = null; // isShowListAppointHistory = true; // }); // } else {} // } else {} // }); // }).catchError((err) { // GifLoaderDialogUtils.hideDialog(context); // // print(err); // // AppToast.showErrorToast(message: err); // // Navigator.of(context).pop(); // }); // } else { // isShowListAppointHistory = false; // } // setMessageType(value); // }, // )); } openSpeechReco() async { new RoboSearch(context: context).showAlertDialog(context); _currentLocaleId = TranslationBase.of(AppGlobal.context).locale.languageCode; bool available = await speech.initialize(onStatus: statusListener, onError: errorListener); if (available) { speech.listen( onResult: resultListener, listenMode: stt.ListenMode.confirmation, localeId: _currentLocaleId == 'en' ? 'en-US' : 'ar-SA', ); } else { print("The user has denied the use of speech recognition."); } } void errorListener(SpeechRecognitionError error) { event.setValue({"searchText": 'null'}); //SpeechToText.closeAlertDialog(context); print(error); } void statusListener(String status) { reconizedWord = status == 'listening' ? 'Lisening...' : 'Sorry....'; } void requestPermissions() async { Map statuses = await [ Permission.microphone, ].request(); print(statuses); } void resultListener(result) { reconizedWord = result.recognizedWords; event.setValue({"searchText": reconizedWord}); if (result.finalResult == true) { setState(() { RoboSearch.closeAlertDialog(context); speech.stop(); messageController.text = reconizedWord + '\n'; }); } } Future initSpeechState() async { bool hasSpeech = await speech.initialize(onError: errorListener, onStatus: statusListener); print(hasSpeech); if (!mounted) return; } } // todo 'sikander' remove useless code // class FeedbackTypeDialog extends StatefulWidget { // final Function(MessageType) onValueSelected; // final MessageType messageTypeDialog; // // const FeedbackTypeDialog({Key key, this.onValueSelected, this.messageTypeDialog = MessageType.NON}) : super(key: key); // // @override // State createState() => new FeedbackTypeDialogState(); // } // // class FeedbackTypeDialogState extends State { // MessageType messageTypeDialog = MessageType.NON; // // setMessageDialogType(MessageType messageType) { // setState(() { // messageTypeDialog = messageType; // }); // } // // @override // void initState() { // messageTypeDialog = widget.messageTypeDialog; // // super.initState(); // } // // Widget build(BuildContext context) { // return BaseView( // builder: (_, model, widge) => SimpleDialog( // title: Text( // TranslationBase.of(context).messageType, // textAlign: TextAlign.center, // ), // children: [ // Container( // // padding: const EdgeInsets.all(10.0), // child: Column( // children: [ // Divider( // height: 2.5, // color: Colors.grey[500], // ), // Row( // children: [ // Expanded( // flex: 1, // child: InkWell( // onTap: () => setMessageDialogType(MessageType.NON), // child: ListTile( // title: Texts(TranslationBase.of(context).notClassified), // leading: Radio( // value: MessageType.NON, // groupValue: messageTypeDialog, // activeColor: CustomColors.accentColor, // onChanged: (MessageType value) => setMessageDialogType(value), // ), // ), // ), // ) // ], // ), // SizedBox( // height: 5.0, // ), // Row( // children: [ // Expanded( // flex: 1, // child: InkWell( // onTap: () => setMessageDialogType(MessageType.ComplaintOnAnAppointment), // child: ListTile( // title: Texts(TranslationBase.of(context).complainAppo), // leading: Radio( // value: MessageType.ComplaintOnAnAppointment, // groupValue: messageTypeDialog, // activeColor: CustomColors.accentColor, // onChanged: (MessageType value) => setMessageDialogType(value), // ), // ), // ), // ) // ], // ), // SizedBox( // height: 5.0, // ), // Row( // children: [ // Expanded( // flex: 1, // child: InkWell( // onTap: () => setMessageDialogType(MessageType.ComplaintWithoutAppointment), // child: ListTile( // title: Texts(TranslationBase.of(context).complainWithoutAppo), // leading: Radio( // value: MessageType.ComplaintWithoutAppointment, // groupValue: messageTypeDialog, // activeColor: CustomColors.accentColor, // onChanged: (MessageType value) => setMessageDialogType(value), // ), // ), // ), // ) // ], // ), // SizedBox( // height: 5.0, // ), // Row( // children: [ // Expanded( // flex: 1, // child: InkWell( // onTap: () => setMessageDialogType(MessageType.Question), // child: ListTile( // title: Texts(TranslationBase.of(context).question), // leading: Radio( // value: MessageType.Question, // groupValue: messageTypeDialog, // activeColor: CustomColors.accentColor, // onChanged: (MessageType value) => setMessageDialogType(value), // ), // ), // ), // ) // ], // ), // SizedBox( // height: 5.0, // ), // Row( // children: [ // Expanded( // flex: 1, // child: InkWell( // onTap: () => setMessageDialogType(MessageType.Compliment), // child: ListTile( // title: Texts(TranslationBase.of(context).compliment), // leading: Radio( // value: MessageType.Compliment, // groupValue: messageTypeDialog, // activeColor: CustomColors.accentColor, // onChanged: (MessageType value) => setMessageDialogType(value), // ), // ), // ), // ) // ], // ), // SizedBox( // height: 5.0, // ), // Row( // children: [ // Expanded( // flex: 1, // child: InkWell( // onTap: () => setMessageDialogType(MessageType.Suggestion), // child: ListTile( // title: Texts(TranslationBase.of(context).suggestion), // leading: Radio( // value: MessageType.Suggestion, // groupValue: messageTypeDialog, // activeColor: CustomColors.accentColor, // onChanged: (MessageType value) => setMessageDialogType(value), // ), // ), // ), // ) // ], // ), // SizedBox( // height: 5.0, // ), // Divider( // height: 2.5, // color: Colors.grey[500], // ), // SizedBox( // height: 5, // ), // Row( // // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: [ // Expanded( // flex: 1, // child: InkWell( // onTap: () { // Navigator.pop(context); // }, // child: Padding( // padding: EdgeInsets.all(8.0), // child: Container( // child: Center( // child: Texts( // TranslationBase.of(context).cancel, // color: CustomColors.accentColor, // ), // ), // ), // ), // ), // ), // Container( // width: 1, // height: 30, // color: Colors.grey[500], // ), // Expanded( // flex: 1, // child: InkWell( // onTap: () { // widget.onValueSelected(messageTypeDialog); // Navigator.pop(context); // }, // child: Padding( // padding: const EdgeInsets.all(8.0), // child: Center( // child: Texts( // TranslationBase.of(context).ok, // fontWeight: FontWeight.w400, // )), // ), // )), // ], // ) // ], // ), // ), // ], // ), // ); // } // }