diff --git a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatLayout.java b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatLayout.java index ea08d835..5675095a 100644 --- a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatLayout.java +++ b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatLayout.java @@ -1,9 +1,11 @@ package com.hyphenate.easeui.modules.chat; import android.app.Activity; +import android.app.AlertDialog; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.DialogInterface; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -53,6 +55,9 @@ import com.hyphenate.easeui.modules.menu.EasePopupWindow; import com.hyphenate.easeui.modules.menu.EasePopupWindowHelper; import com.hyphenate.easeui.modules.menu.MenuItemBean; +import com.hyphenate.chat.translator.EMTranslationManager; +import com.hyphenate.chat.translator.EMTranslationMessage; +import com.hyphenate.chat.translator.EMTranslationResult; import com.hyphenate.easeui.utils.EaseCommonUtils; import com.hyphenate.easeui.utils.EaseUserUtils; import com.hyphenate.easeui.widget.EaseAlertDialog; @@ -137,6 +142,12 @@ public class EaseChatLayout extends RelativeLayout implements IChatLayout, IHand */ private boolean isNotFirstSend; + /** + * 翻译目标语言,默认英文 + */ + + private String targetLanguageCode = "en"; + public EaseChatLayout(Context context) { this(context, null); } @@ -252,6 +263,10 @@ public void loadData(String msgId) { messageListLayout.loadData(msgId); } + public void setTargetLanguageCode(String lanugageCode) { + targetLanguageCode = lanugageCode; + } + private void initTypingHandler() { typingHandler = new Handler() { @Override @@ -948,7 +963,21 @@ public boolean onMenuItemClick(MenuItemBean item) { EMLog.i(TAG,"currentMsgId = "+message.getMsgId() + " timestamp = "+message.getMsgTime()); }else if(itemId == R.id.action_chat_recall) { recallMessage(message); + }else if(itemId == R.id.action_chat_translate) { + messageListLayout.translateMessage(message, targetLanguageCode); + }else if(itemId == R.id.action_chat_reTranslate) { + new AlertDialog.Builder(getContext()) + .setTitle("Using Translate") + .setMessage("Each translation can be retranslated only once. The translation provided is for reference only.") + .setPositiveButton("OK", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + messageListLayout.reTranslate(message, targetLanguageCode); + } + }).show(); + }else if(itemId == R.id.action_chat_hide) { + messageListLayout.hideMessage(message); } + return true; } return false; @@ -965,15 +994,45 @@ public void onDismiss(PopupWindow menu) { menuHelper.show(this, v); } + private boolean showTranslation(EMMessage message) { + if(!EMTranslationManager.getInstance().isInitialized()) + return false; + + if(!EMTranslationManager.getInstance().isTranslationPresentForMessage(message.getMsgId())) + return true; + + EMTranslationResult result = EMTranslationManager.getInstance().getTranslationMessage(message.getMsgId()); + if(result.getShowTranslation()) + return false; + + return true; + } + private void setMenuByMsgType(EMMessage message) { EMMessage.Type type = message.getType(); menuHelper.findItemVisible(R.id.action_chat_copy, false); menuHelper.findItemVisible(R.id.action_chat_recall, false); + menuHelper.findItemVisible(R.id.action_chat_translate, false); + menuHelper.findItemVisible(R.id.action_chat_reTranslate, false); + menuHelper.findItemVisible(R.id.action_chat_hide, false); + menuHelper.findItem(R.id.action_chat_delete).setTitle(getContext().getString(R.string.action_delete)); switch (type) { case TXT: - menuHelper.findItemVisible(R.id.action_chat_copy, true); - menuHelper.findItemVisible(R.id.action_chat_recall, true); + if(message instanceof EMTranslationMessage) { + menuHelper.findItemVisible(R.id.action_chat_delete, false); + + if(((EMTranslationMessage) message).isReTranslatable()) + menuHelper.findItemVisible(R.id.action_chat_reTranslate, true); + + menuHelper.findItemVisible(R.id.action_chat_hide, true); + } else { + menuHelper.findItemVisible(R.id.action_chat_copy, true); + menuHelper.findItemVisible(R.id.action_chat_recall, true); + + if (showTranslation(message)) + menuHelper.findItemVisible(R.id.action_chat_translate, true); + } break; case LOCATION: case FILE: diff --git a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatMessageListLayout.java b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatMessageListLayout.java index 82a4cafa..dcd8eaaf 100644 --- a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatMessageListLayout.java +++ b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/EaseChatMessageListLayout.java @@ -19,10 +19,12 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import com.hyphenate.EMValueCallBack; import com.hyphenate.chat.EMChatRoom; import com.hyphenate.chat.EMClient; import com.hyphenate.chat.EMConversation; import com.hyphenate.chat.EMMessage; +import com.hyphenate.chat.EMTextMessageBody; import com.hyphenate.easeui.R; import com.hyphenate.easeui.adapter.EaseMessageAdapter; import com.hyphenate.easeui.interfaces.MessageListItemClickListener; @@ -36,6 +38,9 @@ import com.hyphenate.easeui.modules.chat.presenter.EaseChatMessagePresenter; import com.hyphenate.easeui.modules.chat.presenter.EaseChatMessagePresenterImpl; import com.hyphenate.easeui.modules.chat.presenter.IChatMessageListView; +import com.hyphenate.chat.translator.EMTranslationManager; +import com.hyphenate.chat.translator.EMTranslationMessage; +import com.hyphenate.chat.translator.EMTranslationResult; import com.hyphenate.easeui.utils.EaseCommonUtils; import java.util.List; @@ -602,6 +607,7 @@ public void removeMessage(EMMessage message) { return; } conversation.removeMessage(message.getMsgId()); + EMTranslationManager.getInstance().removeTranslationByMsgId(message.getMsgId()); runOnUi(()-> { if(presenter.isActive()) { List messages = messageAdapter.getData(); @@ -746,6 +752,61 @@ public void removeRVItemDecoration(@NonNull RecyclerView.ItemDecoration decor) { rvList.removeItemDecoration(decor); } + public void translateMessage(EMMessage message, String languageCode) { + EMTextMessageBody body = (EMTextMessageBody) message.getBody(); + if(body == null) + return; + + EMTranslationManager.getInstance().translate(message.getMsgId(), + message.conversationId(), + body.getMessage(), + languageCode, + new EMValueCallBack() { + @Override + public void onSuccess(EMTranslationResult result) { + if(message == null || messageAdapter.getData() == null) { + return; + } + runOnUi(()-> { + if(presenter.isActive()) { + List messages = messageAdapter.getData(); + int position = messages.lastIndexOf(message); + if(position != -1) { + EMTranslationMessage translationMessage = EMTranslationMessage.createMessage(message, result); + message.setSubMessage(translationMessage); + messageAdapter.notifyItemChanged(position); + } + } + }); + } + @Override + public void onError(int errorCode, String errorText) { + //not used here + } + }); + } + + public void hideMessage(EMMessage message) { + EMTranslationMessage translationMessage = (EMTranslationMessage) message; + EMMessage parent = translationMessage.getParent(); + translationMessage.hide(); + parent.setSubMessage(null); + + int position = messageAdapter.getData().lastIndexOf(parent); + if(position != -1) { + messageAdapter.notifyItemChanged(position); + } + + } + + public void reTranslate(EMMessage message, String languageCode) { + EMTranslationMessage translationMessage = (EMTranslationMessage) message; + EMMessage parent = translationMessage.getParent(); + translationMessage.clearParent();; + parent.setSubMessage(null); + translateMessage(parent, languageCode); + } + /** * 是否有新的消息 * 判断依据为:数据库中最新的一条数据的时间戳是否大于页面上的最新一条数据的时间戳 diff --git a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/presenter/EaseChatMessagePresenterImpl.java b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/presenter/EaseChatMessagePresenterImpl.java index 3831b1f8..c203574e 100644 --- a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/presenter/EaseChatMessagePresenterImpl.java +++ b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/chat/presenter/EaseChatMessagePresenterImpl.java @@ -8,6 +8,9 @@ import com.hyphenate.chat.EMConversation; import com.hyphenate.chat.EMCursorResult; import com.hyphenate.chat.EMMessage; +import com.hyphenate.chat.translator.EMTranslationManager; +import com.hyphenate.chat.translator.EMTranslationMessage; +import com.hyphenate.chat.translator.EMTranslationResult; import java.util.List; @@ -215,16 +218,26 @@ public boolean isMessageId(String msgId) { /** * Check message's status, if is not success or fail, set to {@link com.hyphenate.chat.EMMessage.Status#FAIL} + * Also add translation messages if avaliable * @param messages */ private void checkMessageStatus(List messages) { if(messages == null || messages.isEmpty()) { return; } + for (EMMessage message : messages) { if(message.status() != EMMessage.Status.SUCCESS && message.status() != EMMessage.Status.FAIL) { message.setStatus(EMMessage.Status.FAIL); } + + if(EMTranslationManager.getInstance().isTranslationPresentForMessage(message.getMsgId())) { + EMTranslationResult result = EMTranslationManager.getInstance().getTranslationMessage(message.getMsgId()); + if(result.getShowTranslation()) { + EMTranslationMessage translationMessage = EMTranslationMessage.createMessage(message, result); + message.setSubMessage(translationMessage); + } + } } } } diff --git a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/conversation/presenter/EaseConversationPresenterImpl.java b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/conversation/presenter/EaseConversationPresenterImpl.java index adbf9043..4d03a8fe 100644 --- a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/conversation/presenter/EaseConversationPresenterImpl.java +++ b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/conversation/presenter/EaseConversationPresenterImpl.java @@ -4,6 +4,8 @@ import com.hyphenate.chat.EMClient; import com.hyphenate.chat.EMConversation; +import com.hyphenate.chat.translator.EMTranslationManager; +import com.hyphenate.chat.translator.EMTranslationResult; import com.hyphenate.easeui.constants.EaseConstant; import com.hyphenate.easeui.modules.conversation.model.EaseConversationInfo; import com.hyphenate.easeui.utils.EaseCommonUtils; @@ -170,6 +172,7 @@ public void deleteConversation(int position, EaseConversationInfo info) { if(!isDestroy()) { if(isDelete) { mView.deleteItem(position); + EMTranslationManager.getInstance().removeTranslationByConversationId(((EMConversation) info.getInfo()).conversationId()); }else { mView.deleteItemFail(position, ""); } diff --git a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/menu/EasePopupWindowHelper.java b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/menu/EasePopupWindowHelper.java index b50b35db..d7e78a11 100644 --- a/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/menu/EasePopupWindowHelper.java +++ b/ease-im-kit/src/main/java/com/hyphenate/easeui/modules/menu/EasePopupWindowHelper.java @@ -30,9 +30,9 @@ import java.util.Map; public class EasePopupWindowHelper { - private static final int[] itemIds = {R.id.action_chat_copy, R.id.action_chat_delete, R.id.action_chat_recall}; - private static final int[] titles = {R.string.action_copy, R.string.action_delete, R.string.action_recall}; - private static final int[] icons = {R.drawable.ease_chat_item_menu_copy, R.drawable.ease_chat_item_menu_delete, R.drawable.ease_chat_item_menu_recall}; + private static final int[] itemIds = {R.id.action_chat_copy, R.id.action_chat_delete, R.id.action_chat_recall, R.id.action_chat_translate, R.id.action_chat_reTranslate, R.id.action_chat_hide}; + private static final int[] titles = {R.string.action_copy, R.string.action_delete, R.string.action_recall, R.string.action_translate, R.string.action_reTranslate, R.string.action_hide }; + private static final int[] icons = {R.drawable.ease_chat_item_menu_copy, R.drawable.ease_chat_item_menu_delete, R.drawable.ease_chat_item_menu_recall, R.drawable.ease_chat_item_menu_recall, R.drawable.ease_chat_item_menu_recall, R.drawable.ease_chat_item_menu_recall}; private static final int SPAN_COUNT = 5; private EasePopupWindow pMenu; private List menuItems = new ArrayList<>(); diff --git a/ease-im-kit/src/main/java/com/hyphenate/easeui/widget/chatrow/EaseChatRowText.java b/ease-im-kit/src/main/java/com/hyphenate/easeui/widget/chatrow/EaseChatRowText.java index 1780a94f..a62451fd 100644 --- a/ease-im-kit/src/main/java/com/hyphenate/easeui/widget/chatrow/EaseChatRowText.java +++ b/ease-im-kit/src/main/java/com/hyphenate/easeui/widget/chatrow/EaseChatRowText.java @@ -5,6 +5,7 @@ import android.text.Spanned; import android.text.style.URLSpan; import android.view.View; +import android.widget.ImageView; import android.widget.TextView; import android.widget.TextView.BufferType; @@ -12,10 +13,16 @@ import com.hyphenate.chat.EMTextMessageBody; import com.hyphenate.easeui.R; import com.hyphenate.easeui.manager.EaseDingMessageHelper; +import com.hyphenate.chat.translator.EMTranslationMessage; +import com.hyphenate.chat.translator.EMTranslationResult; import com.hyphenate.easeui.utils.EaseSmileUtils; public class EaseChatRowText extends EaseChatRow { private TextView contentView; + private TextView translationContentView; + private ImageView translationStatusView; + private View translationContainer; + public EaseChatRowText(Context context, boolean isSender) { super(context, isSender); @@ -27,13 +34,16 @@ public EaseChatRowText(Context context, EMMessage message, int position, Object @Override protected void onInflateView() { - inflater.inflate(!showSenderType ? R.layout.ease_row_received_message + inflater.inflate(!showSenderType ? R.layout.ease_row_received_message : R.layout.ease_row_sent_message, this); } @Override protected void onFindViewById() { - contentView = (TextView) findViewById(R.id.tv_chatcontent); + contentView = (TextView) findViewById(R.id.tv_chatcontent); + translationContentView = (TextView) findViewById(R.id.tv_subContent); + translationStatusView = (ImageView) findViewById(R.id.translation_status); + translationContainer = (View) findViewById(R.id.subBubble); } @Override @@ -53,7 +63,31 @@ public boolean onLongClick(View v) { return false; } }); + replaceSpan(); + + if(message.subMessage() != null) { + translationContainer.setVisibility(View.VISIBLE); + EMTranslationResult result = ((EMTranslationMessage)message.subMessage()).getTranslationResult(); + translationContentView.setText(result.getTranslatedText()); + translationContentView.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + contentView.setTag(R.id.action_chat_long_click,true); + if (itemClickListener != null) { + return itemClickListener.onBubbleLongClick(v, message.subMessage()); + } + return false; + } + }); + if(result.isSuccess()) + translationStatusView.setImageResource(R.drawable.translation_success); + else + translationStatusView.setImageResource(R.drawable.translation_failure); + } else { + translationContainer.setVisibility(View.GONE); + } + } } diff --git a/ease-im-kit/src/main/res/drawable-xhdpi/translation_failure.png b/ease-im-kit/src/main/res/drawable-xhdpi/translation_failure.png new file mode 100644 index 00000000..945deb0e Binary files /dev/null and b/ease-im-kit/src/main/res/drawable-xhdpi/translation_failure.png differ diff --git a/ease-im-kit/src/main/res/drawable-xhdpi/translation_success.png b/ease-im-kit/src/main/res/drawable-xhdpi/translation_success.png new file mode 100644 index 00000000..bd6db633 Binary files /dev/null and b/ease-im-kit/src/main/res/drawable-xhdpi/translation_success.png differ diff --git a/ease-im-kit/src/main/res/layout/ease_row_received_message.xml b/ease-im-kit/src/main/res/layout/ease_row_received_message.xml index 715e1cde..1cb78f93 100644 --- a/ease-im-kit/src/main/res/layout/ease_row_received_message.xml +++ b/ease-im-kit/src/main/res/layout/ease_row_received_message.xml @@ -60,5 +60,37 @@ android:layout_toRightOf="@id/iv_userhead" android:visibility="gone" /> + + + + + + \ No newline at end of file diff --git a/ease-im-kit/src/main/res/layout/ease_row_sent_message.xml b/ease-im-kit/src/main/res/layout/ease_row_sent_message.xml index 217535a0..974d6137 100644 --- a/ease-im-kit/src/main/res/layout/ease_row_sent_message.xml +++ b/ease-im-kit/src/main/res/layout/ease_row_sent_message.xml @@ -108,5 +108,34 @@ android:layout_toLeftOf="@id/iv_userhead" android:visibility="gone" /> + + + + + + \ No newline at end of file diff --git a/ease-im-kit/src/main/res/values/ease_ids.xml b/ease-im-kit/src/main/res/values/ease_ids.xml index ace580aa..93397073 100644 --- a/ease-im-kit/src/main/res/values/ease_ids.xml +++ b/ease-im-kit/src/main/res/values/ease_ids.xml @@ -12,6 +12,12 @@ + + + + + + diff --git a/ease-im-kit/src/main/res/values/ease_strings.xml b/ease-im-kit/src/main/res/values/ease_strings.xml index 67655f8d..545b0800 100644 --- a/ease-im-kit/src/main/res/values/ease_strings.xml +++ b/ease-im-kit/src/main/res/values/ease_strings.xml @@ -155,5 +155,9 @@ 多选 删除语音 删除视频 + 翻译 + 重译 + 隐藏 +