import 'package:cached_network_image/cached_network_image.dart'; import 'package:chat/chat/record_view.dart'; import 'package:chat/data/UserData.dart'; import 'package:chat/data/constants.dart'; import 'package:chat/data/robot_chat_mgr.dart'; import 'package:chat/generated/i18n.dart'; import 'package:chat/utils/CustomUI.dart'; import 'package:chat/utils/keyboard_utils.dart'; import 'package:chat/utils/net_state_widget.dart'; import 'package:chat/utils/screen.dart'; import 'package:chat/utils/sound_util.dart'; import 'package:chat/utils/upload_util.dart'; import 'package:chat/utils/video_anim.dart'; import 'package:chat/utils/wpop/w_popup_menu.dart'; import 'package:flutter/material.dart'; import 'package:chat/utils/PopUpMenu.dart' as myPop; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; //import 'package:menu/menu.dart'; import 'package:oktoast/oktoast.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../r.dart'; const Color SendMsgBg = Color(0xFFD4F0FF); class TranslateRobotPage extends StatefulWidget { @override _TranslateRobotPageState createState() => _TranslateRobotPageState(); } class _TranslateRobotPageState extends State { final TextEditingController _textCtrl = TextEditingController(); FocusNode editFocus = FocusNode(); bool _isComposingMessage = false; int curToLang = 1; int curSourceLang = UserData().language; ScrollController _scrollCtrl = ScrollController(); int curKeyboardIndex = -1; List langList; double keyboardHeight; KeyboardBloc _bloc = KeyboardBloc(); @override void initState() { super.initState(); getKeyboardHeight(); _bloc.start(); } @override void didChangeDependencies() { super.didChangeDependencies(); langList = [ I18n.of(context).english, I18n.of(context).Vietnamese, I18n.of(context).traditional_Chinese, I18n.of(context).Simplified_Chinese, I18n.of(context).Korean, I18n.of(context).Japanese, ]; } @override void dispose() { editFocus?.unfocus(); super.dispose(); } getKeyboardHeight() async { var sp = await SharedPreferences.getInstance(); keyboardHeight = sp.getDouble(Constants.KeyboardHeight); if (keyboardHeight == null || keyboardHeight < 100) { keyboardHeight = 280; } } hideKeyBoard() { setState(() { curKeyboardIndex = -1; }); } _langPopMenu(bool isSource) { var curIndex = isSource ? curSourceLang : curToLang; return myPop.PopupMenuButton( child: Container( child: Row( children: [ fixedText(langList[curIndex], color: Colors.black, fontSize: 16), Icon(IconData(0xe63b, fontFamily: Constants.IconFontFamily), color: Colors.grey) ], ), ), offset: Offset(0, 100), onSelected: (int index) { if (curIndex != index) { if (isSource) { curSourceLang = index; } else { curToLang = index; } print('更换翻译语言'); setState(() {}); } }, itemBuilder: (BuildContext context) { return List>.generate(langList.length, (int i) { return myPop.PopupMenuItem( child: Container( alignment: Alignment.center, color: Colors.white, padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10), child: Text(langList[i], textScaleFactor: 1.0, maxLines: 1, style: TextStyle( color: i == curIndex ? Colors.blueAccent : Color(AppColors.AppBarColor), fontSize: 14)), ), value: i, ); }); }); } @override Widget build(BuildContext context) { return GestureDetector( onTap: hideKeyBoard, child: Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( title: Row( mainAxisSize: MainAxisSize.min, children: [ _langPopMenu(true), SizedBox(width: 10), InkWell( onTap: () { var temp = curSourceLang; curSourceLang = curToLang; curToLang = temp; setState(() {}); }, child: Container( child: Icon( IconData(0xe669, fontFamily: Constants.IconFontFamily), size: 12, ), padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5), ), ), SizedBox(width: 20), _langPopMenu(false), ], ), centerTitle: true, leading: CustomUI.buildCustomLeading(context), ), body: SafeArea( child: Column( children: [ NetStateWidget(), Expanded(child: _buildMessageList()), _inputBar(), ], )), )); } Widget _buildMessageList() { return Container( alignment: Alignment.topCenter, child: ListView.builder( reverse: true, shrinkWrap: true, itemCount: RobotChatMgr().robotChatList.length, controller: _scrollCtrl, padding: EdgeInsets.all(8.0), itemBuilder: _buildItem, ), ); } Widget _buildItem(BuildContext context, int index) { var chat = RobotChatMgr().robotChatList[index]; List actionsFunc = []; List actions = [I18n.of(context).delete]; if (chat.type == 0) { actions.add(I18n.of(context).copy); } actionsFunc.add(() { RobotChatMgr().robotChatList.remove(chat); setState(() {}); }); actionsFunc.add(() { ClipboardData clipboardData = ClipboardData(text: chat.msgContent); Clipboard.setData(clipboardData); }); return WPopupMenu( child: chat.isMe ? _buildMyMsg(chat) : _buildRobotMsg(chat), actions: actions, menuWidth: 200, onValueChanged: (int value) { print('选择的是$value个菜单'); if (value >= 0 && value < actionsFunc.length) { actionsFunc[value](); } }, ); } Widget _buildMyMsg(RobotChatModel msg) { bool hasHeadImg = true; if (UserData().basicInfo.headimgurl == null || UserData().basicInfo.headimgurl.length == 0) { hasHeadImg = false; } return Container( width: Screen.width, margin: const EdgeInsets.symmetric(vertical: 10.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.end, children: [ msg.type == 0 ? _textMsg(msg) : _soundMsg(msg), SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ ClipRRect( borderRadius: BorderRadius.circular(8), child: hasHeadImg ? CachedNetworkImage( imageUrl: UserData().basicInfo.headimgurl, width: 40, height: 40, ) : SizedBox( width: 40, height: 40, child: Image.asset(R.assetsImagesDefaultNorAvatar))), ], ) ])); } Widget _soundMsg(RobotChatModel msg) { double time = msg.extraInfo / 1000; if (time > 60) { time = 60.0; } bool isPlaying = false; var soundPath = msg.msgContent; isPlaying = SoundUtils().isPlaying(soundPath); return GestureDetector( child: Container( width: 120, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Container( alignment: Alignment.center, padding: EdgeInsets.only(bottom: 2), margin: EdgeInsets.only(right: 10), width: 25.5, height: 25.5, decoration: BoxDecoration( border: Border.all(color: const Color(0xFF1B92C7), width: 0.5), color: const Color(0xFF04A4FE), shape: BoxShape.circle), child: Icon( IconData(isPlaying ? 0xe652 : 0xe653, fontFamily: Constants.IconFontFamily), size: isPlaying ? 15 : 18, color: Colors.white, ), ), isPlaying ? Stack( children: [ Container( height: 18, width: 19, ), Positioned( bottom: 0, child: VideoAnim( begin: 18, start: 0.444, end: 4.5, )), Positioned( left: 7, bottom: 0, child: VideoAnim( begin: 4.5, end: 18, )), Positioned( left: 14, bottom: 0, child: VideoAnim( begin: 18, end: 4.5, )) ], ) : Stack( children: [ Container( height: 18, width: 19, ), Positioned( bottom: 0, child: CustomUI.buildAudioContaniner(12)), Positioned( left: 7, bottom: 0, child: CustomUI.buildAudioContaniner(4.5)), Positioned( left: 14, bottom: 0, child: CustomUI.buildAudioContaniner(18)) ], ), Expanded(child: SizedBox()), fixedText(time.toStringAsFixed(0), color: Constants.BlackTextColor, fontSize: 16) ], ), padding: EdgeInsets.symmetric(horizontal: 15, vertical: 12), decoration: BoxDecoration( color: SendMsgBg, border: Border.all(color: Color(0xFFB9CBD7), width: 0.6), borderRadius: BorderRadius.all(Radius.circular(8))), ), onTap: () async { print('播放状态 : $isPlaying'); if (isPlaying) { SoundUtils().pause(); } else { SoundUtils().play(soundPath, onPlayed: () { if (mounted) { setState(() {}); } }, complete: () { if (mounted) { setState(() {}); } }); } }, ); } Widget _textMsg(RobotChatModel msg) { return Container( constraints: BoxConstraints(maxWidth: Screen.width - 120), child: fixedText(msg.msgContent, fontSize: 15, color: Colors.black), padding: EdgeInsets.symmetric(horizontal: 9, vertical: 10.5), decoration: BoxDecoration( color: SendMsgBg, border: Border.all(color: Color(0xFFB9CBD7), width: 0.6), borderRadius: BorderRadius.all(Radius.circular(8))), ); } Widget _buildRobotMsg(RobotChatModel msg) { return Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: const EdgeInsets.only(right: 8.0), child: ClipRRect( borderRadius: BorderRadius.circular(8), child: SizedBox( width: 40, height: 40, child: Image.asset(R.assetsImagesRobot))), ), ///todo Container( constraints: BoxConstraints(maxWidth: Screen.width - 120), padding: EdgeInsets.symmetric(horizontal: 9, vertical: 10.5), child: fixedText(msg.msgContent), decoration: BoxDecoration( border: Border.all(color: Color(0xFFDCDCDC), width: 0.5), color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(8))), ) ]); } //输入框 _inputBar() { if (curKeyboardIndex != 0) { if (editFocus.hasFocus) { editFocus.unfocus(); } } else { if (!editFocus.hasFocus) { FocusScope.of(context).requestFocus(editFocus); } } return GestureDetector( onTap: () { print('other keyboard'); }, child: Container( width: Screen.width, color: Colors.white, child: Column( children: [ Container( padding: EdgeInsets.symmetric(horizontal: 7, vertical: 7), alignment: Alignment.topCenter, decoration: BoxDecoration( color: Colors.white, border: Border(top: BorderSide(color: Color(0xFFDFDFDF)))), child: Row( children: [ //输入框 Flexible( child: Container( child: TextField( keyboardAppearance: Brightness.light, onChanged: (String messageText) { setState(() { _isComposingMessage = _textCtrl.text.length > 0; }); }, autofocus: false, style: TextStyle( fontSize: ScreenUtil().setSp(16), textBaseline: TextBaseline.alphabetic), maxLines: 3, minLines: 1, controller: _textCtrl, textInputAction: TextInputAction.newline, inputFormatters: [ LengthLimitingTextInputFormatter(600) //限制长度 ], onSubmitted: _textMessageSubmitted, focusNode: editFocus, onTap: () { setState(() { curKeyboardIndex = 0; }); }, decoration: InputDecoration( hintText: I18n.of(context).input_content, hintStyle: TextStyle( color: const Color(0xffBDBDBD), fontSize: 16), border: null, contentPadding: EdgeInsets.only( left: 5, right: 5, top: 8, bottom: 8), ), ), ), ), SizedBox(width: 10), _isComposingMessage ? InkWell( child: Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: Icon( Icons.send, color: Color(0xFF087FF3), size: 28, )), onTap: _sendTextMessage) : InkWell( child: Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: Icon( IconData(0xe64f, fontFamily: Constants.IconFontFamily), color: curKeyboardIndex == 1 ? Color(0xFF0A80F3) : Color(0xFF797A7C), size: 28, )), onTap: () { if (curKeyboardIndex == 1) { setState(() { curKeyboardIndex = 0; }); } else { setState(() { curKeyboardIndex = 1; }); } }) ], ), ), Divider(height: 1, color: const Color(0xffE0E0E0)), StreamBuilder( stream: _bloc.stream, builder: (BuildContext context, AsyncSnapshot snapshot) { double keyHeight = MediaQuery.of(context).viewInsets.bottom; if (keyHeight > 10) { keyboardHeight = keyHeight; UserData().setKeyboardHeight(keyHeight); } return Container( width: double.infinity, color: Colors.white, height: curKeyboardIndex == 0 || curKeyboardIndex == 1 ? keyboardHeight : 0, child: RecordView( keyboardHeight: keyboardHeight, sendMsg: _sendSoundMsg)); }, ) ], ))); } showKeyBoard() { setState(() { curKeyboardIndex = 0; }); editFocus.requestFocus(); //SystemChannels.textInput.invokeMethod('TextInput.show'); } _sendSoundMsg(String soundPath, int duration) { print('上传文件'); RobotChatModel model = RobotChatModel( msgContent: soundPath, extraInfo: duration, isMe: true, type: 1); RobotChatMgr().addSource(model); setState(() {}); UploadUtil() .commitTranslateSource(2, curSourceLang, curToLang, soundPath) .then((tranStr) { if (tranStr == null) { showToast(I18n.of(context).translate_fail); return; } RobotChatModel model = RobotChatModel(msgContent: tranStr, isMe: false); RobotChatMgr().addSource(model); if (mounted) { setState(() {}); } }); } _sendTextMessage() { if (!checkMessage()) { return; } var sendStr = _textCtrl.text; RobotChatModel model = RobotChatModel(msgContent: sendStr, isMe: true); RobotChatMgr().addSource(model); setState(() {}); UploadUtil() .commitTranslateSource(1, curSourceLang, curToLang, sendStr) .then((tranStr) { if (tranStr == null) { showToast(I18n.of(context).translate_fail); return; } RobotChatModel model = RobotChatModel(msgContent: tranStr, isMe: false); RobotChatMgr().addSource(model); if (mounted) { setState(() {}); } }); _textCtrl.clear(); setState(() { _isComposingMessage = false; }); } bool checkMessage() { if (_textCtrl.text.length == 0) { showToast(I18n.of(context).msg_not); return false; } return true; } Future _textMessageSubmitted(String text) async { _sendTextMessage(); } }