初始代码
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.tencent.imsdk.manager.BaseManager;
|
||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener;
|
||||
import com.tencent.imsdk.v2.V2TIMManager;
|
||||
import com.tencent.imsdk.v2.V2TIMMessageReaction;
|
||||
import com.tencent.imsdk.v2.V2TIMMessageReactionChangeInfo;
|
||||
import com.tencent.imsdk.v2.V2TIMUserInfo;
|
||||
import com.tencent.imsdk.v2.V2TIMValueCallback;
|
||||
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.ITUINotification;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUIExtensionInfo;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUIInitializer;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUIValueCallback;
|
||||
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.UserBean;
|
||||
import com.tencent.qcloud.tuikit.tuichat.TUIChatService;
|
||||
import com.tencent.qcloud.tuikit.tuichat.classicui.component.popmenu.ChatPopMenu;
|
||||
import com.tencent.qcloud.tuikit.tuichat.minimalistui.widget.messagepopmenu.ChatPopActivity;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.ReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.calssicui.widget.ChatClassicPopMenuReactProxy;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.calssicui.widget.ChatClassicReactionPreviewProxy;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.OnMessageReactionsChangedListener;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.minimalistui.widget.ChatMinimalistPopMenuReactProxy;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.minimalistui.widget.ChatMinimalistReactionPreviewProxy;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.MessageReactionBeanCache;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.TUIEmojiPresenter;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.util.TUIEmojiLog;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@AutoService(TUIInitializer.class)
|
||||
@TUIInitializerID("TUIEmojiPlugin")
|
||||
@TUIInitializerDependency("TUIChat")
|
||||
public class TUIEmojiPluginService implements TUIInitializer, ITUINotification, ITUIExtension {
|
||||
public static final String TAG = TUIEmojiPluginService.class.getSimpleName();
|
||||
public static final long PLUGIN_REPORT_CODE = 18;
|
||||
|
||||
private static TUIEmojiPluginService instance;
|
||||
|
||||
private final List<WeakReference<OnMessageReactionsChangedListener>> reactionsChangedListener = new ArrayList<>();
|
||||
|
||||
private final TUIEmojiPresenter presenter = new TUIEmojiPresenter();
|
||||
|
||||
private static TUIEmojiPluginService getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context) {
|
||||
instance = this;
|
||||
initEvent();
|
||||
initExtension();
|
||||
initIMListener();
|
||||
}
|
||||
|
||||
private void initExtension() {
|
||||
TUICore.registerExtension(TUIConstants.TUIChat.Extension.MessagePopMenuTopAreaExtension.EXTENSION_ID, this);
|
||||
TUICore.registerExtension(TUIConstants.TUIChat.Extension.MessageReactPreviewExtension.EXTENSION_ID, this);
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
TUICore.registerEvent(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED, TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS, this);
|
||||
TUICore.registerEvent(TUIConstants.TUIChat.Event.MessageStatus.KEY, TUIConstants.TUIChat.Event.MessageStatus.SUB_KEY_PROCESS_MESSAGE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyEvent(String key, String subKey, Map<String, Object> param) {
|
||||
if (TextUtils.equals(key, TUIConstants.TUIChat.Event.MessageStatus.KEY)) {
|
||||
if (TextUtils.equals(subKey, TUIConstants.TUIChat.Event.MessageStatus.SUB_KEY_PROCESS_MESSAGE)) {
|
||||
List<TUIMessageBean> messageBeans = (List<TUIMessageBean>) param.get(TUIConstants.TUIChat.Event.MessageStatus.MESSAGE_LIST);
|
||||
presenter.getMessageReactions(messageBeans, 10, new TUIValueCallback<List<MessageReactionBean>>() {
|
||||
@Override
|
||||
public void onSuccess(List<MessageReactionBean> object) {
|
||||
TUIEmojiLog.i(TAG, "get message reactions success");
|
||||
for (TUIMessageBean messageBean : messageBeans) {
|
||||
for (MessageReactionBean reactionBean : object) {
|
||||
if (TextUtils.equals(messageBean.getId(), reactionBean.getMessageID())) {
|
||||
MessageReactionBeanCache.putMessageReactionBean(messageBean, reactionBean);
|
||||
if (reactionBean.getReactionCount() != 0) {
|
||||
messageBean.setHasReaction(true);
|
||||
TUIChatService.getInstance().refreshMessage(messageBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.e(TAG, "get message reactions failed, code = " + errorCode + ", message = " + errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (TextUtils.equals(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED, key)) {
|
||||
if (TextUtils.equals(TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS, subKey)) {
|
||||
reportTUIPollComponentUsage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportTUIPollComponentUsage() {
|
||||
try {
|
||||
JSONObject reportParam = new JSONObject();
|
||||
reportParam.put("UIComponentType", PLUGIN_REPORT_CODE);
|
||||
long uiStyleType = BaseManager.TUI_STYLE_TYPE_CLASSIC;
|
||||
try {
|
||||
Class c = Class.forName("com.tencent.qcloud.tuikit.tuichat.minimalistui.MinimalistUIService");
|
||||
if (c != null) {
|
||||
uiStyleType = BaseManager.TUI_STYLE_TYPE_MINIMALIST;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
reportParam.put("UIStyleType", uiStyleType);
|
||||
V2TIMManager.getInstance().callExperimentalAPI("reportTUIComponentUsage", reportParam.toString(), new V2TIMValueCallback<Object>() {
|
||||
@Override
|
||||
public void onError(int code, String desc) {
|
||||
TUIEmojiLog.e(TAG, "report TUIEmojiPlugin usage err = " + code + ", desc = " + ErrorMessageConverter.convertIMError(code, desc));
|
||||
}
|
||||
@Override
|
||||
public void onSuccess(Object data) {
|
||||
TUIEmojiLog.i(TAG, "report TUIEmojiPlugin usage success");
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void initIMListener() {
|
||||
V2TIMManager.getMessageManager().addAdvancedMsgListener(new V2TIMAdvancedMsgListener() {
|
||||
@Override
|
||||
public void onRecvMessageReactionsChanged(List<V2TIMMessageReactionChangeInfo> changeInfos) {
|
||||
for (V2TIMMessageReactionChangeInfo changeInfo : changeInfos) {
|
||||
String messageID = changeInfo.getMessageID();
|
||||
MessageReactionBean cachedMessageReactionBean = MessageReactionBeanCache.getMessageReactionBean(messageID);
|
||||
if (cachedMessageReactionBean == null) {
|
||||
continue;
|
||||
}
|
||||
List<V2TIMMessageReaction> v2TIMMessageReactions = changeInfo.getReactionList();
|
||||
if (v2TIMMessageReactions == null || v2TIMMessageReactions.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, ReactionBean> messageReactionBeanMap = cachedMessageReactionBean.getMessageReactionBeanMap();
|
||||
for (V2TIMMessageReaction v2TIMMessageReaction : v2TIMMessageReactions) {
|
||||
if (v2TIMMessageReaction.getTotalUserCount() <= 0) {
|
||||
messageReactionBeanMap.remove(v2TIMMessageReaction.getReactionID());
|
||||
} else {
|
||||
ReactionBean reactionBean = convertToReactionBean(v2TIMMessageReaction);
|
||||
messageReactionBeanMap.put(reactionBean.getReactionID(), reactionBean);
|
||||
}
|
||||
}
|
||||
List<OnMessageReactionsChangedListener> listeners = getReactionsChangedListenerList();
|
||||
for (OnMessageReactionsChangedListener listener : listeners) {
|
||||
listener.onMessageReactionsChanged(cachedMessageReactionBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static ReactionBean convertToReactionBean(V2TIMMessageReaction v2TIMMessageReaction) {
|
||||
ReactionBean reactionBean = new ReactionBean();
|
||||
reactionBean.setReactionID(v2TIMMessageReaction.getReactionID());
|
||||
reactionBean.setByMySelf(v2TIMMessageReaction.getReactedByMyself());
|
||||
reactionBean.setTotalUserCount(v2TIMMessageReaction.getTotalUserCount());
|
||||
List<V2TIMUserInfo> v2TIMUserInfoList = v2TIMMessageReaction.getPartialUserList();
|
||||
List<UserBean> userBeanList = new ArrayList<>();
|
||||
if (v2TIMUserInfoList != null) {
|
||||
for (V2TIMUserInfo v2TIMUserInfo : v2TIMUserInfoList) {
|
||||
UserBean reactUserBean = new UserBean();
|
||||
reactUserBean.setUserId(v2TIMUserInfo.getUserID());
|
||||
reactUserBean.setNickName(v2TIMUserInfo.getNickName());
|
||||
reactUserBean.setFaceUrl(v2TIMUserInfo.getFaceUrl());
|
||||
userBeanList.add(reactUserBean);
|
||||
}
|
||||
reactionBean.setPartialUserList(userBeanList);
|
||||
}
|
||||
return reactionBean;
|
||||
}
|
||||
|
||||
private List<OnMessageReactionsChangedListener> getReactionsChangedListenerList() {
|
||||
List<OnMessageReactionsChangedListener> listeners = new ArrayList<>();
|
||||
Iterator<WeakReference<OnMessageReactionsChangedListener>> iterator = reactionsChangedListener.listIterator();
|
||||
while (iterator.hasNext()) {
|
||||
WeakReference<OnMessageReactionsChangedListener> listenerWeakReference = iterator.next();
|
||||
OnMessageReactionsChangedListener listener = listenerWeakReference.get();
|
||||
if (listener == null) {
|
||||
iterator.remove();
|
||||
} else {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
public static void addReactionsChangedListener(OnMessageReactionsChangedListener messageReactionsChangedListener) {
|
||||
if (messageReactionsChangedListener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (WeakReference<OnMessageReactionsChangedListener> listenerWeakReference : getInstance().reactionsChangedListener) {
|
||||
if (listenerWeakReference.get() == messageReactionsChangedListener) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
getInstance().reactionsChangedListener.add(new WeakReference<>(messageReactionsChangedListener));
|
||||
}
|
||||
|
||||
private <T> T getOrDefault(Map map, Object key, T defaultValue) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
return defaultValue;
|
||||
}
|
||||
Object object = map.get(key);
|
||||
try {
|
||||
if (object != null) {
|
||||
return (T) object;
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TUIExtensionInfo> onGetExtension(String extensionID, Map<String, Object> param) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRaiseExtension(String extensionID, View parentView, Map<String, Object> param) {
|
||||
if (TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessageReactPreviewExtension.EXTENSION_ID)) {
|
||||
int viewType = getOrDefault(param, TUIConstants.TUIChat.Extension.MessageReactPreviewExtension.VIEW_TYPE,
|
||||
TUIConstants.TUIChat.Extension.MessageReactPreviewExtension.VIEW_TYPE_CLASSIC);
|
||||
Object messageBeanObj = param.get(TUIConstants.TUIChat.Extension.MessageReactPreviewExtension.MESSAGE);
|
||||
if (viewType == TUIConstants.TUIChat.Extension.MessageReactPreviewExtension.VIEW_TYPE_CLASSIC) {
|
||||
if (messageBeanObj instanceof TUIMessageBean && parentView instanceof FrameLayout) {
|
||||
ChatClassicReactionPreviewProxy.fill((TUIMessageBean) messageBeanObj, (FrameLayout) parentView);
|
||||
}
|
||||
} else {
|
||||
if (messageBeanObj instanceof TUIMessageBean && parentView instanceof FrameLayout) {
|
||||
ChatMinimalistReactionPreviewProxy.fill((TUIMessageBean) messageBeanObj, (FrameLayout) parentView);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (TextUtils.equals(extensionID, TUIConstants.TUIChat.Extension.MessagePopMenuTopAreaExtension.EXTENSION_ID)) {
|
||||
Object chatPopMenuObj = param.get(TUIConstants.TUIChat.Extension.MessagePopMenuTopAreaExtension.CHAT_POP_MENU);
|
||||
if (chatPopMenuObj instanceof ChatPopMenu) {
|
||||
ChatClassicPopMenuReactProxy chatClassicPopMenuReactProxy = new ChatClassicPopMenuReactProxy();
|
||||
chatClassicPopMenuReactProxy.setChatPopMenu((ChatPopMenu) chatPopMenuObj);
|
||||
chatClassicPopMenuReactProxy.fill();
|
||||
}
|
||||
|
||||
Object chatPopActivity = param.get(TUIConstants.TUIChat.Extension.MessagePopMenuTopAreaExtension.CHAT_POP_MENU);
|
||||
if (chatPopActivity instanceof ChatPopActivity) {
|
||||
ChatMinimalistPopMenuReactProxy chatMinimalistPopMenuReactProxy = new ChatMinimalistPopMenuReactProxy();
|
||||
chatMinimalistPopMenuReactProxy.setChatPopActivity((ChatPopActivity) chatPopActivity);
|
||||
chatMinimalistPopMenuReactProxy.fill();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.bean;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MessageReactionBean {
|
||||
private String messageID;
|
||||
private final Map<String, ReactionBean> reactionBeanMap = new LinkedHashMap<>();
|
||||
|
||||
public void setMessageID(String messageID) {
|
||||
this.messageID = messageID;
|
||||
}
|
||||
|
||||
public String getMessageID() {
|
||||
return messageID;
|
||||
}
|
||||
|
||||
public void setMessageReactionBeanMap(Map<String, ReactionBean> reactionBeanMap) {
|
||||
this.reactionBeanMap.clear();
|
||||
this.reactionBeanMap.putAll(reactionBeanMap);
|
||||
}
|
||||
|
||||
public Map<String, ReactionBean> getMessageReactionBeanMap() {
|
||||
return reactionBeanMap;
|
||||
}
|
||||
|
||||
public ReactionBean getReactionBean(String reactionID) {
|
||||
return reactionBeanMap.get(reactionID);
|
||||
}
|
||||
|
||||
public int getReactionCount() {
|
||||
if (reactionBeanMap.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return reactionBeanMap.size();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.bean;
|
||||
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.UserBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MessageReactionUserBean {
|
||||
private List<UserBean> userBeanList;
|
||||
private int nextSeq;
|
||||
private boolean isFinished;
|
||||
|
||||
public void setUserBeanList(List<UserBean> userBeanList) {
|
||||
this.userBeanList = userBeanList;
|
||||
}
|
||||
|
||||
public List<UserBean> getUserBeanList() {
|
||||
return userBeanList;
|
||||
}
|
||||
|
||||
public void setFinished(boolean finished) {
|
||||
isFinished = finished;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return isFinished;
|
||||
}
|
||||
|
||||
public void setNextSeq(int nextSeq) {
|
||||
this.nextSeq = nextSeq;
|
||||
}
|
||||
|
||||
public int getNextSeq() {
|
||||
return nextSeq;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.bean;
|
||||
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.UserBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ReactionBean {
|
||||
private String reactionID;
|
||||
private int totalUserCount;
|
||||
private boolean isByMySelf;
|
||||
private List<UserBean> partialUserList;
|
||||
|
||||
public void setByMySelf(boolean byMySelf) {
|
||||
isByMySelf = byMySelf;
|
||||
}
|
||||
|
||||
public void setReactionID(String reactionID) {
|
||||
this.reactionID = reactionID;
|
||||
}
|
||||
|
||||
public void setPartialUserList(List<UserBean> partialUserList) {
|
||||
this.partialUserList = partialUserList;
|
||||
}
|
||||
|
||||
public void setTotalUserCount(int totalUserCount) {
|
||||
this.totalUserCount = totalUserCount;
|
||||
}
|
||||
|
||||
public int getTotalUserCount() {
|
||||
return totalUserCount;
|
||||
}
|
||||
|
||||
public List<UserBean> getPartialUserList() {
|
||||
return partialUserList;
|
||||
}
|
||||
|
||||
public String getReactionID() {
|
||||
return reactionID;
|
||||
}
|
||||
|
||||
public boolean isByMySelf() {
|
||||
return isByMySelf;
|
||||
}
|
||||
}
|
||||
+482
@@ -0,0 +1,482 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.calssicui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.PagerSnapHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
|
||||
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter;
|
||||
import com.tencent.qcloud.tuicore.util.ToastUtil;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.Emoji;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.FaceManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.RecentEmojiManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.LayoutUtil;
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.ScreenUtil;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.IndicatorView;
|
||||
import com.tencent.qcloud.tuikit.tuichat.classicui.component.popmenu.ChatPopMenu;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.R;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.ReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.OnEmojiClickedListener;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.MessageReactionBeanCache;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.TUIEmojiPresenter;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.util.TUIEmojiLog;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatClassicPopMenuReactProxy {
|
||||
private static final String TAG = ChatClassicPopMenuReactProxy.class.getSimpleName();
|
||||
// emoji column num
|
||||
private static final int EMOJI_COLUMN_NUM = 8;
|
||||
private static final int EMOJI_ROW_NUM = 3;
|
||||
private static final int RECENT_EMOJI_NUM = 6;
|
||||
|
||||
private RecyclerView facePageRecyclerView;
|
||||
private LinearLayout facePageLinearLayout;
|
||||
private IndicatorView facePageIndicator;
|
||||
private RecyclerView recentFaceView;
|
||||
private View divideLine;
|
||||
private FacePageAdapter facePageAdapter;
|
||||
|
||||
private final List<Emoji> emojiList = new ArrayList<>();
|
||||
private final List<String> recentEmojiList = new ArrayList<>();
|
||||
private OnEmojiClickedListener onEmojiClickedListener;
|
||||
private boolean isShowMoreFace = false;
|
||||
private int oldFacePageIndex = 0;
|
||||
private Context context;
|
||||
private TUIEmojiPresenter presenter;
|
||||
private ChatPopMenu chatPopMenu;
|
||||
|
||||
public ChatClassicPopMenuReactProxy() {
|
||||
presenter = new TUIEmojiPresenter();
|
||||
}
|
||||
|
||||
public void setChatPopMenu(ChatPopMenu chatPopMenu) {
|
||||
this.chatPopMenu = chatPopMenu;
|
||||
}
|
||||
|
||||
public void fill() {
|
||||
FrameLayout frameLayout = chatPopMenu.getReactFrameLayout();
|
||||
context = frameLayout.getContext();
|
||||
|
||||
View reactionArea = LayoutInflater.from(frameLayout.getContext()).inflate(R.layout.tuiemoji_classic_chat_popup_react_area, null);
|
||||
frameLayout.addView(reactionArea);
|
||||
initEmojiList();
|
||||
|
||||
divideLine = reactionArea.findViewById(R.id.divide_line);
|
||||
// recent faces
|
||||
|
||||
recentFaceView = reactionArea.findViewById(R.id.recent_faces);
|
||||
recentFaceView.setItemAnimator(null);
|
||||
LinearLayoutManager recentLayoutManager = new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false);
|
||||
int recentSpacing = reactionArea.getResources().getDimensionPixelOffset(R.dimen.tuiemoji_chat_pop_menu_recent_face_space);
|
||||
recentFaceView.addItemDecoration(new GridDecoration(null, RECENT_EMOJI_NUM + 1, recentSpacing, 0));
|
||||
recentFaceView.setLayoutManager(recentLayoutManager);
|
||||
RecentFaceAdapter recentFaceAdapter = new RecentFaceAdapter();
|
||||
recentFaceView.setAdapter(recentFaceAdapter);
|
||||
// grid faces
|
||||
facePageLinearLayout = reactionArea.findViewById(R.id.face_grid_ll);
|
||||
facePageRecyclerView = reactionArea.findViewById(R.id.face_grid);
|
||||
facePageIndicator = reactionArea.findViewById(R.id.face_indicator);
|
||||
facePageLinearLayout.setVisibility(View.GONE);
|
||||
LinearLayoutManager faceLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
|
||||
PagerSnapHelper snapHelper = new PagerSnapHelper();
|
||||
snapHelper.attachToRecyclerView(facePageRecyclerView);
|
||||
facePageRecyclerView.setLayoutManager(faceLayoutManager);
|
||||
facePageAdapter = new FacePageAdapter();
|
||||
facePageRecyclerView.setAdapter(facePageAdapter);
|
||||
setFacePageIndicator(faceLayoutManager);
|
||||
if (!chatPopMenu.isShowFaces()) {
|
||||
recentFaceView.setVisibility(View.GONE);
|
||||
divideLine.setVisibility(View.GONE);
|
||||
} else {
|
||||
recentFaceView.setVisibility(View.VISIBLE);
|
||||
if (chatPopMenu.hasMenuAction()) {
|
||||
divideLine.setVisibility(View.VISIBLE);
|
||||
chatPopMenu.setActionListVisibility(View.VISIBLE);
|
||||
} else {
|
||||
divideLine.setVisibility(View.GONE);
|
||||
chatPopMenu.setActionListVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
onEmojiClickedListener = new OnEmojiClickedListener() {
|
||||
@Override
|
||||
public void onEmojiClicked(Emoji emoji) {
|
||||
MessageReactionBean messageReactionBean = MessageReactionBeanCache.getMessageReactionBean(chatPopMenu.getMessageBean().getId());
|
||||
if (messageReactionBean != null) {
|
||||
ReactionBean reactionBean = messageReactionBean.getReactionBean(emoji.getFaceKey());
|
||||
if (reactionBean == null) {
|
||||
addMessageReaction(chatPopMenu.getMessageBean(), emoji.getFaceKey());
|
||||
} else {
|
||||
if (reactionBean.isByMySelf()) {
|
||||
removeMessageReaction(chatPopMenu.getMessageBean(), emoji.getFaceKey());
|
||||
} else {
|
||||
addMessageReaction(chatPopMenu.getMessageBean(), emoji.getFaceKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
updateRecentEmoji(emoji);
|
||||
chatPopMenu.hide();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void addMessageReaction(TUIMessageBean messageBean, String reactionID) {
|
||||
presenter.addMessageReaction(messageBean, reactionID, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUIEmojiLog.i(TAG, "addMessageReaction success " + messageBean.getId() + " " + reactionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.e(TAG, "addMessageReaction failed code " + errorCode + ",message " + errorMessage);
|
||||
ToastUtil.toastLongMessage(
|
||||
context.getString(R.string.tuiemoji_add_reaction_failed_tip) + " " + ErrorMessageConverter.convertIMError(errorCode, errorMessage));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void removeMessageReaction(TUIMessageBean messageBean, String reactionID) {
|
||||
presenter.removeMessageReaction(messageBean, reactionID, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUIEmojiLog.i(TAG, "removeMessageReaction success " + messageBean.getId() + " " + reactionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.e(TAG, "addMessageReaction failed code " + errorCode + ",message " + errorMessage);
|
||||
ToastUtil.toastLongMessage(
|
||||
context.getString(R.string.tuiemoji_remove_reaction_failed_tip) + " " + ErrorMessageConverter.convertIMError(errorCode, errorMessage));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFacePageIndicator(LinearLayoutManager faceLayoutManager) {
|
||||
facePageIndicator.init(facePageAdapter.getItemCount());
|
||||
facePageRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
int currentFacePageIndex;
|
||||
if (dx >= 0) {
|
||||
currentFacePageIndex = faceLayoutManager.findLastVisibleItemPosition();
|
||||
} else {
|
||||
currentFacePageIndex = faceLayoutManager.findFirstVisibleItemPosition();
|
||||
}
|
||||
// the page is not be selected
|
||||
if (currentFacePageIndex == RecyclerView.NO_POSITION || oldFacePageIndex == currentFacePageIndex) {
|
||||
return;
|
||||
}
|
||||
facePageIndicator.playBy(oldFacePageIndex, currentFacePageIndex);
|
||||
oldFacePageIndex = currentFacePageIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initEmojiList() {
|
||||
emojiList.addAll(FaceManager.getEmojiList());
|
||||
initDefaultEmoji();
|
||||
}
|
||||
|
||||
private void initDefaultEmoji() {
|
||||
List<String> emojis = (List<String>) RecentEmojiManager.getCollection();
|
||||
if (emojis == null) {
|
||||
List<Emoji> subList = emojiList.subList(0, RECENT_EMOJI_NUM);
|
||||
List<String> emojiKeys = new ArrayList<>();
|
||||
for (Emoji emoji : subList) {
|
||||
emojiKeys.add(emoji.getFaceKey());
|
||||
}
|
||||
emojis = new ArrayList<>(emojiKeys);
|
||||
RecentEmojiManager.putCollection(emojis);
|
||||
}
|
||||
recentEmojiList.addAll(emojis);
|
||||
}
|
||||
|
||||
private void updateRecentEmoji(Emoji emoji) {
|
||||
recentEmojiList.remove(emoji.getFaceKey());
|
||||
recentEmojiList.add(0, emoji.getFaceKey());
|
||||
RecentEmojiManager.updateRecentUseEmoji(emoji.getFaceKey());
|
||||
}
|
||||
|
||||
class RecentFaceAdapter extends RecyclerView.Adapter<RecentFaceAdapter.RecentFaceViewHolder> {
|
||||
@NonNull
|
||||
@Override
|
||||
public RecentFaceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View faceView = LayoutInflater.from(parent.getContext()).inflate(R.layout.tuiemoji_chat_menu_recent_face_item_layout, parent, false);
|
||||
return new RecentFaceViewHolder(faceView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecentFaceViewHolder holder, int position) {
|
||||
Emoji emoji;
|
||||
if (position == RECENT_EMOJI_NUM) {
|
||||
emoji = new Emoji();
|
||||
Bitmap bitMap;
|
||||
if (!isShowMoreFace) {
|
||||
bitMap = BitmapFactory.decodeResource(context.getResources(), R.drawable.tuiemoji_classic_chat_menu_face_show_more);
|
||||
} else {
|
||||
bitMap = BitmapFactory.decodeResource(context.getResources(), R.drawable.tuiemoji_classic_chat_menu_face_hide_more);
|
||||
}
|
||||
emoji.setIcon(bitMap);
|
||||
} else {
|
||||
emoji = getEmoji(recentEmojiList.get(position));
|
||||
}
|
||||
if (emoji == null) {
|
||||
return;
|
||||
}
|
||||
holder.faceIv.setImageBitmap(emoji.getIcon());
|
||||
if (onEmojiClickedListener != null) {
|
||||
holder.faceIv.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (position == RECENT_EMOJI_NUM) {
|
||||
isShowMoreFace = !isShowMoreFace;
|
||||
refreshLayout();
|
||||
notifyItemChanged(position);
|
||||
} else {
|
||||
onEmojiClickedListener.onEmojiClicked(emoji);
|
||||
chatPopMenu.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private Emoji getEmoji(String emojiKey) {
|
||||
for (Emoji emoji : emojiList) {
|
||||
if (TextUtils.equals(emoji.getFaceKey(), emojiKey)) {
|
||||
return emoji;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return RECENT_EMOJI_NUM + 1;
|
||||
}
|
||||
|
||||
class RecentFaceViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView faceIv;
|
||||
|
||||
public RecentFaceViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
faceIv = itemView.findViewById(R.id.face_iv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FacePageAdapter extends RecyclerView.Adapter<FacePageAdapter.FacePageViewHolder> {
|
||||
@NonNull
|
||||
@Override
|
||||
public FacePageAdapter.FacePageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
RecyclerView faceGridView = new RecyclerView(parent.getContext());
|
||||
faceGridView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
faceGridView.setLayoutManager(new GridLayoutManager(parent.getContext(), EMOJI_COLUMN_NUM));
|
||||
int faceVerticalSpacing = ScreenUtil.dip2px(16.32f);
|
||||
int faceHorizontalSpacing = ScreenUtil.dip2px(9.12f);
|
||||
faceGridView.addItemDecoration(new FaceGridDecoration(EMOJI_COLUMN_NUM, faceHorizontalSpacing, faceVerticalSpacing));
|
||||
return new FacePageViewHolder(faceGridView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull FacePageAdapter.FacePageViewHolder holder, int position) {
|
||||
FaceGridAdapter faceGridAdapter = new FaceGridAdapter();
|
||||
holder.recyclerView.setAdapter(faceGridAdapter);
|
||||
int startIndex = position * EMOJI_ROW_NUM * EMOJI_COLUMN_NUM;
|
||||
int endIndex = (position + 1) * EMOJI_COLUMN_NUM * EMOJI_ROW_NUM;
|
||||
if (endIndex > emojiList.size()) {
|
||||
endIndex = emojiList.size();
|
||||
}
|
||||
List<Emoji> data = emojiList.subList(startIndex, endIndex);
|
||||
faceGridAdapter.setData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return (int) Math.ceil(emojiList.size() * 1.0f / (EMOJI_COLUMN_NUM * EMOJI_ROW_NUM));
|
||||
}
|
||||
|
||||
class FacePageViewHolder extends RecyclerView.ViewHolder {
|
||||
public RecyclerView recyclerView;
|
||||
|
||||
public FacePageViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
recyclerView = (RecyclerView) itemView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshLayout() {
|
||||
if (isShowMoreFace) {
|
||||
facePageLinearLayout.setVisibility(View.VISIBLE);
|
||||
chatPopMenu.setActionListVisibility(View.GONE);
|
||||
divideLine.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
facePageLinearLayout.setVisibility(View.GONE);
|
||||
if (chatPopMenu.hasMenuAction()) {
|
||||
divideLine.setVisibility(View.VISIBLE);
|
||||
chatPopMenu.setActionListVisibility(View.VISIBLE);
|
||||
} else {
|
||||
divideLine.setVisibility(View.GONE);
|
||||
chatPopMenu.setActionListVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
chatPopMenu.showAtLocation();
|
||||
}
|
||||
|
||||
class FaceGridAdapter extends RecyclerView.Adapter<FaceViewHolder> {
|
||||
private List<Emoji> data;
|
||||
|
||||
public void setData(List<Emoji> data) {
|
||||
this.data = data;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FaceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View faceView = LayoutInflater.from(parent.getContext()).inflate(R.layout.tuiemoji_classic_chat_menu_face_item_layout, parent, false);
|
||||
return new FaceViewHolder(faceView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull FaceViewHolder holder, int position) {
|
||||
Emoji emoji = data.get(position);
|
||||
holder.faceIv.setBackground(new BitmapDrawable(holder.itemView.getResources(), emoji.getIcon()));
|
||||
if (onEmojiClickedListener != null) {
|
||||
holder.faceIv.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onEmojiClickedListener.onEmojiClicked(emoji);
|
||||
updateRecentEmoji(emoji);
|
||||
chatPopMenu.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (data == null) {
|
||||
return 0;
|
||||
}
|
||||
return data.size();
|
||||
}
|
||||
}
|
||||
|
||||
static class FaceViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView faceIv;
|
||||
|
||||
public FaceViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
faceIv = itemView.findViewById(R.id.face_iv);
|
||||
}
|
||||
}
|
||||
|
||||
static class FaceGridDecoration extends RecyclerView.ItemDecoration {
|
||||
private final int columnNum;
|
||||
private final int leftRightSpace; // horizontal spacing
|
||||
private final int topBottomSpace; // vertical spacing
|
||||
|
||||
public FaceGridDecoration(int columnNum, int leftRightSpace, int topBottomSpace) {
|
||||
this.columnNum = columnNum;
|
||||
this.leftRightSpace = leftRightSpace;
|
||||
this.topBottomSpace = topBottomSpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
int column = position % columnNum;
|
||||
|
||||
int left = column * leftRightSpace / columnNum;
|
||||
int right = leftRightSpace * (columnNum - 1 - column) / columnNum;
|
||||
|
||||
if (LayoutUtil.isRTL()) {
|
||||
outRect.left = right;
|
||||
outRect.right = left;
|
||||
} else {
|
||||
outRect.left = left;
|
||||
outRect.right = right;
|
||||
}
|
||||
|
||||
// grid has multi rows, add top spacing
|
||||
if (position >= columnNum) {
|
||||
outRect.top = topBottomSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class GridDecoration extends RecyclerView.ItemDecoration {
|
||||
private final int columnNum;
|
||||
private final int leftRightSpace;
|
||||
private final int topBottomSpace;
|
||||
private final Drawable divider;
|
||||
|
||||
public GridDecoration(Drawable divider, int columnNum, int leftRightSpace, int topBottomSpace) {
|
||||
this.divider = divider;
|
||||
this.columnNum = columnNum;
|
||||
this.leftRightSpace = leftRightSpace;
|
||||
this.topBottomSpace = topBottomSpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
int column = position % columnNum;
|
||||
|
||||
int left = column * leftRightSpace / columnNum;
|
||||
int right = leftRightSpace * (columnNum - 1 - column) / columnNum;
|
||||
|
||||
if (LayoutUtil.isRTL()) {
|
||||
outRect.left = right;
|
||||
outRect.right = left;
|
||||
} else {
|
||||
outRect.left = left;
|
||||
outRect.right = right;
|
||||
}
|
||||
|
||||
if (position >= columnNum) {
|
||||
outRect.top = topBottomSpace;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
if (divider == null) {
|
||||
return;
|
||||
}
|
||||
canvas.save();
|
||||
final int childCount = parent.getChildCount();
|
||||
int rowNum = (int) Math.ceil(childCount * 1.0f / columnNum);
|
||||
final int divideLine = rowNum - 1;
|
||||
for (int i = 0; i < divideLine; i++) {
|
||||
View startChild = parent.getChildAt(i * columnNum);
|
||||
View endChild = parent.getChildAt((i + 1) * columnNum - 1);
|
||||
final int bottom = startChild.getBottom();
|
||||
final int top = bottom - divider.getIntrinsicHeight();
|
||||
divider.setBounds(startChild.getLeft(), top + topBottomSpace / 2, endChild.getRight(), bottom + topBottomSpace / 2);
|
||||
divider.draw(canvas);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.calssicui.widget;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUIThemeManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuichat.bean.message.FileMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuichat.bean.message.MergeMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.MessageReactionPreviewPresenter;
|
||||
|
||||
public class ChatClassicReactionPreviewProxy {
|
||||
public static void fill(TUIMessageBean messageBean, FrameLayout reactionAreaContainer) {
|
||||
int childCount = reactionAreaContainer.getChildCount();
|
||||
ChatFlowReactView flowReactView;
|
||||
if (childCount == 0) {
|
||||
flowReactView = new ChatFlowReactView(reactionAreaContainer.getContext());
|
||||
reactionAreaContainer.addView(flowReactView);
|
||||
} else {
|
||||
View view = reactionAreaContainer.getChildAt(0);
|
||||
if (view instanceof ChatFlowReactView) {
|
||||
flowReactView = (ChatFlowReactView) view;
|
||||
} else {
|
||||
flowReactView = new ChatFlowReactView(reactionAreaContainer.getContext());
|
||||
reactionAreaContainer.removeAllViews();
|
||||
reactionAreaContainer.addView(flowReactView);
|
||||
}
|
||||
}
|
||||
if (!messageBean.isSelf() || messageBean instanceof MergeMessageBean || messageBean instanceof FileMessageBean) {
|
||||
flowReactView.setThemeColorId(TUIThemeManager.getAttrResId(flowReactView.getContext(), com.tencent.qcloud.tuikit.timcommon.R.attr.chat_react_other_text_color));
|
||||
} else {
|
||||
flowReactView.setThemeColorId(0);
|
||||
}
|
||||
flowReactView.setVisibility(View.GONE);
|
||||
|
||||
MessageReactionPreviewPresenter presenter = flowReactView.getPresenter();
|
||||
presenter.loadData(messageBean);
|
||||
}
|
||||
}
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.calssicui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUIThemeManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.R;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.UserBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.FaceManager;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.ReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.common.widget.ChatReactDialogFragment;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.ReactPreviewView;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.MessageReactionPreviewPresenter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatFlowReactView extends RecyclerView implements ReactPreviewView {
|
||||
private ChatFlowReactLayoutManager layoutManager;
|
||||
private ChatFlowReactAdapter adapter;
|
||||
private int themeColorId;
|
||||
private TUIMessageBean messageBean;
|
||||
private MessageReactionPreviewPresenter presenter;
|
||||
|
||||
public ChatFlowReactView(@NonNull Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
public ChatFlowReactView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
|
||||
public ChatFlowReactView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
presenter = new MessageReactionPreviewPresenter();
|
||||
presenter.setReactPreviewView(this);
|
||||
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
|
||||
float spacingVertical = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 7.68f, displayMetrics);
|
||||
float spacingHorizontal = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5.76f, displayMetrics);
|
||||
|
||||
layoutManager = new ChatFlowReactLayoutManager(spacingHorizontal, spacingVertical);
|
||||
setLayoutManager(layoutManager);
|
||||
adapter = new ChatFlowReactAdapter();
|
||||
setAdapter(adapter);
|
||||
setOnReactionClickedListener(new OnReactionClickedListener() {
|
||||
@Override
|
||||
public void onClick(String reactionID) {
|
||||
ChatReactDialogFragment fragment = new ChatReactDialogFragment();
|
||||
fragment.setMessageBean(messageBean);
|
||||
fragment.setCurrentReactionID(reactionID);
|
||||
Context context = getContext();
|
||||
FragmentManager fragmentManager = null;
|
||||
if (context instanceof AppCompatActivity) {
|
||||
fragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
|
||||
}
|
||||
if (fragmentManager != null) {
|
||||
fragment.show(fragmentManager, "ReactionDetailDialog");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setThemeColorId(int themeColorId) {
|
||||
this.themeColorId = themeColorId;
|
||||
adapter.setThemeColorId(themeColorId);
|
||||
}
|
||||
|
||||
public void setOnReactionClickedListener(OnReactionClickedListener onReactionClickedListener) {
|
||||
if (adapter != null) {
|
||||
adapter.setOnReactionClickedListener(onReactionClickedListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void setData(MessageReactionBean messageReactionBean) {
|
||||
setVisibility(VISIBLE);
|
||||
if (adapter != null) {
|
||||
adapter.setData(messageReactionBean);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageBean(TUIMessageBean messageBean) {
|
||||
this.messageBean = messageBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TUIMessageBean getMessageBean() {
|
||||
return messageBean;
|
||||
}
|
||||
|
||||
public MessageReactionPreviewPresenter getPresenter() {
|
||||
return presenter;
|
||||
}
|
||||
|
||||
static class ChatFlowReactAdapter extends Adapter<ChatFlowReactViewHolder> {
|
||||
private MessageReactionBean data;
|
||||
private OnReactionClickedListener onReactionClickedListener;
|
||||
private int themeColorId;
|
||||
|
||||
public void setOnReactionClickedListener(OnReactionClickedListener onReactionClickedListener) {
|
||||
this.onReactionClickedListener = onReactionClickedListener;
|
||||
}
|
||||
|
||||
public void setThemeColorId(int themeColorId) {
|
||||
this.themeColorId = themeColorId;
|
||||
}
|
||||
|
||||
public void setData(MessageReactionBean data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ChatFlowReactViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_flow_react_item_layout, parent, false);
|
||||
return new ChatFlowReactViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ChatFlowReactViewHolder holder, int position) {
|
||||
ReactionBean reactionBean = new ArrayList<>(data.getMessageReactionBeanMap().values()).get(position);
|
||||
String emojiId = reactionBean.getReactionID();
|
||||
Bitmap bitmap = FaceManager.getEmoji(emojiId);
|
||||
holder.faceImageView.setImageBitmap(bitmap);
|
||||
List<UserBean> userIds = reactionBean.getPartialUserList();
|
||||
holder.userTextView.setText(formatDisplayUserName(userIds));
|
||||
holder.itemView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (onReactionClickedListener != null) {
|
||||
onReactionClickedListener.onClick(emojiId);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (themeColorId != 0) {
|
||||
holder.userTextView.setTextColor(holder.userTextView.getResources().getColor(themeColorId));
|
||||
} else {
|
||||
holder.userTextView.setTextColor(
|
||||
holder.userTextView.getResources().getColor(TUIThemeManager.getAttrResId(holder.userTextView.getContext(), com.tencent.qcloud.tuikit.timcommon.R.attr.chat_react_text_color)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (data != null) {
|
||||
return data.getReactionCount();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private String formatDisplayUserName(List<UserBean> userBeans) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
int index = 0;
|
||||
for (UserBean userBean : userBeans) {
|
||||
stringBuilder.append(userBean.getDisplayName());
|
||||
index++;
|
||||
if (index != userBeans.size()) {
|
||||
stringBuilder.append("、");
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnReactionClickedListener {
|
||||
void onClick(String reactionID);
|
||||
}
|
||||
|
||||
static class ChatFlowReactViewHolder extends ViewHolder {
|
||||
public TextView userTextView;
|
||||
public ImageView faceImageView;
|
||||
|
||||
public ChatFlowReactViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
userTextView = itemView.findViewById(R.id.users_tv);
|
||||
faceImageView = itemView.findViewById(R.id.face_iv);
|
||||
}
|
||||
}
|
||||
|
||||
// ChatReactView is just a simple flowLayout
|
||||
static class ChatFlowReactLayoutManager extends LayoutManager {
|
||||
private int verticalSpacing = 0;
|
||||
private int horizontalSpacing = 0;
|
||||
|
||||
public ChatFlowReactLayoutManager() {}
|
||||
|
||||
public ChatFlowReactLayoutManager(float horizontalSpacing, float verticalSpacing) {
|
||||
this.verticalSpacing = Math.round(verticalSpacing);
|
||||
this.horizontalSpacing = Math.round(horizontalSpacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutParams generateDefaultLayoutParams() {
|
||||
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChildren(Recycler recycler, State state) {
|
||||
detachAndScrapAttachedViews(recycler);
|
||||
int itemCount = getItemCount();
|
||||
if (itemCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isRTL = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
|
||||
int offsetTop;
|
||||
int offsetBottom;
|
||||
int offsetLeft = getPaddingEnd();
|
||||
int offsetRight = getPaddingStart();
|
||||
|
||||
boolean isLineFirstItem = true;
|
||||
boolean isFirstLine = true;
|
||||
|
||||
int currentMaxBottom = 0;
|
||||
int nextMaxBottom = 0;
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
View childView = recycler.getViewForPosition(i);
|
||||
addView(childView);
|
||||
measureChildWithMargins(childView, 0, 0);
|
||||
int childMeasuredWidth = getDecoratedMeasuredWidth(childView);
|
||||
|
||||
if (isRTL) {
|
||||
if (i != 0 && offsetLeft - horizontalSpacing - childMeasuredWidth < getPaddingEnd()) {
|
||||
// switch a new line
|
||||
isLineFirstItem = true;
|
||||
isFirstLine = false;
|
||||
currentMaxBottom = nextMaxBottom;
|
||||
}
|
||||
} else {
|
||||
if (i != 0 && offsetRight + horizontalSpacing + childMeasuredWidth > getWidth() - getPaddingStart() - getPaddingEnd()) {
|
||||
// switch a new line
|
||||
isLineFirstItem = true;
|
||||
isFirstLine = false;
|
||||
currentMaxBottom = nextMaxBottom;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLineFirstItem) {
|
||||
if (isRTL) {
|
||||
offsetLeft = getWidth() - childMeasuredWidth - getPaddingStart();
|
||||
} else {
|
||||
offsetLeft = getPaddingStart();
|
||||
}
|
||||
} else {
|
||||
if (isRTL) {
|
||||
offsetLeft = offsetLeft - horizontalSpacing - childMeasuredWidth;
|
||||
|
||||
} else {
|
||||
offsetLeft = offsetRight + horizontalSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFirstLine) {
|
||||
offsetTop = getPaddingTop();
|
||||
} else {
|
||||
offsetTop = currentMaxBottom + verticalSpacing;
|
||||
}
|
||||
int childMeasuredHeight = getDecoratedMeasuredHeight(childView);
|
||||
|
||||
offsetRight = offsetLeft + childMeasuredWidth;
|
||||
offsetBottom = offsetTop + childMeasuredHeight;
|
||||
nextMaxBottom = Math.max(nextMaxBottom, offsetBottom);
|
||||
|
||||
layoutDecoratedWithMargins(childView, offsetLeft, offsetTop, offsetRight, offsetBottom);
|
||||
|
||||
isLineFirstItem = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoMeasureEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.common.widget;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUIValueCallback;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.UserBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.FaceManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.impl.GlideEngine;
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.ScreenUtil;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.R;
|
||||
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionUserBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.ReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.TUIEmojiPresenter;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.util.TUIEmojiLog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChatReactDialogFragment extends DialogFragment {
|
||||
private static final String TAG = "ChatReactDialogFragment";
|
||||
private BottomSheetDialog dialog;
|
||||
|
||||
private TUIMessageBean messageBean;
|
||||
private MessageReactionBean messageReactionBean;
|
||||
private String currentReactionID;
|
||||
|
||||
private RecyclerView reactCategoryList;
|
||||
|
||||
private ViewPager2 reactViewPager;
|
||||
|
||||
private TUIEmojiPresenter reactPresenter;
|
||||
|
||||
private OnReactClickListener onReactClickListener;
|
||||
|
||||
private ChatInfo chatInfo;
|
||||
|
||||
private ReactCategoryAdapter categoryAdapter;
|
||||
private ReactDetailAdapter detailAdapter;
|
||||
|
||||
public void setMessageBean(TUIMessageBean messageBean) {
|
||||
this.messageBean = messageBean;
|
||||
}
|
||||
|
||||
public void setChatInfo(ChatInfo chatInfo) {
|
||||
this.chatInfo = chatInfo;
|
||||
}
|
||||
|
||||
public void setOnReactClickListener(OnReactClickListener onReactClickListener) {
|
||||
this.onReactClickListener = onReactClickListener;
|
||||
}
|
||||
|
||||
public void setCurrentReactionID(String currentReactionID) {
|
||||
this.currentReactionID = currentReactionID;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
dialog = new BottomSheetDialog(getContext(), R.style.TUIEmojiTranslucentBgStyle);
|
||||
dialog.setCanceledOnTouchOutside(true);
|
||||
BottomSheetBehavior<FrameLayout> bottomSheetBehavior = dialog.getBehavior();
|
||||
bottomSheetBehavior.setFitToContents(false);
|
||||
bottomSheetBehavior.setHalfExpandedRatio(0.45f);
|
||||
bottomSheetBehavior.setSkipCollapsed(false);
|
||||
bottomSheetBehavior.setExpandedOffset(ScreenUtil.dip2px(36));
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.chat_react_dialog_layout, container);
|
||||
reactViewPager = view.findViewById(R.id.react_view_pager);
|
||||
reactCategoryList = view.findViewById(R.id.react_category_list);
|
||||
initView();
|
||||
initData();
|
||||
return view;
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
reactViewPager.setUserInputEnabled(false);
|
||||
reactViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
categoryAdapter.notifyDataSetChanged();
|
||||
reactCategoryList.smoothScrollToPosition(position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
reactPresenter = new TUIEmojiPresenter();
|
||||
reactCategoryList.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.HORIZONTAL, false));
|
||||
categoryAdapter = new ReactCategoryAdapter();
|
||||
reactCategoryList.setAdapter(categoryAdapter);
|
||||
detailAdapter = new ReactDetailAdapter();
|
||||
reactViewPager.setAdapter(detailAdapter);
|
||||
|
||||
setOnReactClickListener(new OnReactClickListener() {
|
||||
@Override
|
||||
public void onClick(String reactionID) {
|
||||
reactPresenter.removeMessageReaction(messageBean, reactionID, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUIEmojiLog.i(TAG, "remove success");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.i(TAG, "remove reaction failed, code=" + errorCode + ", msg=" + errorMessage);
|
||||
}
|
||||
});
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
reactPresenter.getMessageReactions(Collections.singletonList(messageBean), 1, new TUIValueCallback<List<MessageReactionBean>>() {
|
||||
@Override
|
||||
public void onSuccess(List<MessageReactionBean> object) {
|
||||
if (!object.isEmpty()) {
|
||||
messageReactionBean = object.get(0);
|
||||
if (TextUtils.isEmpty(currentReactionID)) {
|
||||
currentReactionID = getReactionID(0);
|
||||
}
|
||||
categoryAdapter.notifyDataSetChanged();
|
||||
detailAdapter.notifyDataSetChanged();
|
||||
onReactionSelected(currentReactionID);
|
||||
} else {
|
||||
TUIEmojiLog.e(TAG, "getMessageReactions failed, message reaction list is empty");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.e(TAG, "getMessageReactions failed, code=" + errorCode + ",msg=" + errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onReactionSelected(String reactionID) {
|
||||
currentReactionID = reactionID;
|
||||
int index = getReactionIDIndex();
|
||||
reactViewPager.setCurrentItem(index);
|
||||
}
|
||||
|
||||
private int getReactionIDIndex() {
|
||||
if (messageReactionBean == null || messageReactionBean.getReactionCount() <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return new ArrayList<>(messageReactionBean.getMessageReactionBeanMap().keySet()).indexOf(currentReactionID);
|
||||
}
|
||||
|
||||
private String getReactionID(int index) {
|
||||
if (messageReactionBean == null || messageReactionBean.getReactionCount() <= 0) {
|
||||
return "";
|
||||
}
|
||||
return new ArrayList<>(messageReactionBean.getMessageReactionBeanMap().keySet()).get(index);
|
||||
}
|
||||
|
||||
class ReactDetailAdapter extends RecyclerView.Adapter<ReactDetailAdapter.ReactDetailHolder> {
|
||||
@NonNull
|
||||
@Override
|
||||
public ReactDetailHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.minimalist_react_view_pager_layout, parent, false);
|
||||
ReactDetailHolder holder = new ReactDetailHolder(view);
|
||||
holder.recyclerView.setLayoutManager(new LinearLayoutManager(parent.getContext()));
|
||||
holder.recyclerView.setAdapter(new ReactUserAdapter());
|
||||
return holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ReactDetailHolder holder, int position) {
|
||||
ReactUserAdapter adapter = (ReactUserAdapter) holder.recyclerView.getAdapter();
|
||||
String reactionID = getReactionID(position);
|
||||
adapter.reactionID = reactionID;
|
||||
reactPresenter.getAllUserListOfMessageReaction(messageBean, reactionID, 0, 100, new TUIValueCallback<MessageReactionUserBean>() {
|
||||
@Override
|
||||
public void onSuccess(MessageReactionUserBean object) {
|
||||
if (TextUtils.equals(reactionID, adapter.reactionID)) {
|
||||
adapter.messageReactionUserBean = object;
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.e(TAG, "getAllUserListOfMessageReaction failed, code=" + errorCode + ", msg=" + errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (messageReactionBean == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return messageReactionBean.getReactionCount();
|
||||
}
|
||||
}
|
||||
|
||||
class ReactDetailHolder extends RecyclerView.ViewHolder {
|
||||
private RecyclerView recyclerView;
|
||||
private String reactionID;
|
||||
|
||||
public ReactDetailHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
recyclerView = itemView.findViewById(R.id.react_user_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReactUserAdapter extends RecyclerView.Adapter<ReactUserAdapter.ReactUserViewHolder> {
|
||||
private MessageReactionUserBean messageReactionUserBean;
|
||||
private String reactionID;
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ReactUserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.minimalist_react_details_layout, parent, false);
|
||||
return new ReactUserViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ReactUserViewHolder holder, int position) {
|
||||
UserBean reactUserBean = messageReactionUserBean.getUserBeanList().get(position);
|
||||
GlideEngine.loadImage(holder.userFace, reactUserBean.getFaceUrl());
|
||||
holder.userName.setText(reactUserBean.getDisplayName());
|
||||
if (TextUtils.equals(reactUserBean.getUserId(), TUILogin.getLoginUser())) {
|
||||
holder.tips.setText(getResources().getString(R.string.chat_tap_to_remove));
|
||||
holder.tips.setVisibility(View.VISIBLE);
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (onReactClickListener != null) {
|
||||
onReactClickListener.onClick(reactionID);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
holder.tips.setVisibility(View.GONE);
|
||||
holder.itemView.setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (messageReactionUserBean == null || messageReactionUserBean.getUserBeanList() == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return messageReactionUserBean.getUserBeanList().size();
|
||||
}
|
||||
}
|
||||
|
||||
class ReactUserViewHolder extends RecyclerView.ViewHolder {
|
||||
private ImageView userFace;
|
||||
private ImageView emojiIcon;
|
||||
private TextView userName;
|
||||
private TextView tips;
|
||||
|
||||
public ReactUserViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
userFace = itemView.findViewById(R.id.user_face);
|
||||
emojiIcon = itemView.findViewById(R.id.emoji_icon);
|
||||
userName = itemView.findViewById(R.id.user_name);
|
||||
tips = itemView.findViewById(R.id.tips);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReactCategoryAdapter extends RecyclerView.Adapter<ReactCategoryAdapter.ReactCategoryHolder> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ReactCategoryHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.minimalist_react_category_layout, parent, false);
|
||||
return new ReactCategoryHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ReactCategoryHolder holder, int position) {
|
||||
Map<String, ReactionBean> reactionBeanMap = messageReactionBean.getMessageReactionBeanMap();
|
||||
String reactionID = new ArrayList<>(reactionBeanMap.keySet()).get(position);
|
||||
if (TextUtils.equals(currentReactionID, reactionID)) {
|
||||
holder.itemView.setBackgroundResource(R.drawable.tuiemoji_gray_round_rect_bg);
|
||||
} else {
|
||||
holder.itemView.setBackground(null);
|
||||
}
|
||||
holder.reactImg.setImageBitmap(FaceManager.getEmoji(reactionID));
|
||||
ReactionBean reactionBean = reactionBeanMap.get(reactionID);
|
||||
holder.reactNum.setText(reactionBean.getTotalUserCount() + "");
|
||||
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onReactionSelected(reactionID);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (messageReactionBean == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return messageReactionBean.getReactionCount();
|
||||
}
|
||||
}
|
||||
|
||||
class ReactCategoryHolder extends RecyclerView.ViewHolder {
|
||||
private TextView categoryName;
|
||||
private ImageView reactImg;
|
||||
private TextView reactNum;
|
||||
|
||||
public ReactCategoryHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
categoryName = itemView.findViewById(R.id.category_name);
|
||||
reactNum = itemView.findViewById(R.id.react_num);
|
||||
reactImg = itemView.findViewById(R.id.react_img);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnReactClickListener {
|
||||
void onClick(String reactionID);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces;
|
||||
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.Emoji;
|
||||
|
||||
public interface OnEmojiClickedListener {
|
||||
void onEmojiClicked(Emoji emoji);
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OnMessageReactionsChangedListener {
|
||||
void onMessageReactionsChanged(MessageReactionBean messageReactionBean);
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces;
|
||||
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
|
||||
public interface ReactPreviewView {
|
||||
void setData(MessageReactionBean messageReactionBean);
|
||||
TUIMessageBean getMessageBean();
|
||||
void setMessageBean(TUIMessageBean messageBean);
|
||||
}
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.minimalistui.widget;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
|
||||
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter;
|
||||
import com.tencent.qcloud.tuicore.util.ToastUtil;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.Emoji;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.FaceManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.RecentEmojiManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.LayoutUtil;
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.ScreenUtil;
|
||||
import com.tencent.qcloud.tuikit.tuichat.minimalistui.widget.messagepopmenu.ChatPopActivity;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.R;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.ReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.OnEmojiClickedListener;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.MessageReactionBeanCache;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.TUIEmojiPresenter;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.util.TUIEmojiLog;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatMinimalistPopMenuReactProxy {
|
||||
private static final String TAG = ChatMinimalistPopMenuReactProxy.class.getSimpleName();
|
||||
private RecyclerView recentFaceView;
|
||||
private final List<Emoji> emojiList = new ArrayList<>();
|
||||
private final List<String> recentEmojiList = new ArrayList<>();
|
||||
private static final int RECENT_EMOJI_NUM = 6;
|
||||
private static final String RECENT_EMOJI_KEY = "recentEmoji";
|
||||
private ChatPopActivity chatPopActivity;
|
||||
private TUIEmojiPresenter presenter;
|
||||
private OnEmojiClickedListener onEmojiClickedListener;
|
||||
|
||||
public void fill() {
|
||||
presenter = new TUIEmojiPresenter();
|
||||
initEmojiList();
|
||||
|
||||
// recent faces
|
||||
recentFaceView = (RecyclerView) LayoutInflater.from(chatPopActivity).inflate(R.layout.tuiemoji_minimalist_chat_popup_react_area, null);
|
||||
FrameLayout reactionArea = chatPopActivity.getReactionArea();
|
||||
reactionArea.addView(recentFaceView);
|
||||
recentFaceView.setItemAnimator(null);
|
||||
LinearLayoutManager recentLayoutManager = new LinearLayoutManager(chatPopActivity, RecyclerView.HORIZONTAL, false);
|
||||
int recentSpacing = ScreenUtil.dip2px(8f);
|
||||
recentFaceView.addItemDecoration(new GridDecoration(null, RECENT_EMOJI_NUM + 1, recentSpacing, 0));
|
||||
recentFaceView.setLayoutManager(recentLayoutManager);
|
||||
RecentFaceAdapter recentFaceAdapter = new RecentFaceAdapter();
|
||||
recentFaceView.setAdapter(recentFaceAdapter);
|
||||
if (!chatPopActivity.isShowFaces()) {
|
||||
recentFaceView.setVisibility(View.GONE);
|
||||
}
|
||||
onEmojiClickedListener = new OnEmojiClickedListener() {
|
||||
@Override
|
||||
public void onEmojiClicked(Emoji emoji) {
|
||||
MessageReactionBean messageReactionBean = MessageReactionBeanCache.getMessageReactionBean(chatPopActivity.getMessageBean().getId());
|
||||
if (messageReactionBean != null) {
|
||||
ReactionBean reactionBean = messageReactionBean.getReactionBean(emoji.getFaceKey());
|
||||
if (reactionBean == null) {
|
||||
addMessageReaction(chatPopActivity.getMessageBean(), emoji.getFaceKey());
|
||||
} else {
|
||||
if (reactionBean.isByMySelf()) {
|
||||
removeMessageReaction(chatPopActivity.getMessageBean(), emoji.getFaceKey());
|
||||
} else {
|
||||
addMessageReaction(chatPopActivity.getMessageBean(), emoji.getFaceKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
RecentEmojiManager.updateRecentUseEmoji(emoji.getFaceKey());
|
||||
chatPopActivity.hide();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void addMessageReaction(TUIMessageBean messageBean, String reactionID) {
|
||||
presenter.addMessageReaction(messageBean, reactionID, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUIEmojiLog.i(TAG, "addMessageReaction success " + messageBean.getId() + " " + reactionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.e(TAG, "addMessageReaction failed code " + errorCode + ",message " + errorMessage);
|
||||
ToastUtil.toastLongMessage(
|
||||
chatPopActivity.getString(R.string.tuiemoji_add_reaction_failed_tip) + " " + ErrorMessageConverter.convertIMError(errorCode, errorMessage));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void removeMessageReaction(TUIMessageBean messageBean, String reactionID) {
|
||||
presenter.removeMessageReaction(messageBean, reactionID, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUIEmojiLog.i(TAG, "removeMessageReaction success " + messageBean.getId() + " " + reactionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUIEmojiLog.e(TAG, "addMessageReaction failed code " + errorCode + ",message " + errorMessage);
|
||||
ToastUtil.toastLongMessage(
|
||||
chatPopActivity.getString(R.string.tuiemoji_remove_reaction_failed_tip) + " " + ErrorMessageConverter.convertIMError(errorCode, errorMessage));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setChatPopActivity(ChatPopActivity chatPopActivity) {
|
||||
this.chatPopActivity = chatPopActivity;
|
||||
}
|
||||
|
||||
private void initEmojiList() {
|
||||
emojiList.addAll(FaceManager.getEmojiList());
|
||||
initDefaultEmoji();
|
||||
}
|
||||
|
||||
private void initDefaultEmoji() {
|
||||
List<String> emojis = null;
|
||||
emojis = (List<String>) RecentEmojiManager.getCollection();
|
||||
if (emojis == null) {
|
||||
List<Emoji> subList = emojiList.subList(0, RECENT_EMOJI_NUM);
|
||||
List<String> emojiKeys = new ArrayList<>();
|
||||
for (Emoji emoji : subList) {
|
||||
emojiKeys.add(emoji.getFaceKey());
|
||||
}
|
||||
emojis = new ArrayList<>(emojiKeys);
|
||||
RecentEmojiManager.getInstance().putCollection(RECENT_EMOJI_KEY, emojis);
|
||||
}
|
||||
recentEmojiList.addAll(emojis);
|
||||
}
|
||||
|
||||
private void updateRecentEmoji(Emoji emoji) {
|
||||
recentEmojiList.remove(emoji.getFaceKey());
|
||||
recentEmojiList.add(0, emoji.getFaceKey());
|
||||
RecentEmojiManager.updateRecentUseEmoji(emoji.getFaceKey());
|
||||
}
|
||||
|
||||
class RecentFaceAdapter extends RecyclerView.Adapter<RecentFaceAdapter.RecentFaceViewHolder> {
|
||||
private Emoji moreBtn;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecentFaceAdapter.RecentFaceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View faceView = LayoutInflater.from(parent.getContext()).inflate(R.layout.tuiemoji_chat_menu_recent_face_item_layout, parent, false);
|
||||
moreBtn = new Emoji();
|
||||
Bitmap bitMap = BitmapFactory.decodeResource(parent.getResources(), R.drawable.tuiemoji_pop_menu_add_icon);
|
||||
moreBtn.setIcon(bitMap);
|
||||
return new RecentFaceAdapter.RecentFaceViewHolder(faceView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecentFaceAdapter.RecentFaceViewHolder holder, int position) {
|
||||
Emoji emoji;
|
||||
if (position == RECENT_EMOJI_NUM) {
|
||||
emoji = moreBtn;
|
||||
} else {
|
||||
emoji = getEmoji(recentEmojiList.get(position));
|
||||
}
|
||||
if (emoji == null) {
|
||||
return;
|
||||
}
|
||||
holder.faceIv.setImageBitmap(emoji.getIcon());
|
||||
holder.faceIv.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onEmojiClicked(emoji);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onEmojiClicked(Emoji emoji) {
|
||||
if (emoji == moreBtn) {
|
||||
ChatPopMenuEmojiDialogFragment dialogFragment = new ChatPopMenuEmojiDialogFragment();
|
||||
dialogFragment.setEmojiClickListener(new ChatPopMenuEmojiDialogFragment.EmojiClickListener() {
|
||||
@Override
|
||||
public void onClick(Emoji clickedEmoji) {
|
||||
onEmojiClickedListener.onEmojiClicked(clickedEmoji);
|
||||
}
|
||||
});
|
||||
dialogFragment.show(chatPopActivity.getSupportFragmentManager(), "ChatEmoji");
|
||||
return;
|
||||
}
|
||||
onEmojiClickedListener.onEmojiClicked(emoji);
|
||||
updateRecentEmoji(emoji);
|
||||
chatPopActivity.hide();
|
||||
}
|
||||
|
||||
private Emoji getEmoji(String emojiKey) {
|
||||
for (Emoji emoji : emojiList) {
|
||||
if (TextUtils.equals(emoji.getFaceKey(), emojiKey)) {
|
||||
return emoji;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return RECENT_EMOJI_NUM + 1;
|
||||
}
|
||||
|
||||
class RecentFaceViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView faceIv;
|
||||
|
||||
public RecentFaceViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
faceIv = itemView.findViewById(R.id.face_iv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class GridDecoration extends RecyclerView.ItemDecoration {
|
||||
private final int columnNum;
|
||||
private final int leftRightSpace;
|
||||
private final int topBottomSpace;
|
||||
private final Drawable divider;
|
||||
|
||||
public GridDecoration(Drawable divider, int columnNum, int leftRightSpace, int topBottomSpace) {
|
||||
this.divider = divider;
|
||||
this.columnNum = columnNum;
|
||||
this.leftRightSpace = leftRightSpace;
|
||||
this.topBottomSpace = topBottomSpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
int column = position % columnNum;
|
||||
|
||||
int left = column * leftRightSpace / columnNum;
|
||||
int right = leftRightSpace * (columnNum - 1 - column) / columnNum;
|
||||
if (LayoutUtil.isRTL()) {
|
||||
outRect.left = right;
|
||||
outRect.right = left;
|
||||
} else {
|
||||
outRect.left = left;
|
||||
outRect.right = right;
|
||||
}
|
||||
|
||||
if (position >= columnNum) {
|
||||
outRect.top = topBottomSpace;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
if (divider == null) {
|
||||
return;
|
||||
}
|
||||
canvas.save();
|
||||
final int childCount = parent.getChildCount();
|
||||
int rowNum = (int) Math.ceil(childCount * 1.0f / columnNum);
|
||||
final int divideLine = rowNum - 1;
|
||||
for (int i = 0; i < divideLine; i++) {
|
||||
View startChild = parent.getChildAt(i * columnNum);
|
||||
View endChild = parent.getChildAt((i + 1) * columnNum - 1);
|
||||
final int bottom = startChild.getBottom();
|
||||
final int top = bottom - divider.getIntrinsicHeight();
|
||||
divider.setBounds(startChild.getLeft(), top + topBottomSpace / 2, endChild.getRight(), bottom + topBottomSpace / 2);
|
||||
divider.draw(canvas);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.minimalistui.widget;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.MessageReactionPreviewPresenter;
|
||||
|
||||
public class ChatMinimalistReactionPreviewProxy {
|
||||
public static void fill(TUIMessageBean messageBean, FrameLayout reactionAreaContainer) {
|
||||
int childCount = reactionAreaContainer.getChildCount();
|
||||
ChatReactView reactView;
|
||||
if (childCount == 0) {
|
||||
reactView = new ChatReactView(reactionAreaContainer.getContext());
|
||||
reactionAreaContainer.addView(reactView);
|
||||
} else {
|
||||
View view = reactionAreaContainer.getChildAt(0);
|
||||
if (view instanceof ChatReactView) {
|
||||
reactView = (ChatReactView) view;
|
||||
} else {
|
||||
reactView = new ChatReactView(reactionAreaContainer.getContext());
|
||||
reactionAreaContainer.removeAllViews();
|
||||
reactionAreaContainer.addView(reactView);
|
||||
}
|
||||
}
|
||||
reactView.setVisibility(View.GONE);
|
||||
|
||||
MessageReactionPreviewPresenter presenter = reactView.getPresenter();
|
||||
presenter.loadData(messageBean);
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.minimalistui.widget;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.Emoji;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.FaceManager;
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.LayoutUtil;
|
||||
import com.tencent.qcloud.tuikit.timcommon.util.ScreenUtil;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ChatPopMenuEmojiDialogFragment extends DialogFragment {
|
||||
public static final int SPAN_COUNT = 7;
|
||||
|
||||
private BottomSheetDialog dialog;
|
||||
|
||||
private RecyclerView emojiGridList;
|
||||
|
||||
private List<Emoji> emojiList;
|
||||
|
||||
private EmojiClickListener emojiClickListener;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
dialog = new BottomSheetDialog(getContext(), R.style.TUIEmojiTranslucentBgStyle);
|
||||
dialog.setCanceledOnTouchOutside(true);
|
||||
BottomSheetBehavior<FrameLayout> bottomSheetBehavior = dialog.getBehavior();
|
||||
bottomSheetBehavior.setFitToContents(false);
|
||||
bottomSheetBehavior.setHalfExpandedRatio(0.45f);
|
||||
bottomSheetBehavior.setSkipCollapsed(true);
|
||||
bottomSheetBehavior.setExpandedOffset(ScreenUtil.dip2px(36));
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.chat_popmenu_emoji_dialog_layout, container);
|
||||
emojiGridList = view.findViewById(R.id.emoji_grid_list);
|
||||
initData();
|
||||
return view;
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
emojiList = FaceManager.getEmojiList();
|
||||
emojiGridList.setLayoutManager(new GridLayoutManager(getContext(), SPAN_COUNT));
|
||||
emojiGridList.setAdapter(new EmojiAdapter());
|
||||
emojiGridList.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FaceGridDecoration decoration = new FaceGridDecoration(SPAN_COUNT)
|
||||
.setTopBottomSpace(ScreenUtil.dip2px(10))
|
||||
.setWidth(emojiGridList.getWidth())
|
||||
.setItemWidth(emojiGridList.getChildAt(0).getWidth());
|
||||
emojiGridList.addItemDecoration(decoration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setEmojiClickListener(EmojiClickListener emojiClickListener) {
|
||||
this.emojiClickListener = emojiClickListener;
|
||||
}
|
||||
|
||||
class EmojiAdapter extends RecyclerView.Adapter<EmojiAdapter.EmojiHolder> {
|
||||
@NonNull
|
||||
@Override
|
||||
public EmojiHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_pop_menu_emoji_item_layout, parent, false);
|
||||
return new EmojiHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull EmojiHolder holder, int position) {
|
||||
Emoji emoji = emojiList.get(position);
|
||||
holder.emojiImg.setImageBitmap(emoji.getIcon());
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (emojiClickListener != null) {
|
||||
emojiClickListener.onClick(emoji);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (emojiList == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return emojiList.size();
|
||||
}
|
||||
}
|
||||
|
||||
class EmojiHolder extends RecyclerView.ViewHolder {
|
||||
private final ImageView emojiImg;
|
||||
|
||||
public EmojiHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
emojiImg = itemView.findViewById(R.id.emoji_img);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class FaceGridDecoration extends RecyclerView.ItemDecoration {
|
||||
private final int columnNum;
|
||||
private int topBottomSpace;
|
||||
private int width;
|
||||
private int itemWidth;
|
||||
|
||||
public FaceGridDecoration(int columnNum) {
|
||||
this.columnNum = columnNum;
|
||||
}
|
||||
|
||||
public FaceGridDecoration setTopBottomSpace(int space) {
|
||||
this.topBottomSpace = space;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FaceGridDecoration setWidth(int width) {
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FaceGridDecoration setItemWidth(int itemWidth) {
|
||||
this.itemWidth = itemWidth;
|
||||
return this;
|
||||
}
|
||||
|
||||
private int getLeftRightSpace() {
|
||||
return (width - (columnNum * itemWidth)) / (columnNum - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
int column = position % columnNum;
|
||||
int leftRightSpace = getLeftRightSpace();
|
||||
int right = leftRightSpace * (columnNum - 1 - column) / columnNum;
|
||||
int left = column * leftRightSpace / columnNum;
|
||||
if (LayoutUtil.isRTL()) {
|
||||
outRect.right = left;
|
||||
outRect.left = right;
|
||||
} else {
|
||||
outRect.left = left;
|
||||
outRect.right = right;
|
||||
}
|
||||
|
||||
outRect.top = topBottomSpace;
|
||||
outRect.bottom = topBottomSpace;
|
||||
}
|
||||
}
|
||||
|
||||
interface EmojiClickListener {
|
||||
void onClick(Emoji emoji);
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.minimalistui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.component.face.FaceManager;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.R;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.ReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.common.widget.ChatReactDialogFragment;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.ReactPreviewView;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.presenter.MessageReactionPreviewPresenter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChatReactView extends FrameLayout implements ReactPreviewView {
|
||||
private static final int EMOJI_LIMIT = 5;
|
||||
private LinearLayoutManager layoutManager;
|
||||
private TextView reactNumText;
|
||||
private View moreIcon;
|
||||
private RecyclerView reactRecyclerView;
|
||||
private ChatReactAdapter adapter;
|
||||
private MessageReactionPreviewPresenter presenter;
|
||||
private TUIMessageBean messageBean;
|
||||
|
||||
public ChatReactView(@NonNull Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
public ChatReactView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
|
||||
public ChatReactView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
presenter = new MessageReactionPreviewPresenter();
|
||||
presenter.setReactPreviewView(this);
|
||||
View view = LayoutInflater.from(getContext()).inflate(R.layout.chat_minimalist_react_preview_layout, this);
|
||||
reactRecyclerView = view.findViewById(R.id.reacts_emoji_list);
|
||||
reactNumText = view.findViewById(R.id.reacts_num_text);
|
||||
moreIcon = view.findViewById(R.id.more_icon);
|
||||
layoutManager = new LinearLayoutManager(getContext());
|
||||
layoutManager.setOrientation(RecyclerView.HORIZONTAL);
|
||||
reactRecyclerView.setLayoutManager(layoutManager);
|
||||
adapter = new ChatReactAdapter();
|
||||
reactRecyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
public void setData(MessageReactionBean messageReactionBean) {
|
||||
setVisibility(VISIBLE);
|
||||
int num = messageReactionBean.getReactionCount();
|
||||
int allReactionsUserNum = 0;
|
||||
for (ReactionBean reactionBean : messageReactionBean.getMessageReactionBeanMap().values()) {
|
||||
allReactionsUserNum += reactionBean.getTotalUserCount();
|
||||
}
|
||||
reactNumText.setText(allReactionsUserNum + "");
|
||||
if (num > EMOJI_LIMIT) {
|
||||
moreIcon.setVisibility(VISIBLE);
|
||||
} else {
|
||||
moreIcon.setVisibility(GONE);
|
||||
}
|
||||
if (num <= 0) {
|
||||
setVisibility(GONE);
|
||||
return;
|
||||
} else {
|
||||
setVisibility(VISIBLE);
|
||||
}
|
||||
if (adapter != null) {
|
||||
adapter.setData(messageReactionBean);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
OnClickListener onClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showReactionDetailDialog();
|
||||
}
|
||||
};
|
||||
setOnClickListener(onClickListener);
|
||||
adapter.clickListener = onClickListener;
|
||||
}
|
||||
|
||||
private void showReactionDetailDialog() {
|
||||
ChatReactDialogFragment fragment = new ChatReactDialogFragment();
|
||||
fragment.setMessageBean(messageBean);
|
||||
Context context = getContext();
|
||||
FragmentManager fragmentManager = null;
|
||||
if (context instanceof AppCompatActivity) {
|
||||
fragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
|
||||
}
|
||||
if (fragmentManager != null) {
|
||||
fragment.show(fragmentManager, "ReactionDetailDialog");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TUIMessageBean getMessageBean() {
|
||||
return messageBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageBean(TUIMessageBean messageBean) {
|
||||
this.messageBean = messageBean;
|
||||
}
|
||||
|
||||
public void setPresenter(MessageReactionPreviewPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
public MessageReactionPreviewPresenter getPresenter() {
|
||||
return presenter;
|
||||
}
|
||||
|
||||
static class ChatReactAdapter extends RecyclerView.Adapter<ChatReactViewHolder> {
|
||||
private MessageReactionBean data;
|
||||
private OnClickListener clickListener;
|
||||
|
||||
public void setData(MessageReactionBean data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ChatReactViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_minimalist_react_item_layout, parent, false);
|
||||
return new ChatReactViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ChatReactViewHolder holder, int position) {
|
||||
ReactionBean reactionBean = new ArrayList<>(data.getMessageReactionBeanMap().values()).get(position);
|
||||
String emojiId = reactionBean.getReactionID();
|
||||
Bitmap bitmap = FaceManager.getEmoji(emojiId);
|
||||
holder.faceImageView.setImageBitmap(bitmap);
|
||||
holder.itemView.setOnClickListener(clickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (data != null) {
|
||||
return Math.min(data.getReactionCount(), EMOJI_LIMIT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class ChatReactViewHolder extends RecyclerView.ViewHolder {
|
||||
public ImageView faceImageView;
|
||||
|
||||
public ChatReactViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
faceImageView = itemView.findViewById(R.id.face_iv);
|
||||
}
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.model;
|
||||
|
||||
import com.tencent.imsdk.v2.V2TIMCallback;
|
||||
import com.tencent.imsdk.v2.V2TIMManager;
|
||||
import com.tencent.imsdk.v2.V2TIMMessage;
|
||||
import com.tencent.imsdk.v2.V2TIMMessageReaction;
|
||||
import com.tencent.imsdk.v2.V2TIMMessageReactionResult;
|
||||
import com.tencent.imsdk.v2.V2TIMMessageReactionUserResult;
|
||||
import com.tencent.imsdk.v2.V2TIMUserInfo;
|
||||
import com.tencent.imsdk.v2.V2TIMValueCallback;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUIValueCallback;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.UserBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionUserBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.ReactionBean;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TUIEmojiProvider {
|
||||
public void addMessageReaction(TUIMessageBean messageBean, String reactionID, TUICallback callback) {
|
||||
V2TIMMessage message = messageBean.getV2TIMMessage();
|
||||
V2TIMManager.getMessageManager().addMessageReaction(message, reactionID, new V2TIMCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallback.onSuccess(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String desc) {
|
||||
TUICallback.onError(callback, code, desc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeMessageReaction(TUIMessageBean messageBean, String reactionID, TUICallback callback) {
|
||||
V2TIMMessage message = messageBean.getV2TIMMessage();
|
||||
V2TIMManager.getMessageManager().removeMessageReaction(message, reactionID, new V2TIMCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallback.onSuccess(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String desc) {
|
||||
TUICallback.onError(callback, code, desc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getMessageReactions(List<TUIMessageBean> messageBeans, int countPerReaction, TUIValueCallback<List<MessageReactionBean>> callback) {
|
||||
if (messageBeans == null) {
|
||||
return;
|
||||
}
|
||||
List<V2TIMMessage> messages = new ArrayList<>();
|
||||
for (TUIMessageBean messageBean : messageBeans) {
|
||||
if (messageBean.getStatus() == TUIMessageBean.MSG_STATUS_SEND_FAIL) {
|
||||
continue;
|
||||
}
|
||||
if (messageBean.getV2TIMMessage() != null) {
|
||||
messages.add(messageBean.getV2TIMMessage());
|
||||
}
|
||||
}
|
||||
V2TIMManager.getMessageManager().getMessageReactions(messages, countPerReaction, new V2TIMValueCallback<List<V2TIMMessageReactionResult>>() {
|
||||
@Override
|
||||
public void onSuccess(List<V2TIMMessageReactionResult> v2TIMMessageReactionResults) {
|
||||
List<MessageReactionBean> messageReactionBeanList = new ArrayList<>();
|
||||
for (V2TIMMessageReactionResult reactionResult : v2TIMMessageReactionResults) {
|
||||
MessageReactionBean messageReactionBean = new MessageReactionBean();
|
||||
messageReactionBean.setMessageID(reactionResult.getMessageID());
|
||||
List<V2TIMMessageReaction> v2TIMMessageReactionList = reactionResult.getReactionList();
|
||||
Map<String, ReactionBean> reactionBeanMap = new LinkedHashMap<>();
|
||||
if (v2TIMMessageReactionList != null) {
|
||||
for (V2TIMMessageReaction reaction : v2TIMMessageReactionList) {
|
||||
ReactionBean reactionBean = new ReactionBean();
|
||||
reactionBean.setReactionID(reaction.getReactionID());
|
||||
reactionBean.setByMySelf(reaction.getReactedByMyself());
|
||||
reactionBean.setTotalUserCount(reaction.getTotalUserCount());
|
||||
List<V2TIMUserInfo> v2TIMUserInfoList = reaction.getPartialUserList();
|
||||
List<UserBean> userBeanList = new ArrayList<>();
|
||||
if (v2TIMUserInfoList != null) {
|
||||
for (V2TIMUserInfo v2TIMUserInfo : v2TIMUserInfoList) {
|
||||
UserBean reactUserBean = new UserBean();
|
||||
reactUserBean.setUserId(v2TIMUserInfo.getUserID());
|
||||
reactUserBean.setNickName(v2TIMUserInfo.getNickName());
|
||||
reactUserBean.setFaceUrl(v2TIMUserInfo.getFaceUrl());
|
||||
userBeanList.add(reactUserBean);
|
||||
}
|
||||
reactionBean.setPartialUserList(userBeanList);
|
||||
}
|
||||
reactionBeanMap.put(reactionBean.getReactionID(), reactionBean);
|
||||
}
|
||||
}
|
||||
messageReactionBean.setMessageReactionBeanMap(reactionBeanMap);
|
||||
messageReactionBeanList.add(messageReactionBean);
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.onSuccess(messageReactionBeanList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String desc) {
|
||||
if (callback != null) {
|
||||
callback.onError(code, desc);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getAllUserListOfMessageReaction(
|
||||
TUIMessageBean messageBean, String reactionID, int nextSeq, int count, TUIValueCallback<MessageReactionUserBean> callback) {
|
||||
V2TIMMessage message = messageBean.getV2TIMMessage();
|
||||
V2TIMManager.getMessageManager().getAllUserListOfMessageReaction(
|
||||
message, reactionID, nextSeq, count, new V2TIMValueCallback<V2TIMMessageReactionUserResult>() {
|
||||
@Override
|
||||
public void onSuccess(V2TIMMessageReactionUserResult v2TIMMessageReactionUserResult) {
|
||||
MessageReactionUserBean resultBean = new MessageReactionUserBean();
|
||||
resultBean.setFinished(v2TIMMessageReactionUserResult.getIsFinished());
|
||||
resultBean.setNextSeq(v2TIMMessageReactionUserResult.getNextSeq());
|
||||
List<UserBean> userBeanList = new ArrayList<>();
|
||||
List<V2TIMUserInfo> v2TIMUserInfoList = v2TIMMessageReactionUserResult.getUserInfoList();
|
||||
if (v2TIMUserInfoList != null) {
|
||||
for (V2TIMUserInfo userInfo : v2TIMUserInfoList) {
|
||||
UserBean reactUserBean = new UserBean();
|
||||
reactUserBean.setUserId(userInfo.getUserID());
|
||||
reactUserBean.setNickName(userInfo.getNickName());
|
||||
reactUserBean.setFaceUrl(userInfo.getFaceUrl());
|
||||
userBeanList.add(reactUserBean);
|
||||
}
|
||||
}
|
||||
resultBean.setUserBeanList(userBeanList);
|
||||
if (callback != null) {
|
||||
callback.onSuccess(resultBean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String desc) {
|
||||
if (callback != null) {
|
||||
callback.onError(code, desc);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.presenter;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuichat.TUIChatService;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.TUIEmojiPluginService;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.OnMessageReactionsChangedListener;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class MessageReactionBeanCache {
|
||||
|
||||
private static final MessageReactionBeanCache instance = new MessageReactionBeanCache();
|
||||
|
||||
private final WeakHashMap<TUIMessageBean, MessageReactionBean> cacheMap = new WeakHashMap<>();
|
||||
|
||||
private OnMessageReactionsChangedListener messageReactionsChangedListener;
|
||||
|
||||
private MessageReactionBeanCache() {
|
||||
messageReactionsChangedListener = new OnMessageReactionsChangedListener() {
|
||||
@Override
|
||||
public void onMessageReactionsChanged(MessageReactionBean messageReactionBean) {
|
||||
for (TUIMessageBean messageBean : instance.cacheMap.keySet()) {
|
||||
if (TextUtils.equals(messageBean.getId(), messageReactionBean.getMessageID())) {
|
||||
instance.cacheMap.put(messageBean, messageReactionBean);
|
||||
messageBean.setHasReaction(messageReactionBean.getReactionCount() != 0);
|
||||
TUIChatService.getInstance().refreshMessage(messageBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
TUIEmojiPluginService.addReactionsChangedListener(messageReactionsChangedListener);
|
||||
}
|
||||
|
||||
public static void putMessageReactionBean(TUIMessageBean messageBean, MessageReactionBean messageReactionBean) {
|
||||
if (messageBean == null || messageReactionBean == null) {
|
||||
return;
|
||||
}
|
||||
for (TUIMessageBean cached : instance.cacheMap.keySet()) {
|
||||
if (TextUtils.equals(messageBean.getId(), cached.getId())) {
|
||||
instance.cacheMap.remove(cached);
|
||||
break;
|
||||
}
|
||||
}
|
||||
instance.cacheMap.put(messageBean, messageReactionBean);
|
||||
}
|
||||
|
||||
public static MessageReactionBean getMessageReactionBean(TUIMessageBean messageBean) {
|
||||
return instance.cacheMap.get(messageBean);
|
||||
}
|
||||
|
||||
public static MessageReactionBean getMessageReactionBean(String messageID) {
|
||||
for (TUIMessageBean messageBean : instance.cacheMap.keySet()) {
|
||||
if (TextUtils.equals(messageBean.getId(), messageID)) {
|
||||
return instance.cacheMap.get(messageBean);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean contains(String messageID) {
|
||||
for (TUIMessageBean messageBean : instance.cacheMap.keySet()) {
|
||||
if (TextUtils.equals(messageBean.getId(), messageID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
instance.cacheMap.clear();
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.presenter;
|
||||
|
||||
import android.util.Log;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUIValueCallback;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.TUIEmojiPluginService;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.OnMessageReactionsChangedListener;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.interfaces.ReactPreviewView;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.model.TUIEmojiProvider;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class MessageReactionPreviewPresenter {
|
||||
private static final String TAG = MessageReactionPreviewPresenter.class.getSimpleName();
|
||||
private TUIEmojiProvider provider;
|
||||
private ReactPreviewView reactPreviewView;
|
||||
private OnMessageReactionsChangedListener reactionsChangedListener;
|
||||
|
||||
public MessageReactionPreviewPresenter() {
|
||||
provider = new TUIEmojiProvider();
|
||||
}
|
||||
|
||||
public void initListener() {
|
||||
reactionsChangedListener = new OnMessageReactionsChangedListener() {
|
||||
@Override
|
||||
public void onMessageReactionsChanged(MessageReactionBean messageReactionBean) {
|
||||
Log.e(TAG, "onMessageReactionsChanged");
|
||||
}
|
||||
};
|
||||
TUIEmojiPluginService.addReactionsChangedListener(reactionsChangedListener);
|
||||
}
|
||||
|
||||
public void setReactPreviewView(ReactPreviewView reactPreviewView) {
|
||||
this.reactPreviewView = reactPreviewView;
|
||||
}
|
||||
|
||||
public void loadData(TUIMessageBean messageBean) {
|
||||
reactPreviewView.setMessageBean(messageBean);
|
||||
MessageReactionBean messageReactionBean = MessageReactionBeanCache.getMessageReactionBean(messageBean);
|
||||
if (messageReactionBean != null) {
|
||||
reactPreviewView.setData(messageReactionBean);
|
||||
} else {
|
||||
if (!MessageReactionBeanCache.contains(messageBean.getId())) {
|
||||
MessageReactionBean reactionBean = new MessageReactionBean();
|
||||
reactionBean.setMessageID(messageBean.getId());
|
||||
reactionBean.setMessageReactionBeanMap(new HashMap<>());
|
||||
MessageReactionBeanCache.putMessageReactionBean(messageBean, reactionBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.presenter;
|
||||
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUIValueCallback;
|
||||
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.bean.MessageReactionUserBean;
|
||||
import com.tencent.qcloud.tuikit.tuiemojiplugin.model.TUIEmojiProvider;
|
||||
import java.util.List;
|
||||
|
||||
public class TUIEmojiPresenter {
|
||||
private static final String TAG = "TUIEmojiPresenter";
|
||||
private TUIEmojiProvider provider;
|
||||
|
||||
public TUIEmojiPresenter() {
|
||||
provider = new TUIEmojiProvider();
|
||||
}
|
||||
|
||||
|
||||
public void addMessageReaction(TUIMessageBean messageBean, String reactionID, TUICallback callback) {
|
||||
provider.addMessageReaction(messageBean, reactionID, callback);
|
||||
}
|
||||
|
||||
public void removeMessageReaction(TUIMessageBean messageBean, String reactionID, TUICallback callback) {
|
||||
provider.removeMessageReaction(messageBean, reactionID, callback);
|
||||
}
|
||||
|
||||
public void getMessageReactions(List<TUIMessageBean> messageBeans, int maxUserCountPerReaction, TUIValueCallback<List<MessageReactionBean>> callback) {
|
||||
provider.getMessageReactions(messageBeans, maxUserCountPerReaction, callback);
|
||||
}
|
||||
|
||||
public void getAllUserListOfMessageReaction(
|
||||
TUIMessageBean messageBean, String reactionID, int nextSeq, int count, TUIValueCallback<MessageReactionUserBean> callback) {
|
||||
provider.getAllUserListOfMessageReaction(messageBean, reactionID, nextSeq, count, callback);
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.tencent.qcloud.tuikit.tuiemojiplugin.util;
|
||||
|
||||
import com.tencent.imsdk.common.IMLog;
|
||||
|
||||
public class TUIEmojiLog extends IMLog {
|
||||
private static final String PRE = "TUIEmojiLog-";
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1000 B |
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<corners android:radius="12.5dp"/>
|
||||
<solid android:color="#F0F9F9F9"/>
|
||||
|
||||
</shape>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 777 B |
+38
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="7.68dp"
|
||||
android:paddingEnd="7.68dp"
|
||||
android:background="@drawable/chat_react_bg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="23.04dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/face_iv"
|
||||
android:layout_width="15.36dp"
|
||||
android:layout_height="15.36dp"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
<View
|
||||
android:background="#33444444"
|
||||
android:layout_marginStart="3.84dp"
|
||||
android:layout_marginEnd="3.84dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="4.32dp"
|
||||
android:layout_marginBottom="4.32dp"
|
||||
android:layout_width="0.96dp"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/users_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textSize="10.56sp"
|
||||
android:textColor="?attr/chat_react_text_color"/>
|
||||
|
||||
</LinearLayout>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/face_iv"
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
</FrameLayout>
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/chat_message_popup_stroke_border"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/reacts_emoji_list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/more_icon"
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="12dp"
|
||||
android:background="@drawable/chat_reply_more_icon"
|
||||
android:layout_marginEnd="4dp"
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reacts_num_text"
|
||||
android:textSize="12sp"
|
||||
android:textColor="#999999"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/emoji_img"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"/>
|
||||
|
||||
</FrameLayout>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:minHeight="1000dp"
|
||||
android:background="@drawable/chat_bottom_sheet_dialog_border">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="22dp"
|
||||
android:paddingBottom="22dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:fillViewport="true">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/emoji_grid_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/chat_bottom_sheet_dialog_border"
|
||||
android:minHeight="1000dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="27dp"
|
||||
android:paddingEnd="27dp"
|
||||
android:paddingTop="22dp"
|
||||
android:paddingBottom="22dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="6dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="25dp"
|
||||
android:background="@drawable/chat_bottom_sheet_hide"
|
||||
/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/react_category_list"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_gravity="start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/react_view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="380dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/category_name"
|
||||
android:textSize="12sp"
|
||||
android:textColor="#999999"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/react_img"
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/react_num"
|
||||
android:textSize="12sp"
|
||||
android:textColor="#999999"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<com.tencent.qcloud.tuikit.timcommon.component.RoundCornerImageView
|
||||
android:id="@+id/user_face"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentStart="true"
|
||||
app:corner_radius="20dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_toEndOf="@id/user_face"
|
||||
android:gravity="center_vertical|start"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#666666"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/emoji_icon"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/react_user_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</FrameLayout>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/face_iv"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"/>
|
||||
|
||||
</FrameLayout>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/face_iv"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"/>
|
||||
|
||||
</FrameLayout>
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recent_faces"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/divide_line"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:background="#E5E5E5"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/face_grid_ll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/face_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<com.tencent.qcloud.tuikit.timcommon.component.IndicatorView
|
||||
android:id="@+id/face_indicator"
|
||||
android:layout_marginTop="7.44dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="40dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:background="@drawable/chat_minimalist_menu_emoji_list_border">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="tuiemoji_add_reaction_failed_tip">فشل في إضافة رد فعل الرموز التعبيرية</string>
|
||||
<string name="tuiemoji_remove_reaction_failed_tip">فشل في إزالة رد فعل الرموز التعبيرية</string>
|
||||
<string name="chat_tap_to_remove">اضغط للإزالة</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="tuiemoji_add_reaction_failed_tip">添加表情回應失敗</string>
|
||||
<string name="tuiemoji_remove_reaction_failed_tip">刪除表情回應失敗</string>
|
||||
<string name="chat_tap_to_remove">點擊刪除</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="tuiemoji_add_reaction_failed_tip">添加表情回应失败</string>
|
||||
<string name="tuiemoji_remove_reaction_failed_tip">删除表情回应失败</string>
|
||||
<string name="chat_tap_to_remove">点击删除</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="tuiemoji_chat_pop_menu_recent_face_space">12dp</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="tuiemoji_add_reaction_failed_tip">Failed to add emoji reaction</string>
|
||||
<string name="tuiemoji_remove_reaction_failed_tip">Failed to remove emoji reaction</string>
|
||||
<string name="chat_tap_to_remove">Tap to remove</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="TUIEmojiTranslucentBgStyle" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="android:windowBackground">@color/window_background_color</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowEnterAnimation">@anim/translate_dialog_in</item>
|
||||
<item name="android:windowExitAnimation">@anim/translate_dialog_out</item>
|
||||
</style>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user