初始代码

This commit is contained in:
2025-09-03 18:52:07 +08:00
parent 2d21a47e87
commit 6e3e30efa5
3249 changed files with 239147 additions and 0 deletions
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
</application>
</manifest>
@@ -0,0 +1,170 @@
package com.tencent.qcloud.tuikit.tuivoicetotextplugin;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.google.auto.service.AutoService;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.qcloud.tuicore.ServiceInitializer;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.annotations.TUIInitializerDependency;
import com.tencent.qcloud.tuicore.annotations.TUIInitializerID;
import com.tencent.qcloud.tuicore.interfaces.ITUIExtension;
import com.tencent.qcloud.tuicore.interfaces.TUIExtensionEventListener;
import com.tencent.qcloud.tuicore.interfaces.TUIExtensionInfo;
import com.tencent.qcloud.tuicore.interfaces.TUIInitializer;
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.SoundMessageBean;
import com.tencent.qcloud.tuikit.tuichat.config.classicui.TUIChatConfigClassic;
import com.tencent.qcloud.tuikit.tuichat.config.minimalistui.TUIChatConfigMinimalist;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.model.VoiceToTextProvider;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.presenter.VoiceToTextPresenter;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.widget.VoiceToTextMessageLayoutProxy;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@AutoService(TUIInitializer.class)
@TUIInitializerDependency({"TUIChat"})
@TUIInitializerID("TUIVoiceToTextPlugin")
public class TUIVoiceToTextService implements TUIInitializer, ITUIExtension {
public static final String TAG = TUIVoiceToTextService.class.getSimpleName();
private static TUIVoiceToTextService instance;
public static TUIVoiceToTextService getInstance() {
return instance;
}
private Context appContext;
private VoiceToTextMessageLayoutProxy voiceToTextMessageLayoutProxy;
@Override
public void init(Context context) {
appContext = context;
instance = this;
initExtension();
voiceToTextMessageLayoutProxy = new VoiceToTextMessageLayoutProxy();
}
private void initExtension() {
TUICore.registerExtension(TUIConstants.TUIChat.Extension.MessagePopMenu.CLASSIC_EXTENSION_ID, this);
TUICore.registerExtension(TUIConstants.TUIChat.Extension.MessagePopMenu.MINIMALIST_EXTENSION_ID, this);
TUICore.registerExtension(TUIConstants.TUIChat.Extension.MessageBottom.CLASSIC_EXTENSION_ID, this);
TUICore.registerExtension(TUIConstants.TUIChat.Extension.MessageBottom.MINIMALIST_EXTENSION_ID, this);
}
@Override
public List<TUIExtensionInfo> onGetExtension(String extensionID, Map<String, Object> param) {
if (TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessagePopMenu.CLASSIC_EXTENSION_ID)
|| TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessagePopMenu.MINIMALIST_EXTENSION_ID)) {
if (param == null || param.isEmpty()) {
return null;
}
if (TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessagePopMenu.MINIMALIST_EXTENSION_ID)) {
if (!TUIChatConfigMinimalist.isEnableConvert()) {
return null;
}
} else {
if (!TUIChatConfigClassic.isEnableConvert()) {
return null;
}
}
TUIMessageBean messageBean = (TUIMessageBean) param.get(TUIConstants.TUIChat.Extension.MessagePopMenu.MESSAGE_BEAN);
VoiceToTextPresenter presenter = new VoiceToTextPresenter();
V2TIMMessage v2TIMMessage = messageBean.getV2TIMMessage();
if (v2TIMMessage == null) {
return null;
}
if ((V2TIMMessage.V2TIM_MSG_STATUS_SEND_SUCC == v2TIMMessage.getStatus() && messageBean instanceof SoundMessageBean)
&& presenter.getConvertedTextStatus(messageBean.getV2TIMMessage()) != VoiceToTextProvider.MSG_VOICE_TO_TEXT_STATUS_SHOWN) {
TUIExtensionInfo extensionInfo = new TUIExtensionInfo();
extensionInfo.setWeight(2900);
extensionInfo.setText(appContext.getString(R.string.convert_to_text));
if (TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessagePopMenu.CLASSIC_EXTENSION_ID)) {
extensionInfo.setIcon(R.drawable.pop_menu_voice_to_text);
} else {
extensionInfo.setIcon(R.drawable.pop_menu_voice_to_text);
}
extensionInfo.setExtensionListener(new TUIExtensionEventListener() {
@Override
public void onClicked(Map<String, Object> param) {
voiceToTextMessageLayoutProxy.convertMessage(messageBean);
}
});
return Collections.singletonList(extensionInfo);
}
}
return null;
}
@Override
public boolean onRaiseExtension(String extensionID, View parentView, Map<String, Object> param) {
if (TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessageBottom.CLASSIC_EXTENSION_ID)
|| TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessageBottom.MINIMALIST_EXTENSION_ID)) {
if (param == null) {
return false;
}
ViewGroup viewGroup = null;
if (parentView instanceof ViewGroup) {
viewGroup = (ViewGroup) parentView;
}
if (viewGroup == null) {
return false;
}
TUIMessageBean messageBean = (TUIMessageBean) param.get(TUIConstants.TUIChat.MESSAGE_BEAN);
if (messageBean == null) {
return false;
}
V2TIMMessage v2TIMMessage = messageBean.getV2TIMMessage();
if (v2TIMMessage == null) {
return false;
}
if (v2TIMMessage.getElemType() != V2TIMMessage.V2TIM_ELEM_TYPE_SOUND) {
return false;
}
RecyclerView recyclerView = (RecyclerView) param.get(TUIConstants.TUIChat.CHAT_RECYCLER_VIEW);
Fragment fragment = null;
Object fragmentObject = param.get(TUIConstants.TUIChat.FRAGMENT);
if (fragmentObject != null && fragmentObject instanceof Fragment) {
fragment = (Fragment) fragmentObject;
}
if (TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessageBottom.CLASSIC_EXTENSION_ID)) {
voiceToTextMessageLayoutProxy.showVoiceToTextView(fragment, TUIConstants.TUIChat.THEME_STYLE_CLASSIC, recyclerView, viewGroup, messageBean);
} else {
voiceToTextMessageLayoutProxy.showVoiceToTextView(fragment, TUIConstants.TUIChat.THEME_STYLE_MINIMALIST, recyclerView, viewGroup, messageBean);
}
return true;
}
return false;
}
private Object getOrDefault(Object value, Object defaultValue) {
if (value != null) {
return value;
}
return defaultValue;
}
public static Context getAppContext() {
return ServiceInitializer.getAppContext();
}
}
@@ -0,0 +1,146 @@
package com.tencent.qcloud.tuikit.tuivoicetotextplugin.model;
import static com.tencent.imsdk.v2.V2TIMMessage.V2TIM_ELEM_TYPE_SOUND;
import android.text.TextUtils;
import com.tencent.imsdk.BaseConstants;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.imsdk.v2.V2TIMSoundElem;
import com.tencent.imsdk.v2.V2TIMValueCallback;
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
import com.tencent.qcloud.tuikit.timcommon.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.util.TUIVoiceToTextUtils;
import org.json.JSONException;
import org.json.JSONObject;
public class VoiceToTextProvider {
private static final String TAG = "VoiceToTextProvider";
/**
* message conversion unknown state
*/
public static final int MSG_VOICE_TO_TEXT_STATUS_UNKNOWN = 0;
/**
* message conversion hidden state
*/
public static final int MSG_VOICE_TO_TEXT_STATUS_HIDDEN = 1;
/**
* message conversion loading state
*/
public static final int MSG_VOICE_TO_TEXT_STATUS_LOADING = 2;
/**
* message conversion shown state
*/
public static final int MSG_VOICE_TO_TEXT_STATUS_SHOWN = 3;
private static final String KEY_VOICE_TO_TEXT = "voice_to_text";
private static final String KEY_VOICE_TO_TEXT_VIEW_STATUS = "voice_to_text_view_status";
public VoiceToTextProvider() {}
public void convertMessage(TUIMessageBean messageBean, IUIKitCallback<String> callback) {
V2TIMMessage v2TIMMessage = messageBean.getV2TIMMessage();
if (v2TIMMessage == null) {
TUIVoiceToTextUtils.callbackOnError(callback, TAG, BaseConstants.ERR_INVALID_PARAMETERS, "convertMessage v2TIMMessage is null");
return;
}
if (v2TIMMessage.getElemType() != V2TIM_ELEM_TYPE_SOUND) {
TUIVoiceToTextUtils.callbackOnError(callback, TAG, BaseConstants.ERR_INVALID_PARAMETERS, "convertMessage v2TIMMessage is not sound type");
return;
}
V2TIMSoundElem soundElem = v2TIMMessage.getSoundElem();
if (soundElem == null) {
TUIVoiceToTextUtils.callbackOnError(callback, TAG, BaseConstants.ERR_INVALID_PARAMETERS, "soundElem is null");
return;
}
String convertedText = getConvertedText(v2TIMMessage);
if (!TextUtils.isEmpty(convertedText)) {
saveConvertedResult(v2TIMMessage, convertedText, MSG_VOICE_TO_TEXT_STATUS_SHOWN);
TUIVoiceToTextUtils.callbackOnSuccess(callback, convertedText);
return;
}
saveConvertedResult(v2TIMMessage, "", MSG_VOICE_TO_TEXT_STATUS_LOADING);
soundElem.convertVoiceToText("", new V2TIMValueCallback<String>() {
@Override
public void onSuccess(String result) {
if (TextUtils.isEmpty(result)) {
saveConvertedResult(v2TIMMessage, result, MSG_VOICE_TO_TEXT_STATUS_UNKNOWN);
TUIVoiceToTextUtils.callbackOnError(callback, TAG, -1, "result is empty");
} else {
saveConvertedResult(v2TIMMessage, result, MSG_VOICE_TO_TEXT_STATUS_SHOWN);
TUIVoiceToTextUtils.callbackOnSuccess(callback, convertedText);
}
}
@Override
public void onError(int code, String desc) {
saveConvertedResult(v2TIMMessage, "", MSG_VOICE_TO_TEXT_STATUS_UNKNOWN);
TUIVoiceToTextUtils.callbackOnError(callback, TAG, code, desc);
}
});
}
public void saveConvertedResult(V2TIMMessage v2TIMMessage, String text, int status) {
if (v2TIMMessage != null) {
String localCustomData = v2TIMMessage.getLocalCustomData();
JSONObject customJson = new JSONObject();
try {
if (!TextUtils.isEmpty(localCustomData)) {
customJson = new JSONObject(localCustomData);
}
customJson.put(KEY_VOICE_TO_TEXT, text);
customJson.put(KEY_VOICE_TO_TEXT_VIEW_STATUS, status);
v2TIMMessage.setLocalCustomData(customJson.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
public String getConvertedText(V2TIMMessage v2TIMMessage) {
String result = "";
if (v2TIMMessage != null) {
String localCustomData = v2TIMMessage.getLocalCustomData();
if (TextUtils.isEmpty(localCustomData)) {
return result;
}
try {
JSONObject customJson = new JSONObject(localCustomData);
if (customJson.has(KEY_VOICE_TO_TEXT)) {
result = customJson.getString(KEY_VOICE_TO_TEXT);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return result;
}
public int getConvertedTextStatus(V2TIMMessage v2TIMMessage) {
int convertedStatus = MSG_VOICE_TO_TEXT_STATUS_UNKNOWN;
if (v2TIMMessage != null) {
String localCustomData = v2TIMMessage.getLocalCustomData();
if (TextUtils.isEmpty(localCustomData)) {
return convertedStatus;
}
try {
JSONObject customJson = new JSONObject(localCustomData);
if (customJson.has(KEY_VOICE_TO_TEXT_VIEW_STATUS)) {
convertedStatus = customJson.getInt(KEY_VOICE_TO_TEXT_VIEW_STATUS);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return convertedStatus;
}
}
@@ -0,0 +1,69 @@
package com.tencent.qcloud.tuikit.tuivoicetotextplugin.presenter;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.util.ToastUtil;
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
import com.tencent.qcloud.tuikit.timcommon.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuichat.TUIChatConstants;
import com.tencent.qcloud.tuikit.tuichat.interfaces.IMessageRecyclerView;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatLog;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.model.VoiceToTextProvider;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.util.TUIVoiceToTextLog;
import java.util.HashMap;
import java.util.Map;
public class VoiceToTextPresenter {
private static final String TAG = "VoiceToTextPresenter";
public VoiceToTextProvider provider;
public VoiceToTextPresenter() {
provider = new VoiceToTextProvider();
}
public void convertMessage(TUIMessageBean tuiMessageBean, IUIKitCallback<String> callback) {
provider.convertMessage(tuiMessageBean, new IUIKitCallback<String>() {
@Override
public void onSuccess(String result) {
TUIChatLog.d(TAG, "convertMessage success:" + result);
// notify Chat that message has been changed
Map<String, Object> param = new HashMap<>();
param.put(TUIChatConstants.MESSAGE_BEAN, tuiMessageBean);
param.put(TUIChatConstants.DATA_CHANGE_TYPE, IMessageRecyclerView.DATA_CHANGE_SCROLL_TO_POSITION_WITHOUT_HIGH_LIGHT);
TUICore.notifyEvent(TUIConstants.TUIChat.EVENT_KEY_MESSAGE_EVENT, TUIConstants.TUIChat.EVENT_SUB_KEY_MESSAGE_INFO_CHANGED, param);
}
@Override
public void onError(String module, int errCode, String errMsg) {
TUIVoiceToTextLog.e(TAG, "convertMessage failed code:" + errCode + ", msg:" + errMsg);
if (callback != null) {
callback.onError(TAG, errCode, errMsg);
}
Map<String, Object> param = new HashMap<>();
param.put(TUIChatConstants.MESSAGE_BEAN, tuiMessageBean);
param.put(TUIChatConstants.DATA_CHANGE_TYPE, IMessageRecyclerView.DATA_CHANGE_TYPE_UPDATE);
TUICore.notifyEvent(TUIConstants.TUIChat.EVENT_KEY_MESSAGE_EVENT, TUIConstants.TUIChat.EVENT_SUB_KEY_MESSAGE_INFO_CHANGED, param);
}
});
Map<String, Object> param = new HashMap<>();
param.put(TUIChatConstants.MESSAGE_BEAN, tuiMessageBean);
param.put(TUIChatConstants.DATA_CHANGE_TYPE, IMessageRecyclerView.DATA_CHANGE_TYPE_UPDATE);
TUICore.notifyEvent(TUIConstants.TUIChat.EVENT_KEY_MESSAGE_EVENT, TUIConstants.TUIChat.EVENT_SUB_KEY_MESSAGE_INFO_CHANGED, param);
}
public void saveConvertedResult(V2TIMMessage v2TIMMessage, String text, int status) {
provider.saveConvertedResult(v2TIMMessage, text, status);
}
public String getConvertedText(V2TIMMessage v2TIMMessage) {
return provider.getConvertedText(v2TIMMessage);
}
public int getConvertedTextStatus(V2TIMMessage v2TIMMessage) {
return provider.getConvertedTextStatus(v2TIMMessage);
}
}
@@ -0,0 +1,71 @@
package com.tencent.qcloud.tuikit.tuivoicetotextplugin.util;
import com.tencent.imsdk.common.IMLog;
public class TUIVoiceToTextLog extends IMLog {
private static final String PRE = "TUIVoiceToTextLog-";
private static String mixTag(String tag) {
return PRE + tag;
}
/**
* Print INFO level log
*
* @param strTag TAG
* @param strInfo
*/
public static void v(String strTag, String strInfo) {
IMLog.v(mixTag(strTag), strInfo);
}
/**
* Print DEBUG level log
*
* @param strTag TAG
* @param strInfo
*/
public static void d(String strTag, String strInfo) {
IMLog.d(mixTag(strTag), strInfo);
}
/**
* Print INFO level log
*
* @param strTag TAG
* @param strInfo
*/
public static void i(String strTag, String strInfo) {
IMLog.i(mixTag(strTag), strInfo);
}
/**
* Print WARN level log
*
* @param strTag TAG
* @param strInfo
*/
public static void w(String strTag, String strInfo) {
IMLog.w(mixTag(strTag), strInfo);
}
/**
* Print WARN level log
*
* @param strTag TAG
* @param strInfo
*/
public static void w(String strTag, String strInfo, Throwable e) {
IMLog.w(mixTag(strTag), strInfo + e.getMessage());
}
/**
* Print ERROR level log
*
* @param strTag TAG
* @param strInfo
*/
public static void e(String strTag, String strInfo) {
IMLog.e(mixTag(strTag), strInfo);
}
}
@@ -0,0 +1,25 @@
package com.tencent.qcloud.tuikit.tuivoicetotextplugin.util;
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter;
import com.tencent.qcloud.tuikit.timcommon.component.interfaces.IUIKitCallback;
public class TUIVoiceToTextUtils {
public static <T> void callbackOnError(IUIKitCallback<T> callBack, String module, int errCode, String desc) {
if (callBack != null) {
callBack.onError(module, errCode, ErrorMessageConverter.convertIMError(errCode, desc));
}
}
public static <T> void callbackOnError(IUIKitCallback<T> callBack, int errCode, String desc) {
if (callBack != null) {
callBack.onError(null, errCode, ErrorMessageConverter.convertIMError(errCode, desc));
}
}
public static <T> void callbackOnSuccess(IUIKitCallback<T> callBack, T data) {
if (callBack != null) {
callBack.onSuccess(data);
}
}
}
@@ -0,0 +1,233 @@
package com.tencent.qcloud.tuikit.tuivoicetotextplugin.widget;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.util.ToastUtil;
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
import com.tencent.qcloud.tuikit.timcommon.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuichat.TUIChatConstants;
import com.tencent.qcloud.tuikit.tuichat.TUIChatService;
import com.tencent.qcloud.tuikit.tuichat.classicui.component.popmenu.ChatPopMenu;
import com.tencent.qcloud.tuikit.tuichat.classicui.page.TUIBaseChatFragment;
import com.tencent.qcloud.tuikit.tuichat.config.classicui.TUIChatConfigClassic;
import com.tencent.qcloud.tuikit.tuichat.interfaces.IMessageRecyclerView;
import com.tencent.qcloud.tuikit.tuichat.minimalistui.page.TUIBaseChatMinimalistFragment;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.R;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.TUIVoiceToTextService;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.model.VoiceToTextProvider;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.presenter.VoiceToTextPresenter;
import com.tencent.qcloud.tuikit.tuivoicetotextplugin.util.TUIVoiceToTextLog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class VoiceToTextMessageLayoutProxy {
private static final String TAG = "PollMessageLayoutProxy";
protected List<ChatPopMenu.ChatPopMenuAction> mConvertedPopActions = new ArrayList<>();
private ChatPopMenu mConvertedChatPopMenu;
public VoiceToTextMessageLayoutProxy() {}
public void showVoiceToTextView(Fragment fragment, String themeStyle, RecyclerView recyclerView, ViewGroup viewGroup, TUIMessageBean tuiMessageBean) {
if (viewGroup == null || tuiMessageBean == null) {
return;
}
setVoiceToTextContent(fragment, themeStyle, recyclerView, viewGroup, tuiMessageBean);
}
public void convertMessage(TUIMessageBean tuiMessageBean) {
VoiceToTextPresenter voiceToTextPresenter = new VoiceToTextPresenter();
voiceToTextPresenter.convertMessage(tuiMessageBean, new IUIKitCallback<String>() {
@Override
public void onSuccess(String data) {
}
@Override
public void onError(String module, int errCode, String errMsg) {
ToastUtil.toastShortMessage(TUIVoiceToTextService.getAppContext().getString(R.string.convert_to_text_failed_tips));
}
});
}
protected void setVoiceToTextContent(Fragment fragment, String themeStyle, RecyclerView recyclerView, ViewGroup viewGroup, TUIMessageBean msg) {
LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.convert_content_layout, viewGroup);
ImageView loadingImage = viewGroup.findViewById(R.id.convert_loading_iv);
TextView convertedText = viewGroup.findViewById(R.id.convert_tv);
VoiceToTextPresenter voiceToTextPresenter = new VoiceToTextPresenter();
int status = voiceToTextPresenter.getConvertedTextStatus(msg.getV2TIMMessage());
if (status == VoiceToTextProvider.MSG_VOICE_TO_TEXT_STATUS_SHOWN) {
ViewGroup parentViewGroup = (ViewGroup) viewGroup.getParent();
parentViewGroup.setVisibility(View.VISIBLE);
viewGroup.setVisibility(View.VISIBLE);
stopConvertLoading(loadingImage);
convertedText.setVisibility(View.VISIBLE);
if (TextUtils.equals(themeStyle, TUIConstants.TUIChat.THEME_STYLE_MINIMALIST)) {
convertedText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
convertedText.getResources().getDimension(com.tencent.qcloud.tuikit.timcommon.R.dimen.chat_minimalist_message_text_size));
} else {
if (msg.hasRiskContent()) {
convertedText.setText(R.string.convert_to_text_risk_content_failed_tip);
convertedText.setTextColor(viewGroup.getResources().getColor(R.color.convert_to_text_risk_tip_color));
return;
}
convertedText.setTextColor(Color.BLACK);
}
if (msg.isSelf()) {
int sendTextMessageFontSize = TUIChatConfigClassic.getSendTextMessageFontSize();
if (sendTextMessageFontSize != TUIChatConfigClassic.UNDEFINED) {
convertedText.setTextSize(sendTextMessageFontSize);
}
} else {
int receiveTextMessageFontSize = TUIChatConfigClassic.getReceiveTextMessageFontSize();
if (receiveTextMessageFontSize != TUIChatConfigClassic.UNDEFINED) {
convertedText.setTextSize(receiveTextMessageFontSize);
}
}
convertedText.setText(voiceToTextPresenter.getConvertedText(msg.getV2TIMMessage()));
if (fragment != null) {
viewGroup.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
showConvertedItemPopMenu(fragment, themeStyle, recyclerView, view, msg);
return true;
}
});
}
} else if (status == VoiceToTextProvider.MSG_VOICE_TO_TEXT_STATUS_LOADING) {
ViewGroup parentViewGroup = (ViewGroup) viewGroup.getParent();
parentViewGroup.setVisibility(View.VISIBLE);
viewGroup.setVisibility(View.VISIBLE);
startConvertLoading(loadingImage);
convertedText.setVisibility(View.GONE);
viewGroup.setOnLongClickListener(null);
} else {
stopConvertLoading(loadingImage);
viewGroup.setVisibility(View.GONE);
viewGroup.setOnLongClickListener(null);
}
}
private void showConvertedItemPopMenu(Fragment fragment, String themeStyle, RecyclerView recyclerView, View view, TUIMessageBean messageInfo) {
initConvertedPopActions(fragment, themeStyle, messageInfo);
if (mConvertedPopActions.size() == 0) {
return;
}
if (mConvertedChatPopMenu != null) {
mConvertedChatPopMenu.hide();
mConvertedChatPopMenu = null;
}
mConvertedChatPopMenu = new ChatPopMenu(view.getContext());
mConvertedChatPopMenu.setShowFaces(false);
mConvertedChatPopMenu.setChatPopMenuActionList(mConvertedPopActions);
int[] location = new int[2];
recyclerView.getLocationOnScreen(location);
mConvertedChatPopMenu.show(view, location[1]);
}
private void initConvertedPopActions(Fragment fragment, String themeStyle, TUIMessageBean msg) {
if (msg == null) {
return;
}
VoiceToTextPresenter voiceToTextPresenter = new VoiceToTextPresenter();
ChatPopMenu.ChatPopMenuAction copyAction = new ChatPopMenu.ChatPopMenuAction();
copyAction.setActionName(fragment.getContext().getString(R.string.copy_action));
copyAction.setActionIcon(com.tencent.qcloud.tuikit.tuichat.R.drawable.pop_menu_copy);
copyAction.setActionClickListener(() -> onCopyConvertedTextClick(voiceToTextPresenter.getConvertedText(msg.getV2TIMMessage())));
ChatPopMenu.ChatPopMenuAction forwardAction = null;
if (msg.getStatus() != TUIMessageBean.MSG_STATUS_SEND_FAIL) {
forwardAction = new ChatPopMenu.ChatPopMenuAction();
forwardAction.setActionName(fragment.getContext().getString(R.string.forward_action));
forwardAction.setActionIcon(R.drawable.pop_menu_forward);
forwardAction.setActionClickListener(() -> onForwardConvertedTextClick(fragment, themeStyle, msg));
}
ChatPopMenu.ChatPopMenuAction hiddenAction = new ChatPopMenu.ChatPopMenuAction();
hiddenAction.setActionName(fragment.getContext().getString(R.string.hide_action));
hiddenAction.setActionIcon(R.drawable.pop_menu_hide);
hiddenAction.setActionClickListener(() -> onHideConvertedTextClick(msg));
mConvertedPopActions.clear();
mConvertedPopActions.add(copyAction);
if (forwardAction != null) {
mConvertedPopActions.add(forwardAction);
}
mConvertedPopActions.add(hiddenAction);
}
private void onCopyConvertedTextClick(String convertedText) {
ClipboardManager clipboard = (ClipboardManager) TUIChatService.getAppContext().getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard == null || TextUtils.isEmpty(convertedText)) {
return;
}
ClipData clip = ClipData.newPlainText("message", convertedText);
clipboard.setPrimaryClip(clip);
String copySuccess = TUIChatService.getAppContext().getResources().getString(R.string.copy_success_tip);
ToastUtil.toastShortMessage(copySuccess);
}
private void onHideConvertedTextClick(TUIMessageBean messageBean) {
VoiceToTextPresenter voiceToTextPresenter = new VoiceToTextPresenter();
voiceToTextPresenter.saveConvertedResult(messageBean.getV2TIMMessage(), voiceToTextPresenter.getConvertedText(messageBean.getV2TIMMessage()),
VoiceToTextProvider.MSG_VOICE_TO_TEXT_STATUS_HIDDEN);
Map<String, Object> param = new HashMap<>();
param.put(TUIChatConstants.MESSAGE_BEAN, messageBean);
param.put(TUIChatConstants.DATA_CHANGE_TYPE, IMessageRecyclerView.DATA_CHANGE_TYPE_UPDATE);
TUICore.notifyEvent(TUIConstants.TUIChat.EVENT_KEY_MESSAGE_EVENT, TUIConstants.TUIChat.EVENT_SUB_KEY_MESSAGE_INFO_CHANGED, param);
}
private void onForwardConvertedTextClick(Fragment fragment, String themeStyle, TUIMessageBean messageBean) {
if (fragment == null) {
TUIVoiceToTextLog.e(TAG, "onForwardConvertedTextClick fragment is null!");
return;
}
VoiceToTextPresenter voiceToTextPresenter = new VoiceToTextPresenter();
if (themeStyle != null) {
if (themeStyle.equals(TUIConstants.TUIChat.THEME_STYLE_CLASSIC) && fragment instanceof TUIBaseChatFragment) {
((TUIBaseChatFragment) fragment).getChatView().forwardText(voiceToTextPresenter.getConvertedText(messageBean.getV2TIMMessage()));
} else if (themeStyle.equals(TUIConstants.TUIChat.THEME_STYLE_MINIMALIST) && fragment instanceof TUIBaseChatMinimalistFragment) {
((TUIBaseChatMinimalistFragment) fragment).getChatView().forwardText(voiceToTextPresenter.getConvertedText(messageBean.getV2TIMMessage()));
}
}
}
private void startConvertLoading(ImageView loadingImage) {
loadingImage.setVisibility(View.VISIBLE);
RotateAnimation convertRotateAnimation = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
convertRotateAnimation.setRepeatCount(-1);
convertRotateAnimation.setDuration(1000);
convertRotateAnimation.setInterpolator(new LinearInterpolator());
loadingImage.startAnimation(convertRotateAnimation);
}
private void stopConvertLoading(ImageView loadingImage) {
loadingImage.clearAnimation();
loadingImage.setVisibility(View.GONE);
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/convert_loading_iv"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_margin="10dp"
android:background="@drawable/voice_to_text_loading"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/convert_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:lineHeight="20.16sp"
android:textColor="@color/black"
android:textSize="15.5sp"
tools:text="test" />
</RelativeLayout>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="convert_to_text">تحويل النص</string>
<string name="convert_to_text_failed_tips">فشل تحويل</string>
<string name="copy_action">نسخ</string>
<string name="forward_action">إعادة توجيه</string>
<string name="hide_action">إخفاء</string>
<string name="copy_success_tip">تم النسخ بنجاح</string>
<string name="convert_to_text_risk_content_failed_tip">يحتوي على محتوى حساس، فشل تحويل النص</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="convert_to_text">轉文字</string>
<string name="convert_to_text_failed_tips">轉換失敗</string>
<string name="copy_action">複製</string>
<string name="forward_action">轉發</string>
<string name="hide_action">隱藏</string>
<string name="copy_success_tip">複製成功</string>
<string name="convert_to_text_risk_content_failed_tip">涉及敏感內容,轉文字失敗</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="convert_to_text">转文字</string>
<string name="convert_to_text_failed_tips">转换失败</string>
<string name="copy_action">复制</string>
<string name="forward_action">转发</string>
<string name="hide_action">隐藏</string>
<string name="copy_success_tip">复制成功</string>
<string name="convert_to_text_risk_content_failed_tip">涉及敏感内容,转文字失败</string>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="convert_to_text_risk_tip_color">#DA2222</color>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="convert_to_text">Convert to text</string>
<string name="convert_to_text_failed_tips">Convert failed</string>
<string name="copy_action">Copy</string>
<string name="forward_action">Forward</string>
<string name="hide_action">Hide</string>
<string name="copy_success_tip">Copy Success</string>
<string name="convert_to_text_risk_content_failed_tip">Contains sensitive content, text conversion failed</string>
</resources>