首次提交

This commit is contained in:
2025-08-08 11:05:17 +08:00
commit ed7461261c
3842 changed files with 227430 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
plugins {
id 'com.android.library'
}
//apply from: "../MobSdk.gradle"
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main {
res.srcDirs += "src/main/res-minimalistui"
}
}
}
afterEvaluate{
generateReleaseBuildConfig.enabled =false
generateDebugBuildConfig.enabled =false
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'com.google.code.gson:gson:2.8.7'
api 'org.greenrobot:eventbus:3.1.1'
api project(':tuicore')
}

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tencent.qcloud.tuikit.tuiconversation">
<application>
<provider
android:name=".TUIConversationService"
android:authorities="${applicationId}.TUIConversation.Init"
android:enabled="true"
android:exported="false"/>
<!-- **************** Classic UI Activity Start **************** -->
<activity
android:name=".classicui.page.TUIForwardSelectActivity"
android:screenOrientation="portrait" />
<activity
android:name=".classicui.page.TUIFoldedConversationActivity"
android:screenOrientation="portrait" />
<!-- **************** Classic UI Activity End **************** -->
<!-- **************** Minimalist UI Activity Start **************** -->
<activity
android:name=".minimalistui.page.TUIForwardSelectMinimalistActivity"
android:screenOrientation="portrait" />
<activity
android:name=".minimalistui.page.TUIFoldedConversationMinimalistActivity"
android:screenOrientation="portrait" />
<!-- **************** Minimalist UI Activity End **************** -->
</application>
</manifest>

View File

@@ -0,0 +1,81 @@
package com.tencent.qcloud.tuikit.tuiconversation;
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
import com.tencent.qcloud.tuicore.interfaces.ITUIService;
import java.util.Map;
public interface ITUIConversationService extends ITUIService, ITUINotification {
/**
* 1、获取会话是否置顶
* @param method TUIConstants.TUIConversation.METHOD_IS_TOP_CONVERSATION
* @param param {TUIConstants.TUIConversation.CHAT_ID : String}
* @return {TUIConstants.TUIConversation.IS_TOP : Boolean}
* 2、设置会话置顶
* @param method TUIConstants.TUIConversation.METHOD_SET_TOP_CONVERSATION
* @param param {TUIConstants.TUIConversation.CHAT_ID : String, TUIConstants.TUIConversation.IS_SET_TOP : Boolean}
* 3、获取未读总数
* @param method TUIConstants.TUIConversation.METHOD_GET_TOTAL_UNREAD_COUNT
* @return 未读总数
* 4、更新未读总数
* @param method TUIConstants.TUIConversation.METHOD_UPDATE_TOTAL_UNREAD_COUNT
* 5、删除会话。
* @param method TUIConstants.TUIConversation.METHOD_DELETE_CONVERSATION
* @param param {TUIConstants.TUIConversation.CONVERSATION_ID : String}
*
*
* 1、Get whether the conversation is sticky
* @param method TUIConstants.TUIConversation.METHOD_IS_TOP_CONVERSATION
* @param param {TUIConstants.TUIConversation.CHAT_ID : String}
* @return {TUIConstants.TUIConversation.IS_TOP : Boolean}
* 2、Set session sticky
* @param method TUIConstants.TUIConversation.METHOD_SET_TOP_CONVERSATION
* @param param {TUIConstants.TUIConversation.CHAT_ID : String, TUIConstants.TUIConversation.IS_SET_TOP : Boolean}
* 3、Get the total number of unreads
* @param method TUIConstants.TUIConversation.METHOD_GET_TOTAL_UNREAD_COUNT
* @return the total number of unreads
* 4、Update the total number of unreads
* @param method TUIConstants.TUIConversation.METHOD_UPDATE_TOTAL_UNREAD_COUNT
* 5、Delete conversation
* @param method TUIConstants.TUIConversation.METHOD_DELETE_CONVERSATION
* @param param {TUIConstants.TUIConversation.CONVERSATION_ID : String}
*/
@Override
Object onCall(String method, Map<String, Object> param);
/**
* 1、接收退群通知
* @param key TUIConstants.TUIGroup.EVENT_GROUP
* @param subKey TUIConstants.TUIGroup.EVENT_SUB_KEY_EXIT_GROUP,
* TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_DISMISS,
* TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_RECYCLE
* @param param {TUIConstants.TUIGroup.GROUP_ID : String}
* 2、接收群成员退出群通知
* @param key TUIConstants.TUIGroup.EVENT_GROUP
* @param subKey TUIConstants.TUIGroup.EVENT_SUB_KEY_MEMBER_KICKED_GROUP
* @param param {TUIConstants.TUIGroup.GROUP_ID : String, TUIConstants.TUIGroup.GROUP_MEMBER_ID_LIST : ArrayList<String>}
* 3、接收好友备注修改通知。
* @param key TUIConstants.TUIContact.EVENT_FRIEND_INFO_CHANGED
* @param subKey TUIConstants.TUIContact.EVENT_SUB_KEY_FRIEND_REMARK_CHANGED
* @param param {TUIConstants.TUIContact.FRIEND_ID : String, TUIConstants.TUIContact.FRIEND_REMARK : String}
*
*
* 1、Receive notifications of exit group
* @param key TUIConstants.TUIGroup.EVENT_GROUP
* @param subKey TUIConstants.TUIGroup.EVENT_SUB_KEY_EXIT_GROUP,
* TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_DISMISS,
* TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_RECYCLE
* @param param {TUIConstants.TUIGroup.GROUP_ID : String}
* 2、Receive group members leaving the group notification
* @param key TUIConstants.TUIGroup.EVENT_GROUP
* @param subKey TUIConstants.TUIGroup.EVENT_SUB_KEY_MEMBER_KICKED_GROUP
* @param param {TUIConstants.TUIGroup.GROUP_ID : String, TUIConstants.TUIGroup.GROUP_MEMBER_ID_LIST : ArrayList<String>}
* 3、Receive notification of friend's note modification
* @param key TUIConstants.TUIContact.EVENT_FRIEND_INFO_CHANGED
* @param subKey TUIConstants.TUIContact.EVENT_SUB_KEY_FRIEND_REMARK_CHANGED
* @param param {TUIConstants.TUIContact.FRIEND_ID : String, TUIConstants.TUIContact.FRIEND_REMARK : String}
*/
@Override
void onNotifyEvent(String key, String subKey, Map<String, Object> param);
}

View File

@@ -0,0 +1,43 @@
package com.tencent.qcloud.tuikit.tuiconversation;
public class TUIConversationConstants {
public static final String FORWARD_SELECT_CONVERSATION_KEY = "forward_select_conversation_key";
public static final int FORWARD_SELECT_ACTIVTY_CODE = 101;
public static final int FORWARD_SELECT_MEMBERS_CODE = 102;
public static final int FORWARD_CREATE_GROUP_CODE = 103;
public static final String FORWARD_CREATE_NEW_CHAT = "forward_create_new_chat";
public static String covert2HTMLString(String original) {
return "\"<font color=\"#5B6B92\">" + original + "</font>\"";
}
/**
* 1: 仅仅是一个带链接的文本消息
* 2: iOS支持的视频通话版本后续已经不兼容
* 3: 未发布版本
* 4: Android/iOS/Web互通的视频通话版本
*
* 1: Just a text message with a link
* 2: The video calling version supported by iOS is no longer compatible
* 3: unreleased version
* 4: Android/iOS/Web interoperable version for video call
*/
public static final int JSON_VERSION_UNKNOWN = 0;
public static final int JSON_VERSION_1 = 1;
public static final int JSON_VERSION_4 = 4;
public static int version = JSON_VERSION_4;
public static class GroupType {
public static final String TYPE = "type";
public static final String GROUP = "isGroup";
public static final int PRIVATE = 0;
public static final int PUBLIC = 1;
public static final int CHAT_ROOM = 2;
public static final int COMMUNITY = 3;
}
public static final String CONVERSATION_SETTINGS_SP_NAME = "conversation_settings_sp";
public static final String HIDE_FOLD_ITEM_SP_KEY_PREFIX = "hide_fold_item_";
public static final String FOLD_ITEM_IS_UNREAD_SP_KEY_PREFIX = "fold_item_is_unread_";
}

View File

@@ -0,0 +1,370 @@
package com.tencent.qcloud.tuikit.tuiconversation;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import com.tencent.imsdk.v2.V2TIMConversation;
import com.tencent.imsdk.v2.V2TIMConversationListener;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMSDKListener;
import com.tencent.imsdk.v2.V2TIMUserStatus;
import com.tencent.qcloud.tuicore.ServiceInitializer;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.TUILogin;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.ConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.ConversationEventListener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class TUIConversationService extends ServiceInitializer implements ITUIConversationService {
public static final String TAG = TUIConversationService.class.getSimpleName();
private static TUIConversationService instance;
public static TUIConversationService getInstance() {
return instance;
}
private boolean syncFinished = false;
private WeakReference<ConversationEventListener> conversationEventListener;
private final List<WeakReference<ConversationEventListener>> conversationEventListenerList = new ArrayList<>();
@Override
public void init(Context context) {
instance = this;
initService();
initEvent();
initIMListener();
}
private void initService() {
TUICore.registerService(TUIConstants.TUIConversation.SERVICE_NAME, this);
}
private void initEvent() {
TUICore.registerEvent(TUIConstants.TUIGroup.EVENT_GROUP, TUIConstants.TUIGroup.EVENT_SUB_KEY_EXIT_GROUP, this);
TUICore.registerEvent(TUIConstants.TUIGroup.EVENT_GROUP, TUIConstants.TUIGroup.EVENT_SUB_KEY_MEMBER_KICKED_GROUP, this);
TUICore.registerEvent(TUIConstants.TUIGroup.EVENT_GROUP, TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_DISMISS, this);
TUICore.registerEvent(TUIConstants.TUIGroup.EVENT_GROUP, TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_RECYCLE, this);
TUICore.registerEvent(TUIConstants.TUIContact.EVENT_FRIEND_INFO_CHANGED, TUIConstants.TUIContact.EVENT_SUB_KEY_FRIEND_REMARK_CHANGED, this);
TUICore.registerEvent(TUIConstants.TUIGroup.EVENT_GROUP, TUIConstants.TUIGroup.EVENT_SUB_KEY_CLEAR_MESSAGE, this);
TUICore.registerEvent(TUIConstants.TUIContact.EVENT_USER, TUIConstants.TUIContact.EVENT_SUB_KEY_CLEAR_MESSAGE, this);
TUICore.registerEvent(TUIConstants.TUIChat.EVENT_KEY_RECEIVE_MESSAGE, TUIConstants.TUIChat.EVENT_SUB_KEY_CONVERSATION_ID, this);
TUICore.registerEvent(TUIConstants.TUIConversation.EVENT_KEY_MESSAGE_SEND_FOR_CONVERSATION, TUIConstants.TUIConversation.EVENT_SUB_KEY_MESSAGE_SEND_FOR_CONVERSATION, this);
}
@Override
public Object onCall(String method, Map<String, Object> param) {
Bundle result = new Bundle();
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
if (conversationEventListener == null) {
TUIConversationLog.e(TAG, "execute " + method + " failed , conversationEvent listener is null");
return result;
}
if (TextUtils.equals(TUIConstants.TUIConversation.METHOD_IS_TOP_CONVERSATION, method)) {
String chatId = (String) param.get(TUIConstants.TUIConversation.CHAT_ID);
if (!TextUtils.isEmpty(chatId)) {
boolean isTop = conversationEventListener.isTopConversation(chatId);
result.putBoolean(TUIConstants.TUIConversation.IS_TOP, isTop);
}
} else if (TextUtils.equals(TUIConstants.TUIConversation.METHOD_SET_TOP_CONVERSATION, method)) {
String chatId = (String) param.get(TUIConstants.TUIConversation.CHAT_ID);
boolean isTop = (boolean) param.get(TUIConstants.TUIConversation.IS_SET_TOP);
if (!TextUtils.isEmpty(chatId)) {
conversationEventListener.setConversationTop(chatId, isTop, new IUIKitCallback<Void>() {
@Override
public void onSuccess(Void data) {
}
@Override
public void onError(String module, int errCode, String errMsg) {
}
});
}
} else if (TextUtils.equals(TUIConstants.TUIConversation.METHOD_GET_TOTAL_UNREAD_COUNT, method)) {
return conversationEventListener.getUnreadTotal();
} else if (TextUtils.equals(TUIConstants.TUIConversation.METHOD_UPDATE_TOTAL_UNREAD_COUNT, method)) {
HashMap<String, Object> unreadMap = new HashMap<>();
long totalUnread = conversationEventListener.getUnreadTotal();
unreadMap.put(TUIConstants.TUIConversation.TOTAL_UNREAD_COUNT, totalUnread);
TUICore.notifyEvent(TUIConstants.TUIConversation.EVENT_UNREAD, TUIConstants.TUIConversation.EVENT_SUB_KEY_UNREAD_CHANGED, unreadMap);
} else if (TextUtils.equals(TUIConstants.TUIConversation.METHOD_DELETE_CONVERSATION, method)) {
String conversationId = (String) param.get(TUIConstants.TUIConversation.CONVERSATION_ID);
conversationEventListener.clearFoldMarkAndDeleteConversation(conversationId);
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.clearFoldMarkAndDeleteConversation(conversationId);
}
}
return result;
}
@Override
public void onNotifyEvent(String key, String subKey, Map<String, Object> param) {
if (TextUtils.equals(key, TUIConstants.TUIGroup.EVENT_GROUP)) {
if (TextUtils.equals(subKey, TUIConstants.TUIGroup.EVENT_SUB_KEY_EXIT_GROUP)
|| TextUtils.equals(subKey, TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_DISMISS)
|| TextUtils.equals(subKey, TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_RECYCLE)) {
ConversationEventListener eventListener = getConversationEventListener();
String groupId = null;
if (param != null) {
groupId = (String) getOrDefault(param.get(TUIConstants.TUIGroup.GROUP_ID), "");
}
if (eventListener != null) {
eventListener.deleteConversation(groupId, true);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.deleteConversation(groupId, true);
}
} else if (TextUtils.equals(subKey, TUIConstants.TUIGroup.EVENT_SUB_KEY_MEMBER_KICKED_GROUP)) {
if (param == null) {
return;
}
String groupId = (String) getOrDefault(param.get(TUIConstants.TUIGroup.GROUP_ID), "");
ArrayList<String> memberList = (ArrayList<String>) param.get(TUIConstants.TUIGroup.GROUP_MEMBER_ID_LIST);
if (TextUtils.isEmpty(groupId) || memberList == null || memberList.isEmpty()) {
return;
}
for (String id : memberList) {
if (TextUtils.equals(id, TUILogin.getLoginUser())) {
ConversationEventListener eventListener = getConversationEventListener();
if (eventListener != null) {
eventListener.deleteConversation(groupId, true);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.deleteConversation(groupId, true);
}
break;
}
}
} else if (TextUtils.equals(subKey, TUIConstants.TUIGroup.EVENT_SUB_KEY_CLEAR_MESSAGE)) {
String groupId = (String) getOrDefault(param.get(TUIConstants.TUIGroup.GROUP_ID), "");
ConversationEventListener eventListener = getConversationEventListener();
if (eventListener != null) {
eventListener.clearConversationMessage(groupId, true);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.clearConversationMessage(groupId, true);
}
}
} else if (key.equals(TUIConstants.TUIContact.EVENT_USER)) {
if (subKey.equals(TUIConstants.TUIContact.EVENT_SUB_KEY_CLEAR_MESSAGE)) {
if (param == null || param.isEmpty()) {
return;
}
String userID = (String) getOrDefault(param.get(TUIConstants.TUIContact.FRIEND_ID), "");
ConversationEventListener eventListener = getConversationEventListener();
if (eventListener != null) {
eventListener.clearConversationMessage(userID, false);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.clearConversationMessage(userID, false);
}
}
} else if (key.equals(TUIConstants.TUIContact.EVENT_FRIEND_INFO_CHANGED)) {
if (subKey.equals(TUIConstants.TUIContact.EVENT_SUB_KEY_FRIEND_REMARK_CHANGED)) {
if (param == null || param.isEmpty()) {
return;
}
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
if (conversationEventListener == null) {
return;
}
String id = (String) param.get(TUIConstants.TUIContact.FRIEND_ID);
String remark = (String) param.get(TUIConstants.TUIContact.FRIEND_REMARK);
conversationEventListener.onFriendRemarkChanged(id ,remark);
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.onFriendRemarkChanged(id, remark);
}
}
} else if (key.equals(TUIConstants.TUIChat.EVENT_KEY_RECEIVE_MESSAGE)) {
if (subKey.equals(TUIConstants.TUIChat.EVENT_SUB_KEY_CONVERSATION_ID)) {
if (param == null || param.isEmpty()) {
return;
}
String conversationID = (String) param.get(TUIConstants.TUIChat.CONVERSATION_ID);
boolean isTypingMessage = false;
if (param.containsKey(TUIConstants.TUIChat.IS_TYPING_MESSAGE)) {
isTypingMessage = (Boolean) param.get(TUIConstants.TUIChat.IS_TYPING_MESSAGE);
}
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
if (conversationEventListener != null) {
conversationEventListener.onReceiveMessage(conversationID, isTypingMessage);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.onReceiveMessage(conversationID, isTypingMessage);
}
}
} else if (TextUtils.equals(key, TUIConstants.TUIConversation.EVENT_KEY_MESSAGE_SEND_FOR_CONVERSATION)) {
if (TextUtils.equals(subKey, TUIConstants.TUIConversation.EVENT_SUB_KEY_MESSAGE_SEND_FOR_CONVERSATION)) {
if (param == null || param.isEmpty()) {
return;
}
String conversationID = (String) param.get(TUIConstants.TUIConversation.CONVERSATION_ID);
ConversationEventListener eventListener = getConversationEventListener();
if (eventListener != null) {
eventListener.onMessageSendForHideConversation(conversationID);
}
}
}
}
private Object getOrDefault(Object value, Object defaultValue) {
if (value != null) {
return value;
}
return defaultValue;
}
private void initIMListener() {
V2TIMManager.getConversationManager().addConversationListener(new V2TIMConversationListener() {
@Override
public void onSyncServerStart() {
syncFinished = false;
}
@Override
public void onSyncServerFinish() {
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
if (conversationEventListener != null) {
conversationEventListener.onSyncServerFinish();
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.onSyncServerFinish();
}
syncFinished = true;
}
@Override
public void onSyncServerFailed() {
syncFinished = false;
}
@Override
public void onNewConversation(List<V2TIMConversation> conversationList) {
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
List<ConversationInfo> conversationInfoList = ConversationUtils.convertV2TIMConversationList(conversationList);
if (conversationEventListener != null) {
conversationEventListener.onNewConversation(conversationInfoList);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.onNewConversation(conversationInfoList);
}
}
@Override
public void onConversationChanged(List<V2TIMConversation> conversationList) {
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
List<ConversationInfo> conversationInfoList = ConversationUtils.convertV2TIMConversationList(conversationList);
if (conversationEventListener != null) {
conversationEventListener.onConversationChanged(conversationInfoList);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.onConversationChanged(conversationInfoList);
}
}
@Override
public void onTotalUnreadMessageCountChanged(long totalUnreadCount) {
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
if (conversationEventListener != null) {
conversationEventListener.updateTotalUnreadMessageCount(totalUnreadCount);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.updateTotalUnreadMessageCount(totalUnreadCount);
}
HashMap<String, Object> param = new HashMap<>();
param.put(TUIConstants.TUIConversation.TOTAL_UNREAD_COUNT, totalUnreadCount);
TUICore.notifyEvent(TUIConstants.TUIConversation.EVENT_UNREAD, TUIConstants.TUIConversation.EVENT_SUB_KEY_UNREAD_CHANGED, param);
}
});
V2TIMSDKListener v2TIMSDKListener = new V2TIMSDKListener() {
@Override
public void onUserStatusChanged(List<V2TIMUserStatus> userStatusList) {
ConversationEventListener conversationEventListener = getInstance().getConversationEventListener();
if (conversationEventListener != null) {
conversationEventListener.onUserStatusChanged(userStatusList);
}
List<ConversationEventListener> conversationEventObserverList = getConversationEventListenerList();
for(ConversationEventListener conversationEventObserver : conversationEventObserverList) {
conversationEventObserver.onUserStatusChanged(userStatusList);
}
}
};
V2TIMManager.getInstance().addIMSDKListener(v2TIMSDKListener);
}
public void addConversationEventListener(ConversationEventListener conversationEventListener) {
if (conversationEventListener == null) {
return;
}
for (WeakReference<ConversationEventListener> listenerWeakReference : conversationEventListenerList) {
if (listenerWeakReference.get() == conversationEventListener) {
return;
}
}
conversationEventListenerList.add(new WeakReference<>(conversationEventListener));
}
public List<ConversationEventListener> getConversationEventListenerList() {
List<ConversationEventListener> listeners = new ArrayList<>();
Iterator<WeakReference<ConversationEventListener>> iterator = conversationEventListenerList.listIterator();
while(iterator.hasNext()) {
WeakReference<ConversationEventListener> listenerWeakReference = iterator.next();
ConversationEventListener listener = listenerWeakReference.get();
if (listener == null) {
iterator.remove();
} else {
listeners.add(listener);
}
}
return listeners;
}
public void setConversationEventListener(ConversationEventListener conversationManagerKit) {
this.conversationEventListener = new WeakReference<>(conversationManagerKit);
if (syncFinished) {
conversationManagerKit.onSyncServerFinish();
}
}
public ConversationEventListener getConversationEventListener() {
if (conversationEventListener != null) {
return conversationEventListener.get();
}
return null;
}
public void addMessageListener() {
}
}

View File

@@ -0,0 +1,360 @@
package com.tencent.qcloud.tuikit.tuiconversation.bean;
import androidx.annotation.NonNull;
import com.tencent.imsdk.v2.V2TIMConversation;
import com.tencent.imsdk.v2.V2TIMGroupAtInfo;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.imsdk.v2.V2TIMUserStatus;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class ConversationInfo implements Serializable, Comparable<ConversationInfo> {
public static final int TYPE_COMMON = 1;
public static final int TYPE_CUSTOM = 2;
public static final int TYPE_FORWAR_SELECT = 3;
public static final int TYPE_RECENT_LABEL = 4;
/**
* 会话类型自定义会话or普通会话
*
* conversation type
*/
private int type;
/**
* 消息未读数
*
* unread message number
*/
private int unRead;
/**
* 会话ID
*
* conversation ID
*/
private String conversationId;
/**
* 会话标识C2C为对方用户ID群聊为群组ID
*
* ID, C2C is UserID, Group is group ID
*/
private String id;
private int statusType = V2TIMUserStatus.V2TIM_USER_STATUS_UNKNOWN;
private V2TIMConversation conversation;
private List<Object> iconUrlList = new ArrayList<>();
public List<Object> getIconUrlList() {
return iconUrlList;
}
public void setIconUrlList(List<Object> iconUrlList) {
this.iconUrlList = iconUrlList;
}
public V2TIMConversation getConversation() {
return conversation;
}
public void setConversation(V2TIMConversation conversation) {
this.conversation = conversation;
}
public String getShowName() {
if (conversation != null) {
return conversation.getShowName();
}
return null;
}
private String title;
private String iconPath;
private boolean isGroup;
private boolean top;
/**
* 是否为折叠会话 Is folded conversation or not
*/
private boolean isMarkFold;
/**
* 是否标记会话未读 Is marked conversation unread or not
*/
private boolean isMarkUnread;
/**
* 是否标记会话隐藏 Is marked conversation hidden or not
*/
private boolean isMarkHidden;
/**
* 本地记录未读状态 Is marked conversation local-unread or not
*/
private boolean isMarkLocalUnread;
/**
* 最后一条消息时间
*/
private long lastMessageTime;
private V2TIMMessage lastMessage;
/**
* 会话界面显示的@提示消息
*
* "@" message in group
*/
private String atInfoText;
/**
* 会话界面显示消息免打扰图标
*
* the conversation item displays the icon of Do Not Disturb
*/
private boolean showDisturbIcon;
private DraftInfo draft;
private String groupType;
/**
* 会话排序键值
*
* conversation sort key
*/
private long orderKey;
private String room_id;
public ConversationInfo() {
}
public String getRoom_id() {
return room_id;
}
public void setRoom_id(String room_id) {
this.room_id = room_id;
}
public String getConversationId() {
return conversationId;
}
public void setConversationId(String conversationId) {
this.conversationId = conversationId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getUnRead() {
return unRead;
}
public void setUnRead(int unRead) {
this.unRead = unRead;
}
public boolean isGroup() {
return isGroup;
}
public void setGroup(boolean group) {
isGroup = group;
}
public boolean isTop() {
return top;
}
public void setTop(boolean top) {
this.top = top;
}
public boolean isMarkFold() {
return isMarkFold;
}
public void setMarkFold(boolean markFold) {
isMarkFold = markFold;
}
public boolean isMarkUnread() {
return isMarkUnread;
}
public void setMarkUnread(boolean markUnread) {
isMarkUnread = markUnread;
}
public boolean isMarkHidden() {
return isMarkHidden;
}
public void setMarkHidden(boolean markHidden) {
isMarkHidden = markHidden;
}
public boolean isMarkLocalUnread() {
return isMarkLocalUnread;
}
public void setMarkLocalUnread(boolean markLocalUnread) {
isMarkLocalUnread = markLocalUnread;
}
/**
* 获得最后一条消息的时间,单位是秒
*
* Get the time of the last message, in seconds
*/
public long getLastMessageTime() {
return lastMessageTime;
}
/**
* 设置最后一条消息的时间,单位是秒
*
* Set the time of the last message, in seconds
* @param lastMessageTime
*/
public void setLastMessageTime(long lastMessageTime) {
this.lastMessageTime = lastMessageTime;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public V2TIMMessage getLastMessage() {
return lastMessage;
}
public void setLastMessage(V2TIMMessage lastMessage) {
this.lastMessage = lastMessage;
}
public void setAtInfoText(String atInfoText) {
this.atInfoText = atInfoText;
}
public String getAtInfoText() {
return atInfoText;
}
public boolean isShowDisturbIcon() {
return showDisturbIcon;
}
public void setShowDisturbIcon(boolean showDisturbIcon) {
this.showDisturbIcon = showDisturbIcon;
}
public void setDraft(DraftInfo draft) {
this.draft = draft;
}
public DraftInfo getDraft() {
return this.draft;
}
public String getGroupType() {
return groupType;
}
public void setGroupType(String groupType) {
this.groupType = groupType;
}
public String getIconPath() {
return iconPath;
}
public void setIconPath(String iconPath) {
this.iconPath = iconPath;
}
public void setOrderKey(long orderKey) {
this.orderKey = orderKey;
}
public long getOrderKey() {
return orderKey;
}
public List<V2TIMGroupAtInfo> getGroupAtInfoList() {
if (conversation != null) {
return conversation.getGroupAtInfoList();
}
return null;
}
public int getStatusType() {
return statusType;
}
public void setStatusType(int statusType) {
this.statusType = statusType;
}
@Override
public int compareTo(@NonNull ConversationInfo other) {
if (this.isTop() && !other.isTop()) {
return -1;
} else if (!this.isTop() && other.isTop()) {
return 1;
} else {
long thisOrderKey = this.orderKey;
long otherOrderKey = other.orderKey;
if (thisOrderKey > otherOrderKey) {
return -1;
} else if (thisOrderKey == otherOrderKey) {
return 0;
} else {
return 1;
}
}
}
@Override
public String toString() {
return "ConversationInfo{" +
"type=" + type +
", unRead=" + unRead +
", conversationId='" + conversationId + '\'' +
", id='" + id + '\'' +
", iconUrl='" + iconUrlList.size() + '\'' +
", title='" + title + '\'' +
", iconPath=" + iconPath +
", isGroup=" + isGroup +
", top=" + top +
", lastMessageTime=" + lastMessageTime +
", lastMessage=" + lastMessage +
", draftText=" + draft +
", groupType=" + groupType +
", statusType=" + statusType +
'}';
}
}

View File

@@ -0,0 +1,32 @@
package com.tencent.qcloud.tuikit.tuiconversation.bean;
import java.io.Serializable;
public class DraftInfo implements Serializable {
private String draftText;
private long draftTime;
public String getDraftText() {
return draftText;
}
public void setDraftText(String draftText) {
this.draftText = draftText;
}
public long getDraftTime() {
return draftTime;
}
public void setDraftTime(long draftTime) {
this.draftTime = draftTime;
}
@Override
public String toString() {
return "DraftInfo{" +
"draftText='" + draftText + '\'' +
", draftTime=" + draftTime +
'}';
}
}

View File

@@ -0,0 +1,38 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces;
import android.view.View;
import com.tencent.qcloud.tuicore.component.interfaces.ILayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
public interface IConversationLayout extends ILayout {
View getConversationList();
void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack);
void deleteConversation(ConversationInfo conversation);
void clearConversationMessage(ConversationInfo conversation);
/**
* 隐藏普通会话
* Hide normal conversation
*/
void markConversationHidden(ConversationInfo conversation);
/**
* 标记会话已读/未读
* Mark conversation read or unread
*/
void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread);
/**
* 隐藏整个折叠的会话 item
* Hide folded conversation item
*/
void hideFoldedItem(boolean needHide);
/**
* 清除折叠 item 本地未读状态
* Clear unread status of fold item
*/
void clearUnreadStatusOfFoldItem();
}

View File

@@ -0,0 +1,62 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces;
import android.view.View;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.ConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
public interface IConversationListLayout {
void setBackground(int resId);
void setOnConversationAdapterListener(OnConversationAdapterListener listener);
/**
* 不显示小红点未读消息条数开关
*
* Do not display the switch for the number of unread messages with the small red dot
*
* @param flag 默认false表示显示
*/
void disableItemUnreadDot(boolean flag);
/**
* 设置会话Item头像圆角
*
* Set session item avatar rounded corners
*
* @param radius
*/
void setItemAvatarRadius(int radius);
/**
* 设置会话Item顶部字体大小
*
* Set the font size at the top of the session item
*
* @param size
*/
void setItemTopTextSize(int size);
/**
* 设置会话Item底部字体大小
*
* Set the font size at the bottom of the session item
*
* @param size
*/
void setItemBottomTextSize(int size);
/**
* 设置会话Item日期字体大小
*
* Set the session item date font size
*
* @param size
*/
void setItemDateTextSize(int size);
View getListLayout();
ConversationListAdapter getAdapter();
void setAdapter(IConversationListAdapter adapter);
}

View File

@@ -0,0 +1,62 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import java.util.List;
public interface IConversationProvider {
/**
* 获取具体的会话数据集合ConversationContainer依据该数据集合展示会话列表
*
* Get a specific session data set, and ConversationContainer displays the session list based on the data set
*
* @return
*/
List<ConversationInfo> getDataSource();
/**
* 批量添加会话条目
*
* Bulk add session entries
*
* @param conversations 会话数据集合
* @return
*/
boolean addConversations(List<ConversationInfo> conversations);
/**
* 删除会话条目
*
* Delete session entries
*
* @param conversations 会话数据集合
* @return
*/
boolean deleteConversations(List<ConversationInfo> conversations);
/**
* 更新会话条目
*
* Update session entries
*
* @param conversations 会话数据集合
* @return
*/
boolean updateConversations(List<ConversationInfo> conversations);
/**
* 绑定会话适配器时触发的调用,在调用{@link com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter#setDataProvider}时自动调用
*
* Called when a session adapter is bound, automatically called when {@link com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter#setDataProvider} is called
*
* @param adapter 会话UI显示适配器
* @return
*/
void attachAdapter(IConversationListAdapter adapter);
}

View File

@@ -0,0 +1,14 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces;
import android.view.View;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.util.List;
public interface OnConversationAdapterListener {
void onItemClick(View view, int viewType, ConversationInfo conversationInfo);
void OnItemLongClick(View view, ConversationInfo conversationInfo);
void onConversationChanged(List<ConversationInfo> dataSource);
void onUserIconClick( ConversationInfo conversationInfo);
}

View File

@@ -0,0 +1,245 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.page;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupWindow;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuicore.component.fragments.BaseFragment;
import com.tencent.qcloud.tuicore.component.action.PopActionClickListener;
import com.tencent.qcloud.tuicore.component.action.PopDialogAdapter;
import com.tencent.qcloud.tuicore.component.action.PopMenuAction;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.setting.ConversationLayoutSetting;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.util.TUIConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.ConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.ConversationUtils;
import java.util.ArrayList;
import java.util.List;
public class TUIConversationFragment extends BaseFragment {
private View mBaseView;
private ConversationLayout mConversationLayout;
private ListView mConversationPopList;
private PopDialogAdapter mConversationPopAdapter;
private PopupWindow mConversationPopWindow;
private String popWindowConversationId;
private List<PopMenuAction> mConversationPopActions = new ArrayList<>();
private ConversationPresenter presenter;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
mBaseView = inflater.inflate(R.layout.conversation_fragment, container, false);
initView();
return mBaseView;
}
private void initView() {
// 从布局文件中获取会话列表面板
mConversationLayout = mBaseView.findViewById(R.id.conversation_layout);
presenter = new ConversationPresenter();
presenter.setConversationListener();
presenter.setShowType(ConversationPresenter.SHOW_TYPE_CONVERSATION_LIST_WITH_FOLD);
mConversationLayout.setPresenter(presenter);
// 会话列表面板的默认UI和交互初始化
mConversationLayout.initDefault();
// 通过API设置ConversataonLayout各种属性的样例开发者可以打开注释体验效果
ConversationLayoutSetting.customizeConversation(mConversationLayout);
mConversationLayout.getConversationList().setOnConversationAdapterListener(new OnConversationAdapterListener() {
@Override
public void onItemClick(View view, int viewType, ConversationInfo conversationInfo) {
//此处为demo的实现逻辑更根据会话类型跳转到相关界面开发者可根据自己的应用场景灵活实现
if (conversationInfo.isMarkFold()) {
mConversationLayout.clearUnreadStatusOfFoldItem();
startFoldedConversationActivity();
} else {
TUIConversationUtils.startChatActivity(conversationInfo);
}
}
@Override
public void OnItemLongClick(View view, ConversationInfo conversationInfo) {
showItemPopMenu(view, conversationInfo);
}
@Override
public void onConversationChanged(List<ConversationInfo> dataSource) {
if (dataSource == null)return;
ConversationInfo conversationInfo = dataSource.get(0);
if (conversationInfo == null)return;
if (!TextUtils.isEmpty(popWindowConversationId) && popWindowConversationId.equals(conversationInfo.getConversationId())) {
if (mConversationPopWindow != null) {
mConversationPopWindow.dismiss();
}
}
}
@Override
public void onUserIconClick(ConversationInfo conversationInfo) {
}
});
restoreConversationItemBackground();
}
public void restoreConversationItemBackground() {
if (mConversationLayout.getConversationList().getAdapter() != null &&
mConversationLayout.getConversationList().getAdapter().isClick()) {
mConversationLayout.getConversationList().getAdapter().setClick(false);
mConversationLayout.getConversationList().getAdapter().notifyItemChanged(mConversationLayout.getConversationList().getAdapter().getCurrentPosition());
}
}
private void initPopMenuAction() {
// 设置长按conversation显示PopAction
List<PopMenuAction> conversationPopActions = new ArrayList<PopMenuAction>();
PopMenuAction action = new PopMenuAction();
action.setActionName(getResources().getString(R.string.not_display));
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
ConversationInfo conversationInfo = (ConversationInfo) data;
if (conversationInfo.isMarkFold()) {
mConversationLayout.hideFoldedItem(true);
} else {
mConversationLayout.markConversationHidden(conversationInfo);
}
}
});
conversationPopActions.add(action);
mConversationPopActions.clear();
mConversationPopActions.addAll(conversationPopActions);
}
private void addMarkUnreadPopMenuAction(boolean markUnread) {
PopMenuAction action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mConversationLayout.markConversationUnread((ConversationInfo) data, markUnread);
}
});
if (markUnread) {
action.setActionName(getResources().getString(R.string.mark_unread));
} else {
action.setActionName(getResources().getString(R.string.mark_read));
}
mConversationPopActions.add(0, action);
}
private void addDeletePopMenuAction() {
PopMenuAction action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mConversationLayout.deleteConversation((ConversationInfo) data);
}
});
action.setActionName(getResources().getString(R.string.chat_delete));
mConversationPopActions.add(action);
}
/**
* 长按会话item弹框
* @param view 长按 view
* @param conversationInfo 会话数据对象
*/
private void showItemPopMenu(View view, final ConversationInfo conversationInfo) {
initPopMenuAction();
if (!conversationInfo.isMarkFold()) {
if (conversationInfo.getUnRead() > 0) {
addMarkUnreadPopMenuAction(false);
} else {
if (conversationInfo.isMarkUnread()) {
addMarkUnreadPopMenuAction(false);
} else {
addMarkUnreadPopMenuAction(true);
}
}
addDeletePopMenuAction();
}
View itemPop = LayoutInflater.from(getActivity()).inflate(R.layout.conversation_pop_menu_layout, null);
mConversationPopList = itemPop.findViewById(R.id.pop_menu_list);
mConversationPopList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PopMenuAction action = mConversationPopActions.get(position);
if (action.getActionClickListener() != null) {
action.getActionClickListener().onActionClick(position, conversationInfo);
}
mConversationPopWindow.dismiss();
restoreConversationItemBackground();
}
});
for (int i = 0; i < mConversationPopActions.size(); i++) {
PopMenuAction action = mConversationPopActions.get(i);
if (conversationInfo.isTop()) {
if (action.getActionName().equals(getResources().getString(R.string.chat_top))) {
action.setActionName(getResources().getString(R.string.quit_chat_top));
}
} else {
if (action.getActionName().equals(getResources().getString(R.string.quit_chat_top))) {
action.setActionName(getResources().getString(R.string.chat_top));
}
}
}
mConversationPopAdapter = new PopDialogAdapter();
mConversationPopList.setAdapter(mConversationPopAdapter);
mConversationPopAdapter.setDataSource(mConversationPopActions);
mConversationPopWindow = new PopupWindow(itemPop, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
mConversationPopWindow.setBackgroundDrawable(new ColorDrawable());
mConversationPopWindow.setOutsideTouchable(true);
int width = ConversationUtils.getListUnspecifiedWidth(mConversationPopAdapter, mConversationPopList);
mConversationPopWindow.setWidth(width);
popWindowConversationId = conversationInfo.getConversationId();
mConversationPopWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
restoreConversationItemBackground();
popWindowConversationId = "";
}
});
int x = view.getWidth() / 2;
int y = - view.getHeight() / 3;
int popHeight = ScreenUtil.dip2px(45) * 3;
if (y + popHeight + view.getY() + view.getHeight() > mConversationLayout.getBottom()) {
y = y - popHeight;
}
mConversationPopWindow.showAsDropDown(view, x, y, Gravity.TOP | Gravity.START);
}
private void startFoldedConversationActivity() {
Intent intent = new Intent(getActivity(), TUIFoldedConversationActivity.class);
startActivity(intent);
}
}

View File

@@ -0,0 +1,22 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.page;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.component.activities.BaseLightActivity;
import com.tencent.qcloud.tuikit.tuiconversation.R;
public class TUIFoldedConversationActivity extends BaseLightActivity {
private TUIFoldedConversationFragment mTUIFoldedConversationFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.folded_activity);
init();
}
private void init() {
mTUIFoldedConversationFragment = new TUIFoldedConversationFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.empty_view, mTUIFoldedConversationFragment).commitAllowingStateLoss();
}
}

View File

@@ -0,0 +1,222 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.page;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupWindow;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.action.PopActionClickListener;
import com.tencent.qcloud.tuicore.component.action.PopDialogAdapter;
import com.tencent.qcloud.tuicore.component.action.PopMenuAction;
import com.tencent.qcloud.tuicore.component.fragments.BaseFragment;
import com.tencent.qcloud.tuicore.component.interfaces.ITitleBarLayout;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.util.TUIConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.FoldedConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationFoldPresenter;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.ConversationUtils;
import java.util.ArrayList;
import java.util.List;
public class TUIFoldedConversationFragment extends BaseFragment {
private View mBaseView;
private TitleBarLayout mTitleBarLayout;
private FoldedConversationLayout mFoldedLayout;
private PopDialogAdapter mConversationPopAdapter;
private ListView mConversationPopList;
private PopupWindow mConversationPopWindow;
private String popWindowConversationId;
private List<PopMenuAction> mConversationPopActions = new ArrayList<>();
private ConversationFoldPresenter presenter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mBaseView = inflater.inflate(R.layout.folded_fragment, container, false);
initView();
return mBaseView;
}
private void initView() {
mFoldedLayout = mBaseView.findViewById(R.id.folded_conversation_layout);
mTitleBarLayout = mFoldedLayout.getTitleBar();
mTitleBarLayout.setTitle(getResources().getString(R.string.folded_group_chat), ITitleBarLayout.Position.MIDDLE);
mTitleBarLayout.setOnLeftClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().finish();
}
});
presenter = new ConversationFoldPresenter();
presenter.initListener();
mFoldedLayout.setPresenter(presenter);
mFoldedLayout.initDefault();
mFoldedLayout.getConversationList().setOnConversationAdapterListener(new OnConversationAdapterListener() {
@Override
public void onItemClick(View view, int viewType, ConversationInfo conversationInfo) {
TUIConversationUtils.startChatActivity(conversationInfo);
}
@Override
public void OnItemLongClick(View view, ConversationInfo conversationInfo) {
showItemPopMenu(view, conversationInfo);
}
@Override
public void onConversationChanged(List<ConversationInfo> dataSource) {
if (dataSource == null)return;
ConversationInfo conversationInfo = dataSource.get(0);
if (conversationInfo == null)return;
if (!TextUtils.isEmpty(popWindowConversationId) && popWindowConversationId.equals(conversationInfo.getConversationId())) {
if (mConversationPopWindow != null) {
mConversationPopWindow.dismiss();
}
}
}
@Override
public void onUserIconClick(ConversationInfo conversationInfo) {
}
});
restoreConversationItemBackground();
}
private void initPopMenuAction() {
// 设置长按conversation显示PopAction
List<PopMenuAction> conversationPopActions = new ArrayList<PopMenuAction>();
PopMenuAction action = new PopMenuAction();
action.setActionName(getResources().getString(R.string.not_display));
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
ConversationInfo conversationInfo = (ConversationInfo) data;
mFoldedLayout.markConversationHidden((ConversationInfo) data);
}
});
conversationPopActions.add(action);
action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mFoldedLayout.deleteConversation((ConversationInfo) data);
}
});
action.setActionName(getResources().getString(R.string.chat_delete));
conversationPopActions.add(action);
mConversationPopActions.clear();
mConversationPopActions.addAll(conversationPopActions);
}
private void restoreConversationItemBackground() {
if (mFoldedLayout.getConversationList().getAdapter() != null &&
mFoldedLayout.getConversationList().getAdapter().isClick()) {
mFoldedLayout.getConversationList().getAdapter().setClick(false);
mFoldedLayout.getConversationList().getAdapter().notifyItemChanged(mFoldedLayout.getConversationList().getAdapter().getCurrentPosition());
}
}
private void addMarkUnreadPopMenuAction(boolean markUnread) {
PopMenuAction action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mFoldedLayout.markConversationUnread((ConversationInfo) data, markUnread);
}
});
if (markUnread) {
action.setActionName(getResources().getString(R.string.mark_unread));
} else {
action.setActionName(getResources().getString(R.string.mark_read));
}
mConversationPopActions.add(0, action);
}
private void showItemPopMenu(View view, final ConversationInfo conversationInfo) {
initPopMenuAction();
if (conversationInfo.getUnRead() > 0) {
addMarkUnreadPopMenuAction(false);
} else {
if (conversationInfo.isMarkUnread()) {
addMarkUnreadPopMenuAction(false);
} else {
addMarkUnreadPopMenuAction(true);
}
}
View itemPop = LayoutInflater.from(getActivity()).inflate(R.layout.conversation_pop_menu_layout, null);
mConversationPopList = itemPop.findViewById(R.id.pop_menu_list);
mConversationPopList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PopMenuAction action = mConversationPopActions.get(position);
if (action.getActionClickListener() != null) {
action.getActionClickListener().onActionClick(position, conversationInfo);
}
mConversationPopWindow.dismiss();
restoreConversationItemBackground();
}
});
for (int i = 0; i < mConversationPopActions.size(); i++) {
PopMenuAction action = mConversationPopActions.get(i);
if (conversationInfo.isTop()) {
if (action.getActionName().equals(getResources().getString(R.string.chat_top))) {
action.setActionName(getResources().getString(R.string.quit_chat_top));
}
} else {
if (action.getActionName().equals(getResources().getString(R.string.quit_chat_top))) {
action.setActionName(getResources().getString(R.string.chat_top));
}
}
}
mConversationPopAdapter = new PopDialogAdapter();
mConversationPopList.setAdapter(mConversationPopAdapter);
mConversationPopAdapter.setDataSource(mConversationPopActions);
mConversationPopWindow = new PopupWindow(itemPop, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
mConversationPopWindow.setBackgroundDrawable(new ColorDrawable());
mConversationPopWindow.setOutsideTouchable(true);
popWindowConversationId = conversationInfo.getConversationId();
int width = ConversationUtils.getListUnspecifiedWidth(mConversationPopAdapter, mConversationPopList);
mConversationPopWindow.setWidth(width);
mConversationPopWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
restoreConversationItemBackground();
popWindowConversationId = "";
}
});
int x = view.getWidth() / 2;
int y = - view.getHeight() / 3;
int popHeight = ScreenUtil.dip2px(45) * 3;
if (y + popHeight + view.getY() + view.getHeight() > mFoldedLayout.getBottom()) {
y = y - popHeight;
}
mConversationPopWindow.showAsDropDown(view, x, y, Gravity.TOP | Gravity.START);
}
}

View File

@@ -0,0 +1,42 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.page;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuicore.component.activities.BaseLightActivity;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
public class TUIForwardSelectActivity extends BaseLightActivity {
private static final String TAG = TUIForwardSelectActivity.class.getSimpleName();
private TUIForwardSelectFragment mTUIForwardSelectFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.forward_activity);
init();
}
@Override
protected void onNewIntent(Intent intent) {
TUIConversationLog.i(TAG, "onNewIntent");
super.onNewIntent(intent);;
}
@Override
protected void onResume() {
TUIConversationLog.i(TAG, "onResume");
super.onResume();
}
private void init() {
mTUIForwardSelectFragment = new TUIForwardSelectFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.empty_view, mTUIForwardSelectFragment).commitAllowingStateLoss();
}
}

View File

@@ -0,0 +1,337 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.page;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.component.CustomLinearLayoutManager;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.fragments.BaseFragment;
import com.tencent.qcloud.tuicore.component.interfaces.ITitleBarLayout;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationConstants;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.ConversationListLayout;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.ForwardConversationSelectorAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.ForwardSelectLayout;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class TUIForwardSelectFragment extends BaseFragment {
private View mBaseView;
private TitleBarLayout mTitleBarLayout;
private ForwardSelectLayout mForwardLayout;
private RecyclerView mForwardSelectlistView;
private ForwardConversationSelectorAdapter mAdapter;
private List<ConversationInfo> mDataSource = new ArrayList<>();
private List<ConversationInfo> mContactDataSource = new ArrayList<>();
private List<ConversationInfo> mAllSelectedConversations = new ArrayList<>();
private RelativeLayout mForwardSelectlistViewLayout;
private TextView mSureView;
private ConversationPresenter presenter;
private static final String TAG = TUIForwardSelectFragment.class.getSimpleName();
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
mBaseView = inflater.inflate(R.layout.forward_fragment, container, false);
return mBaseView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mForwardLayout = view.findViewById(R.id.forward_conversation_layout);
presenter = new ConversationPresenter();
mForwardLayout.setPresenter(presenter);
mForwardLayout.initDefault();
customizeConversation();
mForwardLayout.getConversationList().setOnConversationAdapterListener(new OnConversationAdapterListener() {
@Override
public void onItemClick(View view, int viewType, ConversationInfo conversationInfo) {
if (viewType == ConversationInfo.TYPE_RECENT_LABEL){
return;
} else if (viewType == ConversationInfo.TYPE_FORWAR_SELECT){
if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_cancle))){
Bundle param = new Bundle();
param.putInt(TUIConversationConstants.GroupType.TYPE, TUIConversationConstants.GroupType.PUBLIC);
param.putBoolean(TUIConversationConstants.FORWARD_CREATE_NEW_CHAT, false);
TUICore.startActivity(TUIForwardSelectFragment.this, "ForwardSelectGroupActivity", param, TUIConversationConstants.FORWARD_SELECT_MEMBERS_CODE);
}else if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_close))){
Bundle param = new Bundle();
param.putInt(TUIConversationConstants.GroupType.TYPE, TUIConversationConstants.GroupType.PUBLIC);
param.putBoolean(TUIConversationConstants.FORWARD_CREATE_NEW_CHAT, true);
TUICore.startActivity(TUIForwardSelectFragment.this, "ForwardSelectGroupActivity", param, TUIConversationConstants.FORWARD_CREATE_GROUP_CODE);
}else{
TUIConversationLog.d(TAG,"Titlebar exception");
}
} else {
if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_cancle))) {
mDataSource = mForwardLayout.getConversationList().getAdapter().getSelectedItem();
checkRepeat();
refreshSelectConversations();
} else if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_close))){
forwardMessages(conversationInfo);
} else {
forwardMessages(conversationInfo);
}
}
}
@Override
public void OnItemLongClick(View view, ConversationInfo conversationInfo) {
}
@Override
public void onConversationChanged(List<ConversationInfo> dataSource) {
}
@Override
public void onUserIconClick(ConversationInfo conversationInfo) {
}
});
mForwardSelectlistViewLayout = view.findViewById(R.id.forward_select_list_layout);
mForwardSelectlistViewLayout.setVisibility(View.VISIBLE);
mForwardSelectlistView = view.findViewById(R.id.forward_select_list);
mForwardSelectlistView.setLayoutManager(new CustomLinearLayoutManager(getContext(), CustomLinearLayoutManager.HORIZONTAL, false));
mAdapter = new ForwardConversationSelectorAdapter(this.getContext());
mForwardSelectlistView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new ForwardConversationSelectorAdapter.OnItemClickListener() {
@Override
public void onClick(View view, int position) {
boolean needFresh = false;
if (mDataSource != null && mDataSource.size() != 0){
if(position < mDataSource.size()) {
mDataSource.remove(position);
mForwardLayout.getConversationList().getAdapter().setSelectConversations(mDataSource);
needFresh = true;
}
}
if(!needFresh) {
if (mContactDataSource != null && mContactDataSource.size() != 0) {
int dataSourcePosition = mDataSource == null ? 0 : mDataSource.size();
if (position - dataSourcePosition < mContactDataSource.size()) {
mContactDataSource.remove(position - dataSourcePosition);
needFresh = true;
}
}
}
if (needFresh) {
refreshSelectConversations();
}
}
});
mSureView = view.findViewById(R.id.btn_msg_ok);
mSureView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getActivity() != null) {
HashMap<String, Boolean> conversationMap = new HashMap<>();
if (mDataSource != null && mDataSource.size() != 0){
for (int i=0;i<mDataSource.size();i++){
conversationMap.put(mDataSource.get(i).getId(), mDataSource.get(i).isGroup());
}
}
if (mContactDataSource != null && mContactDataSource.size() != 0){
for (int i=0;i<mContactDataSource.size();i++){
conversationMap.put(mContactDataSource.get(i).getId(), mContactDataSource.get(i).isGroup());
}
}
Intent intent = new Intent();
intent.putExtra(TUIConversationConstants.FORWARD_SELECT_CONVERSATION_KEY, conversationMap);
getActivity().setResult(TUIConversationConstants.FORWARD_SELECT_ACTIVTY_CODE, intent);
getActivity().finish();
}
}
});
refreshSelectConversations();
initTitleAction();
}
private void refreshSelectConversations(){
mAllSelectedConversations.clear();
mDataSource = mForwardLayout.getConversationList().getAdapter().getSelectedItem();
if (mDataSource != null && mDataSource.size() != 0){
mAllSelectedConversations.addAll(mDataSource);
}
if (mContactDataSource != null && mContactDataSource.size() != 0){
mAllSelectedConversations.addAll(mContactDataSource);
}
mAdapter.setDataSource(mAllSelectedConversations);
if (mAllSelectedConversations == null || mAllSelectedConversations.size() == 0){
mSureView.setText(getString(com.tencent.qcloud.tuicore.R.string.sure));
mSureView.setVisibility(View.GONE);
mForwardSelectlistViewLayout.setVisibility(View.GONE);
} else {
mForwardSelectlistViewLayout.setVisibility(View.VISIBLE);
mSureView.setVisibility(View.VISIBLE);
mSureView.setText(getString(com.tencent.qcloud.tuicore.R.string.sure) + "(" + mAllSelectedConversations.size() + ")");
}
}
private void forwardMessages(final ConversationInfo conversationInfo){
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("");
builder.setMessage(getString(R.string.forward_alert_title));
builder.setCancelable(true);
builder.setPositiveButton(getString(com.tencent.qcloud.tuicore.R.string.sure), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (getActivity() != null) {
HashMap<String, Boolean> chatInfo = new HashMap<>();
chatInfo.put(conversationInfo.getId(), conversationInfo.isGroup());
Intent intent = new Intent();
intent.putExtra(TUIConversationConstants.FORWARD_SELECT_CONVERSATION_KEY, chatInfo);
getActivity().setResult(TUIConversationConstants.FORWARD_SELECT_ACTIVTY_CODE, intent);
getActivity().finish();
}
dialog.dismiss();
}
});
builder.setNegativeButton(getString(com.tencent.qcloud.tuicore.R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void customizeConversation(){
mTitleBarLayout = mForwardLayout.getTitleBar();
mTitleBarLayout.setTitle("", TitleBarLayout.Position.MIDDLE);
mTitleBarLayout.getLeftGroup().setVisibility(View.VISIBLE);
mTitleBarLayout.getRightGroup().setVisibility(View.VISIBLE);
mTitleBarLayout.setTitle(getString(R.string.titlebar_close), ITitleBarLayout.Position.LEFT);
mTitleBarLayout.setTitle(getString(R.string.titlebar_mutiselect), TitleBarLayout.Position.RIGHT);
mTitleBarLayout.getLeftIcon().setVisibility(View.GONE);
mTitleBarLayout.getRightIcon().setVisibility(View.GONE);
}
private void initTitleAction() {
mForwardLayout.getTitleBar().setOnLeftClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_cancle))){
mTitleBarLayout.getRightGroup().setVisibility(View.VISIBLE);
mTitleBarLayout.setTitle(getString(R.string.titlebar_close), TitleBarLayout.Position.LEFT);
mTitleBarLayout.setTitle(getString(R.string.titlebar_mutiselect), TitleBarLayout.Position.RIGHT);
ConversationListLayout listLayout = mForwardLayout.getConversationList();
listLayout.getAdapter().setShowMultiSelectCheckBox(false);
listLayout.getAdapter().notifyDataSetChanged();
mForwardSelectlistViewLayout.setVisibility(View.GONE);
mAdapter.setDataSource(null);
mAllSelectedConversations.clear();
}else if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_close))){
getActivity().finish();
}else{
TUIConversationLog.d(TAG,"Titlebar exception");
}
}
});
mForwardLayout.getTitleBar().setOnRightClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mTitleBarLayout.getRightGroup().setVisibility(View.GONE);
mTitleBarLayout.setTitle(getString(R.string.titlebar_cancle), TitleBarLayout.Position.LEFT);
ConversationListLayout listLayout = mForwardLayout.getConversationList();
listLayout.getAdapter().setShowMultiSelectCheckBox(true);
listLayout.getAdapter().notifyDataSetChanged();
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == TUIConversationConstants.FORWARD_CREATE_GROUP_CODE && resultCode == TUIConversationConstants.FORWARD_CREATE_GROUP_CODE) {
if (getActivity() != null) {
getActivity().setResult(TUIConversationConstants.FORWARD_SELECT_ACTIVTY_CODE, data);
getActivity().finish();
}
} else if (requestCode == TUIConversationConstants.FORWARD_SELECT_MEMBERS_CODE && resultCode == TUIConversationConstants.FORWARD_SELECT_MEMBERS_CODE){
HashMap<String, String> conversationMap = (HashMap<String, String>) data.getSerializableExtra(TUIConversationConstants.FORWARD_SELECT_CONVERSATION_KEY);
if (conversationMap == null || conversationMap.isEmpty()){
mContactDataSource.clear();
refreshSelectConversations();
return;
}
mContactDataSource.clear();
for (Map.Entry<String, String> entry: conversationMap.entrySet()){
ConversationInfo conversationInfo = new ConversationInfo();
List<Object> iconList = new ArrayList<>();
iconList.add(entry.getValue());
conversationInfo.setIconUrlList(iconList);
conversationInfo.setId(entry.getKey());
conversationInfo.setGroup(false);
mContactDataSource.add(conversationInfo);
}
checkRepeat();
refreshSelectConversations();
}
}
private void checkRepeat() {
Iterator<ConversationInfo> iterator = mContactDataSource.iterator();
while (iterator.hasNext()) {
ConversationInfo conversationInfo = iterator.next();
if (mDataSource != null && mDataSource.size() != 0) {
for (int i = 0; i < mDataSource.size(); i++) {
if (conversationInfo.getId().equals(mDataSource.get(i).getId())) {
iterator.remove();
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.setting;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.ConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.widget.ConversationListLayout;
public class ConversationLayoutSetting {
public static void customizeConversation(final ConversationLayout layout) {
ConversationListLayout listLayout = (ConversationListLayout) layout.getConversationList();
listLayout.setItemTopTextSize(16);
listLayout.setItemBottomTextSize(12);
listLayout.setItemDateTextSize(10);
listLayout.setItemAvatarRadius(180);
listLayout.disableItemUnreadDot(false);
// 动态插入删除Item包括自定义会话
// final ConversationInfo customInfo = new ConversationInfo();
// customInfo.setType(ConversationInfo.TYPE_CUSTOM);
// customInfo.setId("自定义会话");
// customInfo.setGroup(false);
// customInfo.setTitle("乔丹风行8代跑鞋 风随我动!");
// customInfo.setIconUrl("https://img1.gtimg.com/ninja/2/2019/03/ninja155375585738456.jpg");
//
//
// new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
// @Override
// public void run() {
// layout.addConversationInfo(0, customInfo);
// }
// }, 3000);
// new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
// @Override
// public void run() {
// layout.removeConversationInfo(0);
// }
// }, 5000);
}
}

View File

@@ -0,0 +1,35 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.util;
import android.os.Bundle;
import com.tencent.imsdk.v2.V2TIMConversation;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.io.Serializable;
public class TUIConversationUtils {
public static void startChatActivity(ConversationInfo conversationInfo) {
Bundle param = new Bundle();
param.putInt(TUIConstants.TUIChat.CHAT_TYPE, conversationInfo.isGroup() ? V2TIMConversation.V2TIM_GROUP : V2TIMConversation.V2TIM_C2C);
param.putString(TUIConstants.TUIChat.CHAT_ID, conversationInfo.getId());
param.putString(TUIConstants.TUIChat.CHAT_NAME, conversationInfo.getTitle());
param.putString(TUIConstants.TUIChat.ROOM_ID,conversationInfo.getRoom_id());
if (conversationInfo.getDraft() != null) {
param.putString(TUIConstants.TUIChat.DRAFT_TEXT, conversationInfo.getDraft().getDraftText());
param.putLong(TUIConstants.TUIChat.DRAFT_TIME, conversationInfo.getDraft().getDraftTime());
}
param.putBoolean(TUIConstants.TUIChat.IS_TOP_CHAT, conversationInfo.isTop());
param.putString(TUIConstants.TUIChat.FACE_URL, conversationInfo.getIconPath());
if (conversationInfo.isGroup()) {
param.putString(TUIConstants.TUIChat.GROUP_TYPE, conversationInfo.getGroupType());
param.putSerializable(TUIConstants.TUIChat.AT_INFO_LIST, (Serializable) conversationInfo.getGroupAtInfoList());
}
if (conversationInfo.isGroup()) {
TUICore.startActivity(TUIConstants.TUIChat.GROUP_CHAT_ACTIVITY_NAME, param);
} else {
TUICore.startActivity(TUIConstants.TUIChat.C2C_CHAT_ACTIVITY_NAME, param);
}
}
}

View File

@@ -0,0 +1,25 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.view.View;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import androidx.recyclerview.widget.RecyclerView;
public abstract class ConversationBaseHolder extends RecyclerView.ViewHolder {
protected View rootView;
protected ConversationListAdapter mAdapter;
public ConversationBaseHolder(View itemView) {
super(itemView);
rootView = itemView;
}
public void setAdapter(RecyclerView.Adapter adapter) {
mAdapter = (ConversationListAdapter) adapter;
}
public abstract void layoutViews(ConversationInfo conversationInfo, int position);
}

View File

@@ -0,0 +1,251 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.graphics.Color;
import android.text.Html;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.imsdk.v2.V2TIMUserStatus;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.TUIThemeManager;
import com.tencent.qcloud.tuicore.component.UnreadCountTextView;
import com.tencent.qcloud.tuicore.util.DateTimeUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.bean.DraftInfo;
import com.tencent.qcloud.tuikit.tuiconversation.config.TUIConversationConfig;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
import java.util.Date;
import java.util.HashMap;
public class ConversationCommonHolder extends ConversationBaseHolder {
public ConversationIconView conversationIconView;
protected LinearLayout leftItemLayout;
protected TextView titleText;
protected TextView messageText;
protected TextView timelineText;
protected UnreadCountTextView unreadText;
protected TextView atInfoText;
protected ImageView disturbView;
protected CheckBox multiSelectCheckBox;
protected RelativeLayout messageStatusLayout;
public ImageView messageSending;
public ImageView messageFailed;
private boolean isForwardMode = false;
protected View userStatusView;
private boolean showFoldedStyle = true;
public ConversationCommonHolder(View itemView) {
super(itemView);
leftItemLayout = rootView.findViewById(R.id.item_left);
conversationIconView = rootView.findViewById(R.id.conversation_icon);
titleText = rootView.findViewById(R.id.conversation_title);
messageText = rootView.findViewById(R.id.conversation_last_msg);
timelineText = rootView.findViewById(R.id.conversation_time);
unreadText = rootView.findViewById(R.id.conversation_unread);
atInfoText = rootView.findViewById(R.id.conversation_at_msg);
disturbView = rootView.findViewById(R.id.not_disturb);
multiSelectCheckBox = rootView.findViewById(R.id.select_checkbox);
messageStatusLayout = rootView.findViewById(R.id.message_status_layout);
messageFailed = itemView.findViewById(R.id.message_status_failed);
messageSending = itemView.findViewById(R.id.message_status_sending);
userStatusView = itemView.findViewById(R.id.user_status);
}
public void setForwardMode(boolean forwardMode) {
isForwardMode = forwardMode;
}
public void setShowFoldedStyle(boolean showFoldedStyle) {
this.showFoldedStyle = showFoldedStyle;
}
public void layoutViews(ConversationInfo conversation, int position) {
// if (conversation.isTop() && !isForwardMode) {
// leftItemLayout.setBackgroundColor(rootView.getResources().getColor(R.color.conversation_item_top_color));
// } else {
// leftItemLayout.setBackgroundColor(Color.WHITE);
// }
if (showFoldedStyle && conversation.isMarkFold()) {
titleText.setText(R.string.folded_group_chat);
timelineText.setVisibility(View.GONE);
} else {
titleText.setText(conversation.getTitle());
}
messageText.setText("");
timelineText.setText("");
DraftInfo draftInfo = conversation.getDraft();
String draftText = "";
if (draftInfo != null) {
Gson gson = new Gson();
HashMap draftJsonMap;
draftText = draftInfo.getDraftText();
try {
draftJsonMap = gson.fromJson(draftInfo.getDraftText(), HashMap.class);
if (draftJsonMap != null) {
draftText = (String) draftJsonMap.get("content");
}
} catch (JsonSyntaxException e) {
TUIConversationLog.e("ConversationCommonHolder", " getDraftJsonMap error ");
}
}
if (draftInfo != null) {
messageText.setText(draftText);
timelineText.setText(DateTimeUtil.getTimeFormatText(new Date(draftInfo.getDraftTime() * 1000)));
} else {
HashMap<String, Object> param = new HashMap<>();
param.put(TUIConstants.TUIChat.V2TIMMESSAGE, conversation.getLastMessage());
String lastMsgDisplayString = (String) TUICore.callService(TUIConstants.TUIChat.SERVICE_NAME, TUIConstants.TUIChat.METHOD_GET_DISPLAY_STRING, param);
// 获取要显示的字符
// Get the characters to display
if (lastMsgDisplayString != null) {
messageText.setText(Html.fromHtml(lastMsgDisplayString));
messageText.setTextColor(rootView.getResources().getColor(R.color.list_bottom_text_bg));
}
if (conversation.getLastMessage() != null) {
timelineText.setText(DateTimeUtil.getTimeFormatText(new Date(conversation.getLastMessageTime() * 1000)));
}
}
if (conversation.isShowDisturbIcon()) {
if ((showFoldedStyle && conversation.isMarkFold())) {
if (conversation.isMarkLocalUnread()) {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("");
} else {
unreadText.setVisibility(View.GONE);
}
} else {
if (conversation.getUnRead() == 0) {
if (conversation.isMarkUnread()) {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("");
} else {
unreadText.setVisibility(View.GONE);
}
} else {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("");
if (messageText.getText() != null) {
String text = messageText.getText().toString();
messageText.setText("[" + conversation.getUnRead() + rootView.getContext().getString(R.string.message_num) + "] " + text);
}
}
}
} else if (conversation.getUnRead() > 0) {
unreadText.setVisibility(View.VISIBLE);
if (conversation.getUnRead() > 99) {
unreadText.setText("99+");
} else {
unreadText.setText("" + conversation.getUnRead());
}
} else {
if (conversation.isMarkUnread()) {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("1");
} else {
unreadText.setVisibility(View.GONE);
}
}
if (draftInfo != null) {
atInfoText.setVisibility(View.VISIBLE);
atInfoText.setText(R.string.drafts);
atInfoText.setTextColor(Color.RED);
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
} else {
if (conversation.getAtInfoText().isEmpty()) {
atInfoText.setVisibility(View.GONE);
} else {
atInfoText.setVisibility(View.VISIBLE);
atInfoText.setText(conversation.getAtInfoText());
atInfoText.setTextColor(Color.RED);
}
V2TIMMessage lastMessage = conversation.getLastMessage();
if (lastMessage != null) {
int status = lastMessage.getStatus();
if (status == V2TIMMessage.V2TIM_MSG_STATUS_SEND_FAIL) {
messageStatusLayout.setVisibility(View.VISIBLE);
messageFailed.setVisibility(View.VISIBLE);
messageSending.setVisibility(View.GONE);
} else if (status == V2TIMMessage.V2TIM_MSG_STATUS_SENDING) {
messageStatusLayout.setVisibility(View.VISIBLE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.VISIBLE);
} else {
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
}
} else {
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
}
}
conversationIconView.setRadius(mAdapter.getItemAvatarRadius());
if (mAdapter.getItemDateTextSize() != 0) {
timelineText.setTextSize(mAdapter.getItemDateTextSize());
}
if (mAdapter.getItemBottomTextSize() != 0) {
messageText.setTextSize(mAdapter.getItemBottomTextSize());
}
if (mAdapter.getItemTopTextSize() != 0) {
titleText.setTextSize(mAdapter.getItemTopTextSize());
}
if (!mAdapter.hasItemUnreadDot()) {
unreadText.setVisibility(View.GONE);
}
conversationIconView.setShowFoldedStyle(showFoldedStyle);
conversationIconView.setConversation(conversation);
if (conversation.isShowDisturbIcon() && !isForwardMode) {
if (showFoldedStyle && conversation.isMarkFold()) {
disturbView.setVisibility(View.GONE);
} else {
disturbView.setVisibility(View.VISIBLE);
}
} else {
disturbView.setVisibility(View.GONE);
}
if (isForwardMode) {
messageText.setVisibility(View.GONE);
timelineText.setVisibility(View.GONE);
unreadText.setVisibility(View.GONE);
atInfoText.setVisibility(View.GONE);
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
}
if (!conversation.isGroup() && TUIConversationConfig.getInstance().isShowUserStatus()) {
userStatusView.setVisibility(View.VISIBLE);
if (conversation.getStatusType() == V2TIMUserStatus.V2TIM_USER_STATUS_ONLINE) {
userStatusView.setBackgroundResource(TUIThemeManager.getAttrResId(rootView.getContext(), com.tencent.qcloud.tuicore.R.attr.user_status_online));
} else {
userStatusView.setBackgroundResource(TUIThemeManager.getAttrResId(rootView.getContext(), com.tencent.qcloud.tuicore.R.attr.user_status_offline));
}
} else {
userStatusView.setVisibility(View.GONE);
}
}
}

View File

@@ -0,0 +1,68 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.graphics.Color;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
public class ConversationCustomHolder extends ConversationBaseHolder {
protected LinearLayout leftItemLayout;
protected TextView titleText;
protected TextView messageText;
protected TextView timelineText;
protected TextView unreadText;
protected ConversationIconView conversationIconView;
public ConversationCustomHolder(View itemView) {
super(itemView);
leftItemLayout = rootView.findViewById(R.id.item_left);
conversationIconView = rootView.findViewById(R.id.conversation_icon);
titleText = rootView.findViewById(R.id.conversation_title);
messageText = rootView.findViewById(R.id.conversation_last_msg);
timelineText = rootView.findViewById(R.id.conversation_time);
unreadText = rootView.findViewById(R.id.conversation_unread);
}
@Override
public void layoutViews(ConversationInfo conversation, int position) {
if (conversation.isTop()) {
leftItemLayout.setBackgroundColor(rootView.getResources().getColor(R.color.conversation_item_top_color));
} else {
leftItemLayout.setBackgroundColor(Color.WHITE);
}
conversationIconView.setConversation(conversation);
titleText.setText(conversation.getTitle());
messageText.setText("");
timelineText.setText("");
if (conversation.getUnRead() > 0) {
unreadText.setVisibility(View.VISIBLE);
if (conversation.getUnRead() > 99) {
unreadText.setText("99+");
} else {
unreadText.setText("" + conversation.getUnRead());
}
} else {
unreadText.setVisibility(View.GONE);
}
if (mAdapter.getItemDateTextSize() != 0) {
timelineText.setTextSize(mAdapter.getItemDateTextSize());
}
if (mAdapter.getItemBottomTextSize() != 0) {
messageText.setTextSize(mAdapter.getItemBottomTextSize());
}
if (mAdapter.getItemTopTextSize() != 0) {
titleText.setTextSize(mAdapter.getItemTopTextSize());
}
}
}

View File

@@ -0,0 +1,171 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.tencent.qcloud.tuicore.TUIConfig;
import com.tencent.qcloud.tuicore.component.gatherimage.SynthesizedImageView;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuicore.util.BackgroundTasks;
import com.tencent.qcloud.tuicore.util.ImageUtil;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuicore.util.ThreadHelper;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationIconPresenter;
import java.util.ArrayList;
import java.util.List;
/**
* 会话列表头像View
*/
public class ConversationIconView extends RelativeLayout {
private static final int icon_size = ScreenUtil.getPxByDp(50);
private ImageView mIconView;
private boolean showFoldedStyle = false;
private ConversationIconPresenter presenter;
public ConversationIconView(Context context) {
super(context);
init();
}
public ConversationIconView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ConversationIconView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
inflate(getContext(), com.tencent.qcloud.tuicore.R.layout.profile_icon_view, this);
mIconView = findViewById(com.tencent.qcloud.tuicore.R.id.profile_icon);
((SynthesizedImageView) mIconView).defaultImage(TUIConfig.getDefaultAvatarImage());
presenter = new ConversationIconPresenter();
}
public void setShowFoldedStyle(boolean showFoldedStyle) {
this.showFoldedStyle = showFoldedStyle;
}
/**
* 设置会话头像的url
*
* @param iconUrls 头像url,最多只取前9个
*/
public void setIconUrls(final List<Object> iconUrls, final String conversationId) {
// 需要在主线程中执行,以免写缓存出现问题
BackgroundTasks.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) (mIconView)).displayImage(iconUrls).load(conversationId);
}
}
});
}
public void setConversation(ConversationInfo conversationInfo) {
if (showFoldedStyle && conversationInfo.isMarkFold()) {
mIconView.setImageResource(R.drawable.ic_fold);
} else if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) (mIconView)).setImageId(conversationInfo.getConversationId());
if (conversationInfo.isGroup()) {
fillConversationUrlForGroup(conversationInfo);
} else {
setIconUrls(conversationInfo.getIconUrlList(), conversationInfo.getConversationId());
}
}
}
private void fillConversationUrlForGroup(final ConversationInfo info) {
List<Object> iconUrlList = info.getIconUrlList();
if (iconUrlList == null || iconUrlList.size() == 0) {
if (!TUIConfig.isEnableGroupGridAvatar()) {
List<Object> faceList = new ArrayList<>();
faceList.add(TUIConfig.getDefaultGroupAvatarImage());
setIconUrls(faceList, info.getConversationId());
return;
}
// 读取文件,在线程池中进行,避免主线程卡顿
ThreadHelper.INST.execute(new Runnable() {
@Override
public void run() {
final String savedIcon = ImageUtil.getGroupConversationAvatar(info.getConversationId());
if (TextUtils.isEmpty(savedIcon)) {
fillFaceUrlList(info.getId(), info);
} else {
List<Object> list = new ArrayList<>();
list.add(savedIcon);
info.setIconUrlList(list);
setIconUrls(list, info.getConversationId());
}
}
});
} else {
if (!TUIConfig.isEnableGroupGridAvatar() && iconUrlList.size() > 1) {
List<Object> faceList = new ArrayList<>();
faceList.add(TUIConfig.getDefaultGroupAvatarImage());
setIconUrls(faceList, info.getConversationId());
} else {
setIconUrls(iconUrlList, info.getConversationId());
}
}
}
private void fillFaceUrlList(final String groupID, final ConversationInfo info) {
BackgroundTasks.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
clearImage();
presenter.getGroupMemberIconList(groupID, new IUIKitCallback<List<Object>>() {
@Override
public void onSuccess(List<Object> data) {
info.setIconUrlList(data);
setIconUrls(data, info.getConversationId());
}
@Override
public void onError(String module, int errCode, String errMsg) {
}
});
}
});
}
public void setRadius(int radius) {
if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) (mIconView)).setRadius(radius);
}
}
public void setDefaultImageResId(int resId) {
BitmapDrawable bd = (BitmapDrawable) getContext().getResources().getDrawable(resId);
mIconView.setImageBitmap(bd.getBitmap());
}
public void setBitmapResId(int resId) {
BitmapDrawable bd = (BitmapDrawable) getContext().getResources().getDrawable(resId);
Bitmap bitmap = ImageUtil.toRoundBitmap(bd.getBitmap());
mIconView.setImageBitmap(bitmap);
}
public void clearImage() {
if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) mIconView).clear();
}
}
}

View File

@@ -0,0 +1,143 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.IConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
import java.util.HashMap;
import java.util.Map;
public class ConversationLayout extends RelativeLayout implements IConversationLayout {
private ConversationListLayout mConversationList;
private ConversationPresenter presenter;
public ConversationLayout(Context context) {
super(context);
init();
}
public ConversationLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ConversationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setPresenter(ConversationPresenter presenter) {
this.presenter = presenter;
if (mConversationList != null) {
mConversationList.setPresenter(presenter);
}
}
/**
* 初始化相关UI元素
*/
private void init() {
inflate(getContext(), R.layout.conversation_layout, this);
mConversationList = findViewById(R.id.conversation_list);
}
public void initDefault() {
final ConversationListAdapter adapter = new ConversationListAdapter();
if (presenter != null) {
initSearchView(adapter);
adapter.setShowFoldedStyle(true);
}
mConversationList.setAdapter((IConversationListAdapter) adapter);
if (presenter != null) {
presenter.setAdapter(adapter);
}
mConversationList.loadConversation(0);
}
public void initSearchView(ConversationListAdapter adapter) {
Map<String, Object> param = new HashMap<>();
param.put(TUIConstants.TUIConversation.CONTEXT, getContext());
Map<String, Object> searchExtension = TUICore.getExtensionInfo(TUIConstants.TUIConversation.EXTENSION_CLASSIC_SEARCH, param);
if (searchExtension != null) {
View searchView = (View) searchExtension.get(TUIConstants.TUIConversation.SEARCH_VIEW);
if (searchView != null) {
adapter.setSearchView(searchView);
}
}
}
@Override
public void setParentLayout(Object parent) {
}
@Override
public ConversationListLayout getConversationList() {
return mConversationList;
}
@Override
public void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack) {
if (presenter != null) {
presenter.setConversationTop(conversation, callBack);
}
}
@Override
public void deleteConversation(ConversationInfo conversation) {
if (presenter != null) {
presenter.deleteConversation(conversation);
}
}
@Override
public void clearConversationMessage(ConversationInfo conversation) {
if (presenter != null) {
presenter.clearConversationMessage(conversation);
}
}
@Override
public void markConversationHidden(ConversationInfo conversation) {
if (presenter != null) {
presenter.markConversationHidden(conversation, true);
}
}
@Override
public void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread) {
if (presenter != null) {
presenter.markConversationUnread(conversationInfo, markUnread);
}
}
@Override
public void hideFoldedItem(boolean needHide) {
if (presenter != null) {
presenter.hideFoldItem(needHide);
}
}
@Override
public void clearUnreadStatusOfFoldItem() {
if (presenter != null) {
presenter.setUnreadStatusOfFoldItem(false);
}
}
@Override
public TitleBarLayout getTitleBar() {
return null;
}
}

View File

@@ -0,0 +1,550 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.graphics.Color;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationService;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ConversationListAdapter extends RecyclerView.Adapter implements IConversationListAdapter {
public static final int ITEM_TYPE_HEADER_SEARCH = 101;
public static final int ITEM_TYPE_FOOTER_LOADING = -99;
public static final int HEADER_COUNT = 1;
public static final int FOOTER_COUNT = 1;
public static final int SELECT_COUNT = 1;
public static final int SELECT_LABEL_COUNT = 1;
private boolean mHasShowUnreadDot = true;
private int mItemAvatarRadius = ScreenUtil.getPxByDp(50);
private int mTopTextSize;
private int mBottomTextSize;
private int mDateTextSize;
protected List<ConversationInfo> mDataSource = new ArrayList<>();
private OnConversationAdapterListener mOnConversationAdapterListener;
//消息转发
private final HashMap<String, Boolean> mSelectedPositions = new HashMap<>();
private boolean isShowMultiSelectCheckBox = false;
private boolean isForwardFragment = false;
private boolean mIsLoading = false;
// 长按高亮显示
private boolean isClick = false;
private int currentPosition = -1;
private View searchView;
// 展示折叠样式
private boolean showFoldedStyle = true;
public ConversationListAdapter() {
}
public int getCurrentPosition() {
return currentPosition;
}
public boolean isClick() {
return isClick;
}
public void setClick(boolean click) {
isClick = click;
}
public void setCurrentPosition(int currentPosition, boolean isClick) {
this.currentPosition = currentPosition;
this.isClick = isClick;
}
public void setShowMultiSelectCheckBox(boolean show) {
isShowMultiSelectCheckBox = show;
if (!isShowMultiSelectCheckBox) {
mSelectedPositions.clear();
}
}
public void setForwardFragment(boolean forwardFragment) {
isForwardFragment = forwardFragment;
}
public void setSearchView(View searchView) {
this.searchView = searchView;
}
public void setShowFoldedStyle(boolean showFoldedStyle) {
this.showFoldedStyle = showFoldedStyle;
}
//设置给定位置条目的选择状态
public void setItemChecked(String conversationId, boolean isChecked) {
mSelectedPositions.put(conversationId, isChecked);
}
//根据位置判断条目是否选中
private boolean isItemChecked(String id) {
if (mSelectedPositions.size() <= 0) {
return false;
}
if (mSelectedPositions.containsKey(id)) {
return mSelectedPositions.get(id);
} else {
return false;
}
}
// 获得选中条目的结果
public List<ConversationInfo> getSelectedItem() {
if (mSelectedPositions.size() == 0) {
return null;
}
List<ConversationInfo> selectList = new ArrayList<>();
for (int i = 0; i < getItemCount() - 1; i++) {
ConversationInfo conversationInfo = getItem(i);
if (conversationInfo == null) {
continue;
}
if (isItemChecked(conversationInfo.getConversationId())) {
selectList.add(conversationInfo);
}
}
return selectList;
}
public void setSelectConversations(List<ConversationInfo> dataSource) {
if (dataSource == null || dataSource.size() == 0) {
mSelectedPositions.clear();
notifyDataSetChanged();
return;
}
mSelectedPositions.clear();
for (int i = 0; i < dataSource.size(); i++) {
for (int j = 0; j < mDataSource.size(); j++) {
if (TextUtils.equals(dataSource.get(i).getConversationId(), mDataSource.get(j).getConversationId())) {
setItemChecked(mDataSource.get(j).getConversationId(), true);
notifyDataSetChanged();
break;
}
}
}
}
public void setOnConversationAdapterListener(OnConversationAdapterListener listener) {
this.mOnConversationAdapterListener = listener;
}
@Override
public void onDataSourceChanged(List<ConversationInfo> dataSource) {
this.mDataSource = dataSource;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ConversationBaseHolder holder = null;
// 创建不同的 ViewHolder
View view;
// 根据ViewType来创建条目
if (viewType == ITEM_TYPE_HEADER_SEARCH) {
// 如果 searchView 不显示,添加一个隐藏的 view防止 recyclerview 自动滑到最底部
if (searchView == null) {
searchView = new View(parent.getContext());
}
return new HeaderViewHolder(searchView);
} else if (viewType == ConversationInfo.TYPE_CUSTOM) {
view = inflater.inflate(R.layout.conversation_custom_adapter, parent, false);
holder = new ConversationCustomHolder(view);
} else if (viewType == ITEM_TYPE_FOOTER_LOADING) {
view = inflater.inflate(R.layout.loading_progress_bar, parent, false);
return new FooterViewHolder(view);
} else if (viewType == ConversationInfo.TYPE_FORWAR_SELECT) {
view = inflater.inflate(R.layout.conversation_forward_select_adapter, parent, false);
return new ForwardSelectHolder(view);
} else if (viewType == ConversationInfo.TYPE_RECENT_LABEL) {
view = inflater.inflate(R.layout.conversation_forward_label_adapter, parent, false);
return new ForwardLabelHolder(view);
} else {
view = inflater.inflate(R.layout.conversation_list_item_layout, parent, false);
holder = new ConversationCommonHolder(view);
((ConversationCommonHolder) holder).setForwardMode(isForwardFragment);
((ConversationCommonHolder) holder).setShowFoldedStyle(showFoldedStyle);
}
holder.setAdapter(this);
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
final ConversationInfo conversationInfo = getItem(position);
ConversationBaseHolder baseHolder = null;
if (conversationInfo != null) {
baseHolder = (ConversationBaseHolder) holder;
}
switch (getItemViewType(position)) {
case ConversationInfo.TYPE_CUSTOM:
case ConversationInfo.TYPE_RECENT_LABEL:
break;
case ITEM_TYPE_FOOTER_LOADING: {
if (holder instanceof FooterViewHolder) {
((ConversationBaseHolder) holder).layoutViews(null, position);
}
break;
}
case ConversationInfo.TYPE_FORWAR_SELECT: {
ForwardSelectHolder selectHolder = (ForwardSelectHolder) holder;
selectHolder.refreshTitle(!isShowMultiSelectCheckBox);
setOnClickListener(holder, getItemViewType(position), conversationInfo);
break;
}
default:
setOnClickListener(holder, getItemViewType(position), conversationInfo);
}
if (baseHolder != null) {
baseHolder.layoutViews(conversationInfo, position);
setCheckBoxStatus(conversationInfo, position, baseHolder);
}
if (getCurrentPosition() == position && isClick()) {
// baseHolder.itemView.setBackgroundResource(R.color.conversation_item_clicked_color);
} else {
if (conversationInfo == null) {
return;
}
// if (conversationInfo.isTop() && !isForwardFragment) {
// baseHolder.itemView.setBackgroundColor(baseHolder.rootView.getResources().getColor(R.color.conversation_item_top_color));
// } else {
// baseHolder.itemView.setBackgroundColor(Color.WHITE);
// }
}
}
private void setOnClickListener(RecyclerView.ViewHolder holder, int viewType, ConversationInfo conversationInfo) {
if (holder instanceof HeaderViewHolder) {
return;
}
//设置点击和长按事件
if (mOnConversationAdapterListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnConversationAdapterListener.onItemClick(view, viewType, conversationInfo);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mOnConversationAdapterListener.OnItemLongClick(view, conversationInfo);
int position = getIndexInAdapter(conversationInfo);
if (position != -1) {
setCurrentPosition(position, true);
notifyItemChanged(position);
}
return true;
}
});
}
}
// 设置多选框的选中状态和点击事件
private void setCheckBoxStatus(final ConversationInfo conversationInfo, int position, ConversationBaseHolder baseHolder) {
if (!(baseHolder instanceof ConversationCommonHolder) || ((ConversationCommonHolder) baseHolder).multiSelectCheckBox == null) {
return;
}
int viewType = getItemViewType(position);
String conversationId = conversationInfo.getConversationId();
ConversationCommonHolder commonHolder = (ConversationCommonHolder) baseHolder;
if (!isShowMultiSelectCheckBox) {
commonHolder.multiSelectCheckBox.setVisibility(View.GONE);
} else {
commonHolder.multiSelectCheckBox.setVisibility(View.VISIBLE);
//设置条目状态
commonHolder.multiSelectCheckBox.setChecked(isItemChecked(conversationId));
//checkBox的监听
commonHolder.multiSelectCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setItemChecked(conversationId, !isItemChecked(conversationId));
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onItemClick(v, viewType, conversationInfo);
}
}
});
//条目view的监听
baseHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setItemChecked(conversationId, !isItemChecked(conversationId));
int currentPosition = getIndexInAdapter(conversationInfo);
if (currentPosition != -1) {
notifyItemChanged(currentPosition);
}
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onItemClick(v, viewType, conversationInfo);
}
}
});
((ConversationCommonHolder) baseHolder).conversationIconView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onUserIconClick(conversationInfo);
}
}
});
}
}
public int getIndexInAdapter(ConversationInfo conversationInfo) {
int position = -1;
if (mDataSource != null) {
int indexInData = mDataSource.indexOf(conversationInfo);
if (indexInData != -1) {
position = getItemIndexInAdapter(indexInData);
}
}
return position;
}
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
// ViewHolder 被回收时要清空头像 view 并且停止异步加载头像
if (holder instanceof ConversationCommonHolder) {
((ConversationCommonHolder) holder).conversationIconView.clearImage();
}
}
public ConversationInfo getItem(int position) {
if (mDataSource.isEmpty() || position == getItemCount() - 1) {
return null;
}
int dataPosition;
if (isForwardFragment) {
dataPosition = position - SELECT_COUNT - SELECT_LABEL_COUNT;
} else {
dataPosition = position - HEADER_COUNT;
}
if (dataPosition < mDataSource.size() && dataPosition >= 0) {
return mDataSource.get(dataPosition);
}
return null;
}
@Override
public int getItemCount() {
int listSize = mDataSource.size();
if (isForwardFragment) {
return listSize + SELECT_COUNT + SELECT_LABEL_COUNT + FOOTER_COUNT;
}
return listSize + HEADER_COUNT + FOOTER_COUNT;
}
@Override
public int getItemViewType(int position) {
if (isForwardFragment) {
if (position == 0) {
return ConversationInfo.TYPE_FORWAR_SELECT;
} else if (position == 1) {
return ConversationInfo.TYPE_RECENT_LABEL;
}
} else {
if (position == 0) {
return ITEM_TYPE_HEADER_SEARCH;
}
}
if (position == getItemCount() - 1) {
return ITEM_TYPE_FOOTER_LOADING;
} else if (mDataSource != null) {
ConversationInfo conversationInfo = getItem(position);
if (conversationInfo != null) {
return conversationInfo.getType();
}
}
return ConversationInfo.TYPE_COMMON;
}
private int getItemIndexInAdapter(int index) {
int itemIndex;
if (isForwardFragment) {
itemIndex = index + SELECT_LABEL_COUNT + SELECT_COUNT;
} else {
itemIndex = index + HEADER_COUNT;
}
return itemIndex;
}
@Override
public void onItemRemoved(int position) {
int itemIndex = getItemIndexInAdapter(position);
notifyItemRemoved(itemIndex);
}
@Override
public void onItemInserted(int position) {
int itemIndex = getItemIndexInAdapter(position);
notifyItemInserted(itemIndex);
}
@Override
public void onItemChanged(int position) {
int itemIndex = getItemIndexInAdapter(position);
notifyItemChanged(itemIndex);
}
@Override
public void onItemRangeChanged(int startPosition, int count) {
int itemStartIndex = getItemIndexInAdapter(startPosition);
notifyItemRangeChanged(itemStartIndex, count);
}
@Override
public void onConversationChanged(List<ConversationInfo> conversationInfoList) {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onConversationChanged(conversationInfoList);
}
}
public void setItemTopTextSize(int size) {
mTopTextSize = size;
}
public int getItemTopTextSize() {
return mTopTextSize;
}
public void setItemBottomTextSize(int size) {
mBottomTextSize = size;
}
public int getItemBottomTextSize() {
return mBottomTextSize;
}
public void setItemDateTextSize(int size) {
mDateTextSize = size;
}
public int getItemDateTextSize() {
return mDateTextSize;
}
public void setItemAvatarRadius(int radius) {
mItemAvatarRadius = radius;
}
public int getItemAvatarRadius() {
return mItemAvatarRadius;
}
public void disableItemUnreadDot(boolean flag) {
mHasShowUnreadDot = !flag;
}
public boolean hasItemUnreadDot() {
return mHasShowUnreadDot;
}
@Override
public void onLoadingStateChanged(boolean isLoading) {
this.mIsLoading = isLoading;
notifyItemChanged(getItemCount() - 1);
}
@Override
public void onViewNeedRefresh() {
notifyDataSetChanged();
}
//header
static class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(@NonNull View itemView) {
super(itemView);
}
}
//footer
class FooterViewHolder extends ConversationBaseHolder {
public FooterViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
public void layoutViews(ConversationInfo conversationInfo, int position) {
RecyclerView.LayoutParams param = (RecyclerView.LayoutParams) rootView.getLayoutParams();
if (mIsLoading) {
param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
param.width = LinearLayout.LayoutParams.MATCH_PARENT;
rootView.setVisibility(View.VISIBLE);
} else {
param.height = 0;
param.width = 0;
rootView.setVisibility(View.GONE);
}
rootView.setLayoutParams(param);
}
}
static class ForwardLabelHolder extends ConversationBaseHolder {
public ForwardLabelHolder(View itemView) {
super(itemView);
}
@Override
public void layoutViews(ConversationInfo conversationInfo, int position) {
}
}
static class ForwardSelectHolder extends ConversationBaseHolder {
private final TextView titleView;
public ForwardSelectHolder(View itemView) {
super(itemView);
titleView = itemView.findViewById(R.id.forward_title);
}
@Override
public void layoutViews(ConversationInfo conversationInfo, int position) {
}
public void refreshTitle(boolean isCreateGroup) {
if (titleView == null) return;
if (isCreateGroup) {
titleView.setText(TUIConversationService.getAppContext().getString(R.string.forward_select_new_chat));
} else {
titleView.setText(TUIConversationService.getAppContext().getString(R.string.forward_select_from_contact));
}
}
}
}

View File

@@ -0,0 +1,142 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import com.tencent.qcloud.tuicore.component.CustomLinearLayoutManager;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.IConversationListLayout;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
public class ConversationListLayout extends RecyclerView implements IConversationListLayout {
private ConversationListAdapter mAdapter;
private ConversationPresenter presenter;
private boolean isFolded = false;
public ConversationListLayout(Context context) {
super(context);
init();
}
public ConversationListLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ConversationListLayout(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setPresenter(ConversationPresenter presenter) {
this.presenter = presenter;
}
public void init() {
setLayoutFrozen(false);
setItemViewCacheSize(0);
setHasFixedSize(true);
setFocusableInTouchMode(false);
CustomLinearLayoutManager linearLayoutManager = new CustomLinearLayoutManager(getContext());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
setLayoutManager(linearLayoutManager);
SimpleItemAnimator animator = (SimpleItemAnimator) getItemAnimator();
if (animator != null) {
animator.setSupportsChangeAnimations(false);
}
}
@Override
public void setBackground(int resId) {
setBackgroundColor(resId);
}
@Override
public void disableItemUnreadDot(boolean flag) {
mAdapter.disableItemUnreadDot(flag);
}
@Override
public void setItemAvatarRadius(int radius) {
mAdapter.setItemAvatarRadius(radius);
}
@Override
public void setItemTopTextSize(int size) {
mAdapter.setItemTopTextSize(size);
}
@Override
public void setItemBottomTextSize(int size) {
mAdapter.setItemBottomTextSize(size);
}
@Override
public void setItemDateTextSize(int size) {
mAdapter.setItemDateTextSize(size);
}
@Override
public ConversationListLayout getListLayout() {
return this;
}
@Override
public ConversationListAdapter getAdapter() {
return mAdapter;
}
@Override
public void setAdapter(IConversationListAdapter adapter) {
if (adapter instanceof ConversationListAdapter) {
super.setAdapter((ConversationListAdapter) adapter);
mAdapter = (ConversationListAdapter) adapter;
}
}
@Override
public void setOnConversationAdapterListener(OnConversationAdapterListener listener){
mAdapter.setOnConversationAdapterListener(listener);
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if (state == RecyclerView.SCROLL_STATE_IDLE) {
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
if (layoutManager == null) {
return;
}
int lastPosition = layoutManager.findLastCompletelyVisibleItemPosition();
if (mAdapter != null) {
if (lastPosition == mAdapter.getItemCount() - 1 && !isLoadCompleted()) {
mAdapter.onLoadingStateChanged(true);
if (presenter != null) {
presenter.loadMoreConversation();
}
}
}
}
}
public void loadConversation(long nextSeq) {
if (presenter != null) {
presenter.loadConversation(nextSeq);
}
}
boolean isLoadCompleted(){
if (presenter != null) {
return presenter.isLoadFinished();
}
return false;
}
}

View File

@@ -0,0 +1,112 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.IConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationFoldPresenter;
public class FoldedConversationLayout extends RelativeLayout implements IConversationLayout {
private TitleBarLayout titleBarLayout;
private FoldedConversationListLayout conversationListLayout;
private ConversationFoldPresenter presenter;
public FoldedConversationLayout(Context context) {
super(context);
init();
}
public FoldedConversationLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FoldedConversationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setPresenter(ConversationFoldPresenter presenter) {
this.presenter = presenter;
if (conversationListLayout != null) {
conversationListLayout.setPresenter(presenter);
}
}
private void init() {
inflate(getContext(), R.layout.folded_layout, this);
titleBarLayout = findViewById(R.id.conversation_title);
conversationListLayout = findViewById(R.id.folded_conversation_list);
}
public void initDefault() {
final ConversationListAdapter adapter = new ConversationListAdapter();
conversationListLayout.setAdapter((IConversationListAdapter) adapter);
adapter.setShowFoldedStyle(false);
if (presenter != null) {
presenter.setAdapter(adapter);
}
conversationListLayout.loadConversation();
}
@Override
public FoldedConversationListLayout getConversationList() {
return conversationListLayout;
}
@Override
public void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack) {
}
@Override
public void deleteConversation(ConversationInfo conversation) {
if (presenter != null) {
presenter.deleteConversation(conversation);
}
}
@Override
public void clearConversationMessage(ConversationInfo conversation) {
}
@Override
public void markConversationHidden(ConversationInfo conversation) {
if (presenter != null) {
presenter.markConversationHidden(conversation, true);
}
}
@Override
public void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread) {
if (presenter != null) {
presenter.markConversationUnread(conversationInfo, markUnread);
}
}
@Override
public void hideFoldedItem(boolean needHide) {
}
@Override
public void clearUnreadStatusOfFoldItem() {
}
@Override
public TitleBarLayout getTitleBar() {
return titleBarLayout;
}
@Override
public void setParentLayout(Object parent) {
}
}

View File

@@ -0,0 +1,114 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import com.tencent.qcloud.tuicore.component.CustomLinearLayoutManager;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.IConversationListLayout;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationFoldPresenter;
public class FoldedConversationListLayout extends RecyclerView implements IConversationListLayout {
private ConversationListAdapter mAdapter;
private ConversationFoldPresenter presenter;
private boolean isFolded = false;
public FoldedConversationListLayout(Context context) {
super(context);
init();
}
public FoldedConversationListLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public FoldedConversationListLayout(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setPresenter(ConversationFoldPresenter presenter) {
this.presenter = presenter;
}
public void init() {
setLayoutFrozen(false);
setItemViewCacheSize(0);
setHasFixedSize(true);
setFocusableInTouchMode(false);
CustomLinearLayoutManager linearLayoutManager = new CustomLinearLayoutManager(getContext());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
setLayoutManager(linearLayoutManager);
SimpleItemAnimator animator = (SimpleItemAnimator) getItemAnimator();
if (animator != null) {
animator.setSupportsChangeAnimations(false);
}
}
@Override
public void setBackground(int resId) {
setBackgroundColor(resId);
}
@Override
public void disableItemUnreadDot(boolean flag) {
mAdapter.disableItemUnreadDot(flag);
}
@Override
public void setItemAvatarRadius(int radius) {
mAdapter.setItemAvatarRadius(radius);
}
@Override
public void setItemTopTextSize(int size) {
mAdapter.setItemTopTextSize(size);
}
@Override
public void setItemBottomTextSize(int size) {
mAdapter.setItemBottomTextSize(size);
}
@Override
public void setItemDateTextSize(int size) {
mAdapter.setItemDateTextSize(size);
}
@Override
public FoldedConversationListLayout getListLayout() {
return this;
}
@Override
public ConversationListAdapter getAdapter() {
return mAdapter;
}
@Override
public void setAdapter(IConversationListAdapter adapter) {
if (adapter instanceof ConversationListAdapter) {
super.setAdapter((ConversationListAdapter) adapter);
mAdapter = (ConversationListAdapter) adapter;
}
}
@Override
public void setOnConversationAdapterListener(OnConversationAdapterListener listener) {
mAdapter.setOnConversationAdapterListener(listener);
}
public void loadConversation() {
if (presenter != null) {
presenter.loadConversation();
}
}
}

View File

@@ -0,0 +1,85 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.util.List;
public class ForwardConversationSelectorAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private Context context;
private List<ConversationInfo> list;
private OnItemClickListener mOnItemClickListener;
public ForwardConversationSelectorAdapter(Context context) {
this.context = context;
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
@NonNull
@Override
public ConversationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ConversationViewHolder(LayoutInflater.from(context).inflate(R.layout.forward_conversation_selector_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
ConversationViewHolder viewHolder = (ConversationViewHolder) holder;
viewHolder.conversationUserIconView.setVisibility(View.VISIBLE);
viewHolder.conversationUserIconView.setConversation(list.get(position));
viewHolder.conversationUserIconView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onClick(v, position);
}
});
}
public void setDataSource(List<ConversationInfo> dataSource) {
if (dataSource == null) {
if (list != null) {
list.clear();
}
} else {
list = dataSource;
}
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mOnItemClickListener = listener;
}
public interface OnItemClickListener {
void onClick(View view, int position);
}
static class ConversationViewHolder extends RecyclerView.ViewHolder {
public ConversationIconView conversationUserIconView;
public ConversationViewHolder(View itemView) {
super(itemView);
conversationUserIconView = itemView.findViewById(R.id.conversation_user_icon_view);
}
}
}

View File

@@ -0,0 +1,106 @@
package com.tencent.qcloud.tuikit.tuiconversation.classicui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.classicui.interfaces.IConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
public class ForwardSelectLayout extends RelativeLayout implements IConversationLayout {
private TitleBarLayout titleBarLayout;
private ConversationListLayout conversationList;
private ConversationPresenter presenter;
public ForwardSelectLayout(Context context) {
super(context);
init();
}
public ForwardSelectLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ForwardSelectLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setPresenter(ConversationPresenter presenter) {
this.presenter = presenter;
if (conversationList != null) {
conversationList.setPresenter(presenter);
}
}
/**
* 初始化相关UI元素
*/
private void init() {
inflate(getContext(), R.layout.forward_layout, this);
titleBarLayout = findViewById(R.id.conversation_title);
conversationList = findViewById(R.id.conversation_list);
}
public void initDefault() {
final ConversationListAdapter adapter = new ConversationListAdapter();
adapter.setForwardFragment(true);
conversationList.setAdapter((IConversationListAdapter) adapter);
presenter.setAdapter(adapter);
presenter.loadConversation(0);
}
public TitleBarLayout getTitleBar() {
return titleBarLayout;
}
@Override
public void setParentLayout(Object parent) {
}
@Override
public ConversationListLayout getConversationList() {
return conversationList;
}
@Override
public void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack) {
}
@Override
public void deleteConversation(ConversationInfo conversation) {
}
@Override
public void clearConversationMessage(ConversationInfo conversation) {
}
@Override
public void markConversationHidden(ConversationInfo conversation) {
}
@Override
public void hideFoldedItem(boolean needHide) {
}
@Override
public void clearUnreadStatusOfFoldItem() {
}
@Override
public void markConversationUnread(ConversationInfo conversationInfo, boolean markRead) {
}
}

View File

@@ -0,0 +1,207 @@
package com.tencent.qcloud.tuikit.tuiconversation.commonutil;
import android.text.TextUtils;
import android.view.View;
import android.widget.ListView;
import com.tencent.imsdk.v2.V2TIMConversation;
import com.tencent.imsdk.v2.V2TIMGroupAtInfo;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.qcloud.tuicore.TUIConfig;
import com.tencent.qcloud.tuicore.component.action.PopDialogAdapter;
import com.tencent.qcloud.tuicore.util.DateTimeUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationService;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.bean.DraftInfo;
import java.util.ArrayList;
import java.util.List;
public class ConversationUtils {
private static final String TAG = ConversationUtils.class.getSimpleName();
public static List<ConversationInfo> convertV2TIMConversationList(List<V2TIMConversation> conversationList) {
List<ConversationInfo> conversationInfoList = new ArrayList<>();
if (conversationList != null) {
for(V2TIMConversation conversation : conversationList) {
conversationInfoList.add(convertV2TIMConversation(conversation));
}
}
return conversationInfoList;
}
public static ConversationInfo convertV2TIMConversation(final V2TIMConversation conversation) {
if (conversation == null) {
return null;
}
TUIConversationLog.i(TAG, "TIMConversation2ConversationInfo id:" + conversation.getConversationID()
+ "|name:" + conversation.getShowName()
+ "|unreadNum:" + conversation.getUnreadCount());
final ConversationInfo info = new ConversationInfo();
info.setConversation(conversation);
int type = conversation.getType();
if (type != V2TIMConversation.V2TIM_C2C && type != V2TIMConversation.V2TIM_GROUP) {
return null;
}
boolean isGroup = type == V2TIMConversation.V2TIM_GROUP;
String draftText = conversation.getDraftText();
if (!TextUtils.isEmpty(draftText)) {
DraftInfo draftInfo = new DraftInfo();
draftInfo.setDraftText(draftText);
draftInfo.setDraftTime(conversation.getDraftTimestamp());
info.setDraft(draftInfo);
}
V2TIMMessage message = conversation.getLastMessage();
if (message == null) {
long time = DateTimeUtil.getStringToDate("0001-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss");
info.setLastMessageTime(time);
} else {
info.setLastMessageTime(message.getTimestamp());
info.setLastMessage(message);
}
int atInfoType = getAtInfoType(conversation);
switch (atInfoType){
case V2TIMGroupAtInfo.TIM_AT_ME:
info.setAtInfoText(TUIConversationService.getAppContext().getString(R.string.ui_at_me));
break;
case V2TIMGroupAtInfo.TIM_AT_ALL:
info.setAtInfoText(TUIConversationService.getAppContext().getString(R.string.ui_at_all));
break;
case V2TIMGroupAtInfo.TIM_AT_ALL_AT_ME:
info.setAtInfoText(TUIConversationService.getAppContext().getString(R.string.ui_at_all_me));
break;
default:
info.setAtInfoText("");
break;
}
info.setTitle(conversation.getShowName());
List<Object> faceList = new ArrayList<>();
if (isGroup) {
if (!TextUtils.isEmpty(conversation.getFaceUrl())) {
faceList.add(conversation.getFaceUrl());
}
} else {
if (TextUtils.isEmpty(conversation.getFaceUrl())) {
faceList.add(TUIConfig.getDefaultAvatarImage());
} else {
faceList.add(conversation.getFaceUrl());
}
}
info.setIconPath(conversation.getFaceUrl());
info.setIconUrlList(faceList);
if (isGroup) {
info.setId(conversation.getGroupID());
info.setGroupType(conversation.getGroupType());
} else {
info.setId(conversation.getUserID());
}
if (V2TIMManager.GROUP_TYPE_MEETING.equals(conversation.getGroupType())) {
info.setShowDisturbIcon(false);
} else {
info.setShowDisturbIcon(conversation.getRecvOpt() == V2TIMMessage.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE);
}
info.setConversationId(conversation.getConversationID());
info.setGroup(isGroup);
if (!V2TIMManager.GROUP_TYPE_AVCHATROOM.equals(conversation.getGroupType())) {
info.setUnRead(conversation.getUnreadCount());
}
info.setTop(conversation.isPinned());
info.setOrderKey(conversation.getOrderKey());
if (conversation.getMarkList() != null) {
if (conversation.getMarkList().contains(V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_FOLD)) {
info.setMarkFold(true);
} else {
info.setMarkFold(false);
}
if (conversation.getMarkList().contains(V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_UNREAD)) {
info.setMarkUnread(true);
} else {
info.setMarkUnread(false);
}
if (conversation.getMarkList().contains(V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_HIDE)) {
info.setMarkHidden(true);
} else {
info.setMarkHidden(false);
}
}
return info;
}
private static int getAtInfoType(V2TIMConversation conversation){
int atInfoType = 0;
boolean atMe = false;
boolean atAll = false;
List<V2TIMGroupAtInfo> atInfoList = conversation.getGroupAtInfoList();
if (atInfoList == null || atInfoList.isEmpty()){
return V2TIMGroupAtInfo.TIM_AT_UNKNOWN;
}
for(V2TIMGroupAtInfo atInfo : atInfoList){
if (atInfo.getAtType() == V2TIMGroupAtInfo.TIM_AT_ME){
atMe = true;
continue;
}
if (atInfo.getAtType() == V2TIMGroupAtInfo.TIM_AT_ALL){
atAll = true;
continue;
}
if (atInfo.getAtType() == V2TIMGroupAtInfo.TIM_AT_ALL_AT_ME){
atMe = true;
atAll = true;
continue;
}
}
if (atAll && atMe){
atInfoType = V2TIMGroupAtInfo.TIM_AT_ALL_AT_ME;
} else if (atAll){
atInfoType = V2TIMGroupAtInfo.TIM_AT_ALL;
} else if (atMe){
atInfoType = V2TIMGroupAtInfo.TIM_AT_ME;
} else {
atInfoType = V2TIMGroupAtInfo.TIM_AT_UNKNOWN;
}
return atInfoType;
}
public static boolean isIgnored(ConversationInfo conversationInfo) {
if (V2TIMManager.GROUP_TYPE_AVCHATROOM.equals(conversationInfo.getGroupType())) {
return true;
}
return false;
}
public static int getListUnspecifiedWidth(PopDialogAdapter adapter, ListView listView) {
if (adapter == null || listView == null) {
return 0;
}
int maxWidth = 0;
View convertView = null;
int childCount = adapter.getCount();
if (childCount <= 0) {
return 0;
}
for (int i = 0; i < childCount; i++) {
View child = adapter.getView(i, convertView, listView);
child.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + child.getPaddingLeft() + child.getPaddingRight());
convertView = child;
}
return maxWidth;
}
}

View File

@@ -0,0 +1,37 @@
package com.tencent.qcloud.tuikit.tuiconversation.commonutil;
import com.tencent.imsdk.common.IMLog;
public class TUIConversationLog extends IMLog {
private static final String PRE = "TUIKit-";
private static String mixTag(String tag) {
return PRE + tag;
}
public static void v(String strTag, String strInfo) {
IMLog.v(mixTag(strTag), strInfo);
}
public static void d(String strTag, String strInfo) {
IMLog.d(mixTag(strTag), strInfo);
}
public static void i(String strTag, String strInfo) {
IMLog.i(mixTag(strTag), strInfo);
}
public static void w(String strTag, String strInfo) {
IMLog.w(mixTag(strTag), strInfo);
}
public static void w(String strTag, String strInfo, Throwable e) {
IMLog.w(mixTag(strTag), strInfo + e.getMessage());
}
public static void e(String strTag, String strInfo) {
IMLog.e(mixTag(strTag), strInfo);
}
}

View File

@@ -0,0 +1,25 @@
package com.tencent.qcloud.tuikit.tuiconversation.commonutil;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter;
public class TUIConversationUtils {
public static <T> void callbackOnError(IUIKitCallback<T> callBack, String module, int errCode, String desc) {
if (callBack != null) {
callBack.onError(module, errCode, ErrorMessageConverter.convertIMError(errCode, desc));
}
}
public static <T> void callbackOnError(IUIKitCallback<T> callBack, int errCode, String desc) {
if (callBack != null) {
callBack.onError(null, errCode, ErrorMessageConverter.convertIMError(errCode, desc));
}
}
public static <T> void callbackOnSuccess(IUIKitCallback<T> callBack, T data) {
if (callBack != null) {
callBack.onSuccess(data);
}
}
}

View File

@@ -0,0 +1,23 @@
package com.tencent.qcloud.tuikit.tuiconversation.config;
public class TUIConversationConfig {
public static final String TAG = TUIConversationConfig.class.getSimpleName();
private static TUIConversationConfig instance;
private boolean isShowUserStatus;
public static TUIConversationConfig getInstance() {
if (instance == null) {
instance = new TUIConversationConfig();
}
return instance;
}
public boolean isShowUserStatus() {
return isShowUserStatus;
}
public void setShowUserStatus(boolean showUserStatus) {
isShowUserStatus = showUserStatus;
}
}

View File

@@ -0,0 +1,25 @@
package com.tencent.qcloud.tuikit.tuiconversation.interfaces;
import com.tencent.imsdk.v2.V2TIMUserStatus;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.util.List;
public interface ConversationEventListener {
void deleteConversation(String chatId, boolean isGroup);
void clearConversationMessage(String chatId, boolean isGroup);
void clearFoldMarkAndDeleteConversation(String conversationId);
void setConversationTop(String chatId, boolean isChecked, IUIKitCallback<Void> iuiKitCallBack);
boolean isTopConversation(String chatId);
long getUnreadTotal();
void onSyncServerFinish();
void updateTotalUnreadMessageCount(long count);
void onNewConversation(List<ConversationInfo> conversationList);
void onConversationChanged(List<ConversationInfo> conversationList);
void onFriendRemarkChanged(String id, String remark);
void onUserStatusChanged(List<V2TIMUserStatus> userStatusList);
void refreshUserStatusFragmentUI();
void onReceiveMessage(String conversationID, boolean isTypingMessage);
void onMessageSendForHideConversation(String conversationID);
}

View File

@@ -0,0 +1,33 @@
package com.tencent.qcloud.tuikit.tuiconversation.interfaces;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.util.List;
public interface IConversationListAdapter {
/**
* 获取适配器的条目数据返回的是ConversationInfo对象或其子对象
*
* Get the entry data of the adapter, which returns the ConversationInfo object or its sub-objects
*
* @param position
* @return ConversationInfo
*/
ConversationInfo getItem(int position);
void onLoadingStateChanged(boolean isLoading);
void onDataSourceChanged(List<ConversationInfo> conversationInfoList);
void onViewNeedRefresh();
void onItemRemoved(int position);
void onItemInserted(int position);
void onItemChanged(int position);
void onItemRangeChanged(int startPosition, int count);
void onConversationChanged(List<ConversationInfo> conversationInfoList);
}

View File

@@ -0,0 +1,38 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces;
import android.view.View;
import com.tencent.qcloud.tuicore.component.interfaces.ILayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
public interface IConversationLayout extends ILayout {
View getConversationList();
void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack);
void deleteConversation(ConversationInfo conversation);
void clearConversationMessage(ConversationInfo conversation);
/**
* 隐藏普通会话
* Hide normal conversation
*/
void markConversationHidden(ConversationInfo conversation);
/**
* 标记会话已读/未读
* Mark conversation read or unread
*/
void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread);
/**
* 隐藏整个折叠的会话 item
* Hide folded conversation item
*/
void hideFoldedItem(boolean needHide);
/**
* 清除折叠 item 本地未读状态
* Clear unread status of fold item
*/
void clearUnreadStatusOfFoldItem();
}

View File

@@ -0,0 +1,63 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces;
import android.view.View;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationListAdapter;
public interface IConversationListLayout {
void setBackground(int resId);
void setOnConversationAdapterListener(OnConversationAdapterListener listener);
/**
* 不显示小红点未读消息条数开关
*
* Do not display the switch for the number of unread messages with the small red dot
*
* @param flag 默认false表示显示
*/
void disableItemUnreadDot(boolean flag);
/**
* 设置会话Item头像圆角
*
* Set session item avatar rounded corners
*
* @param radius
*/
void setItemAvatarRadius(int radius);
/**
* 设置会话Item顶部字体大小
*
* Set the font size at the top of the session item
*
* @param size
*/
void setItemTopTextSize(int size);
/**
* 设置会话Item底部字体大小
*
* Set the font size at the bottom of the session item
*
* @param size
*/
void setItemBottomTextSize(int size);
/**
* 设置会话Item日期字体大小
*
* Set the session item date font size
*
* @param size
*/
void setItemDateTextSize(int size);
View getListLayout();
ConversationListAdapter getAdapter();
void setAdapter(IConversationListAdapter adapter);
}

View File

@@ -0,0 +1,62 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import java.util.List;
public interface IConversationProvider {
/**
* 获取具体的会话数据集合ConversationContainer依据该数据集合展示会话列表
*
* Get a specific session data set, and ConversationContainer displays the session list based on the data set
*
* @return
*/
List<ConversationInfo> getDataSource();
/**
* 批量添加会话条目
*
* Bulk add session entries
*
* @param conversations 会话数据集合
* @return
*/
boolean addConversations(List<ConversationInfo> conversations);
/**
* 删除会话条目
*
* Delete session entries
*
* @param conversations 会话数据集合
* @return
*/
boolean deleteConversations(List<ConversationInfo> conversations);
/**
* 更新会话条目
*
* Update session entries
*
* @param conversations 会话数据集合
* @return
*/
boolean updateConversations(List<ConversationInfo> conversations);
/**
* 绑定会话适配器时触发的调用,在调用{@link com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter#setDataProvider}时自动调用
*
* Called when a session adapter is bound, automatically called when {@link com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter#setDataProvider} is called
*
* @param adapter 会话UI显示适配器
* @return
*/
void attachAdapter(IConversationListAdapter adapter);
}

View File

@@ -0,0 +1,17 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces;
import android.view.View;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.util.List;
public interface OnConversationAdapterListener {
void onItemClick(View view, int viewType, ConversationInfo conversationInfo);
void OnItemLongClick(View view, ConversationInfo conversationInfo);
void onConversationChanged(List<ConversationInfo> dataSource);
void onMarkConversationUnread(View view, ConversationInfo conversationInfo, boolean markUnread);
void onMarkConversationHidden(View view, ConversationInfo conversationInfo);
void onClickMoreView(View view, ConversationInfo conversationInfo);
void onSwipeConversationChanged(ConversationInfo conversationInfo);
}

View File

@@ -0,0 +1,642 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.page;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.component.action.PopActionClickListener;
import com.tencent.qcloud.tuicore.component.action.PopDialogAdapter;
import com.tencent.qcloud.tuicore.component.action.PopMenuAction;
import com.tencent.qcloud.tuicore.component.fragments.BaseFragment;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationConstants;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.ConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.util.TUIConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.Menu;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
import java.util.ArrayList;
import java.util.List;
public class ConversationMinimalistFragment extends BaseFragment {
private View mBaseView;
private ConversationLayout mConversationLayout;
private ListView mConversationPopList;
private PopDialogAdapter mConversationPopAdapter;
private PopupWindow mConversationPopWindow;
private String popWindowConversationId;
private List<PopMenuAction> mConversationPopActions = new ArrayList<>();
private AlertDialog mBottomDialog;
private boolean isShowReadButton, isShowReadAllButton;
private BroadcastReceiver unreadCountReceiver;
private Menu menu;
private ConversationPresenter presenter;
private ConversationListAdapter mAdapter;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
mBaseView = inflater.inflate(R.layout.minimalistui_conversation_fragment, container, false);
initView();
return mBaseView;
}
private void initView() {
// 从布局文件中获取会话列表面板
mConversationLayout = mBaseView.findViewById(R.id.conversation_layout);
presenter = new ConversationPresenter();
presenter.setConversationListener();
presenter.setShowType(ConversationPresenter.SHOW_TYPE_CONVERSATION_LIST_WITH_FOLD);
mConversationLayout.setPresenter(presenter);
// 会话列表面板的默认UI和交互初始化
mConversationLayout.initDefault();
// 通过API设置ConversataonLayout各种属性的样例开发者可以打开注释体验效果
// ConversationLayoutSetting.customizeConversation(mConversationLayout);
isShowReadButton = false;
isShowReadAllButton = false;
mAdapter = mConversationLayout.getConversationList().getAdapter();
mConversationLayout.getConversationList().setOnConversationAdapterListener(new OnConversationAdapterListener() {
@Override
public void onItemClick(View view, int viewType, ConversationInfo conversationInfo) {
if (mConversationLayout.isMultiSelected()) {
if (mAdapter == null) {
refreshEditConversationDialog(0);
return;
}
List<ConversationInfo> mSelectConversations = mAdapter.getSelectedItem();
if (mSelectConversations == null) {
refreshEditConversationDialog(0);
return;
}
isShowReadButton = false;
for(ConversationInfo conversation : mSelectConversations) {
if (conversation.isMarkUnread() || conversation.getUnRead() > 0) {
isShowReadButton = true;
break;
}
}
refreshEditConversationDialog(mSelectConversations.size());
} else if (conversationInfo.isMarkFold()) {
mConversationLayout.clearUnreadStatusOfFoldItem();
startFoldedConversationActivity();
} else {
TUIConversationUtils.startChatActivity(conversationInfo);
}
}
@Override
public void OnItemLongClick(View view, ConversationInfo conversationInfo) {
showItemPopMenu(view, conversationInfo);
}
@Override
public void onConversationChanged(List<ConversationInfo> dataSource) {
if (dataSource == null)return;
ConversationInfo conversationInfo = dataSource.get(0);
if (conversationInfo == null)return;
if (!TextUtils.isEmpty(popWindowConversationId) && popWindowConversationId.equals(conversationInfo.getConversationId())) {
if (mConversationPopWindow != null) {
mConversationPopWindow.dismiss();
}
if (mAdapter != null) {
mAdapter.closeAllSwipeItems();
}
}
}
@Override
public void onMarkConversationUnread(View view, ConversationInfo conversationInfo, boolean markUnread) {
mConversationLayout.markConversationUnread(conversationInfo, markUnread);
}
@Override
public void onMarkConversationHidden(View view, ConversationInfo conversationInfo) {
mConversationLayout.markConversationHidden(conversationInfo);
}
@Override
public void onClickMoreView(View view, ConversationInfo conversationInfo) {
showConversationMoreActionDialog(conversationInfo);
}
@Override
public void onSwipeConversationChanged(ConversationInfo conversationInfo) {
if (conversationInfo == null) {
popWindowConversationId = "";
return;
}
popWindowConversationId = conversationInfo.getConversationId();
}
});
mConversationLayout.setOnClickListener(new OnClickListener() {
@Override
public void onEditConversationStartClick() {
showEditConversationDialog();
}
@Override
public void onEditConversationEndClick() {
closeEditConversationDialog();
}
@Override
public void onStartChatClick() {
if (menu == null) {
return;
}
if (menu.isShowing()) {
menu.hide();
} else {
menu.show();
}
}
});
initUnreadCountReceiver();
restoreConversationItemBackground();
setConversationMenu();
}
public void restoreConversationItemBackground() {
if (mConversationLayout.getConversationList().getAdapter() != null &&
mConversationLayout.getConversationList().getAdapter().isClick()) {
mConversationLayout.getConversationList().getAdapter().setClick(false);
mConversationLayout.getConversationList().getAdapter().notifyItemChanged(mConversationLayout.getConversationList().getAdapter().getCurrentPosition());
}
}
private void initUnreadCountReceiver() {
unreadCountReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
long unreadCount = intent.getLongExtra(TUIConstants.UNREAD_COUNT_EXTRA, 0);
if (unreadCount > 0) {
isShowReadAllButton = true;
} else {
isShowReadAllButton = false;
}
}
};
IntentFilter unreadCountFilter = new IntentFilter();
unreadCountFilter.addAction(TUIConstants.CONVERSATION_UNREAD_COUNT_ACTION);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(unreadCountReceiver, unreadCountFilter);
}
private void initPopMenuAction() {
// 设置长按conversation显示PopAction
List<PopMenuAction> conversationPopActions = new ArrayList<PopMenuAction>();
PopMenuAction action = new PopMenuAction();
action.setActionName(getResources().getString(R.string.not_display));
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
ConversationInfo conversationInfo = (ConversationInfo) data;
if (conversationInfo.isMarkFold()) {
mConversationLayout.hideFoldedItem(true);
} else {
mConversationLayout.markConversationHidden(conversationInfo);
}
}
});
conversationPopActions.add(action);
mConversationPopActions.clear();
mConversationPopActions.addAll(conversationPopActions);
}
private void addMarkUnreadPopMenuAction(boolean markUnread) {
PopMenuAction action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mConversationLayout.markConversationUnread((ConversationInfo) data, markUnread);
}
});
if (markUnread) {
action.setActionName(getResources().getString(R.string.mark_unread));
} else {
action.setActionName(getResources().getString(R.string.mark_read));
}
mConversationPopActions.add(0, action);
}
private void addDeletePopMenuAction() {
PopMenuAction action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mConversationLayout.deleteConversation((ConversationInfo) data);
}
});
action.setActionName(getResources().getString(R.string.chat_delete));
mConversationPopActions.add(action);
}
/**
* 长按会话item弹框
* @param view 长按 view
* @param conversationInfo 会话数据对象
*/
private void showItemPopMenu(View view, final ConversationInfo conversationInfo) {
initPopMenuAction();
if (!conversationInfo.isMarkFold()) {
if (conversationInfo.getUnRead() > 0) {
addMarkUnreadPopMenuAction(false);
} else {
if (conversationInfo.isMarkUnread()) {
addMarkUnreadPopMenuAction(false);
} else {
addMarkUnreadPopMenuAction(true);
}
}
addDeletePopMenuAction();
}
View itemPop = LayoutInflater.from(getActivity()).inflate(R.layout.conversation_pop_menu_layout, null);
mConversationPopList = itemPop.findViewById(R.id.pop_menu_list);
mConversationPopList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PopMenuAction action = mConversationPopActions.get(position);
if (action.getActionClickListener() != null) {
action.getActionClickListener().onActionClick(position, conversationInfo);
}
mConversationPopWindow.dismiss();
restoreConversationItemBackground();
}
});
for (int i = 0; i < mConversationPopActions.size(); i++) {
PopMenuAction action = mConversationPopActions.get(i);
if (conversationInfo.isTop()) {
if (action.getActionName().equals(getResources().getString(R.string.chat_top))) {
action.setActionName(getResources().getString(R.string.quit_chat_top));
}
} else {
if (action.getActionName().equals(getResources().getString(R.string.quit_chat_top))) {
action.setActionName(getResources().getString(R.string.chat_top));
}
}
}
mConversationPopAdapter = new PopDialogAdapter();
mConversationPopList.setAdapter(mConversationPopAdapter);
mConversationPopAdapter.setDataSource(mConversationPopActions);
mConversationPopWindow = new PopupWindow(itemPop, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
mConversationPopWindow.setBackgroundDrawable(new ColorDrawable());
mConversationPopWindow.setOutsideTouchable(true);
popWindowConversationId = conversationInfo.getConversationId();
int width = ConversationUtils.getListUnspecifiedWidth(mConversationPopAdapter, mConversationPopList);
mConversationPopWindow.setWidth(width);
mConversationPopWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
restoreConversationItemBackground();
popWindowConversationId = "";
}
});
int x = view.getWidth() / 2;
int y = - view.getHeight() / 3;
int popHeight = ScreenUtil.dip2px(45) * 3;
if (y + popHeight + view.getY() + view.getHeight() > mConversationLayout.getBottom()) {
y = y - popHeight;
}
mConversationPopWindow.showAsDropDown(view, x, y, Gravity.TOP | Gravity.START);
}
private void startFoldedConversationActivity() {
Intent intent = new Intent(getActivity(), TUIFoldedConversationMinimalistActivity.class);
startActivity(intent);
}
public interface OnClickListener {
void onEditConversationStartClick();
void onEditConversationEndClick();
void onStartChatClick();
}
private void showEditConversationDialog(){
if (mBottomDialog != null && mBottomDialog.isShowing()) {
return;
}
View view = LayoutInflater.from(getContext()).inflate(R.layout.minimalist_bottom_bar,null,false);
mBottomDialog = new AlertDialog.Builder(getContext()).setView(view).create();
TextView markReadView = view.findViewById(R.id.mark_read);
TextView notDisplayView = view.findViewById(R.id.not_display);
TextView deleteChatView = view.findViewById(R.id.delete_chat);
if (isShowReadAllButton) {
markReadView.setAlpha(1f);
markReadView.setEnabled(true);
markReadView.setText(getString(R.string.has_all_read));
} else {
markReadView.setAlpha(0.5f);
markReadView.setEnabled(false);
markReadView.setText(getString(R.string.mark_read));
}
notDisplayView.setAlpha(0.5f);
notDisplayView.setEnabled(false);
deleteChatView.setAlpha(0.5f);
deleteChatView.setEnabled(false);
markReadView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (markReadView.getText().equals(getString(R.string.has_all_read))) {
presenter.clearAllUnreadMessage();
} else {
if (mAdapter == null) {
resetEditConversationStatus();
return;
}
List<ConversationInfo> mSelectConversations = mAdapter.getSelectedItem();
for (ConversationInfo conversationInfo : mSelectConversations) {
mConversationLayout.markConversationUnread(conversationInfo, false);
}
}
resetEditConversationStatus();
}
});
notDisplayView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mAdapter == null) {
resetEditConversationStatus();
return;
}
List<ConversationInfo> mSelectConversations = mAdapter.getSelectedItem();
for(ConversationInfo conversationInfo : mSelectConversations) {
mConversationLayout.markConversationHidden(conversationInfo);
}
resetEditConversationStatus();
}
});
deleteChatView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mAdapter == null) {
resetEditConversationStatus();
return;
}
List<ConversationInfo> mSelectConversations = mAdapter.getSelectedItem();
for(ConversationInfo conversationInfo : mSelectConversations) {
mConversationLayout.deleteConversation(conversationInfo);
}
resetEditConversationStatus();
}
});
mBottomDialog.setCanceledOnTouchOutside(false);
mBottomDialog.show();
Window win = mBottomDialog.getWindow();
win.setGravity(Gravity.BOTTOM); // 这里控制弹出的位置
win.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams lp = win.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
mBottomDialog.getWindow().setBackgroundDrawableResource(R.color.conversation_bottom_bg);
win.setAttributes(lp);
win.setDimAmount(0f);
win.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
win.setFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
mBottomDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
resetEditConversationStatus();
}
return false;
}
});
}
private void refreshEditConversationDialog(int selectSize) {
if (mBottomDialog == null) {
return;
}
TextView markReadView = mBottomDialog.findViewById(R.id.mark_read);
TextView notDisplayView = mBottomDialog.findViewById(R.id.not_display);
TextView deleteChatView = mBottomDialog.findViewById(R.id.delete_chat);
if (selectSize <= 0) {
deleteChatView.setAlpha(0.5f);
deleteChatView.setEnabled(false);
notDisplayView.setAlpha(0.5f);
notDisplayView.setEnabled(false);
markReadView.setAlpha(1f);
markReadView.setEnabled(true);
markReadView.setText(getString(R.string.has_all_read));
} else {
deleteChatView.setAlpha(1f);
deleteChatView.setEnabled(true);
notDisplayView.setAlpha(1f);
notDisplayView.setEnabled(true);
markReadView.setText(getString(R.string.mark_read));
if (isShowReadButton) {
markReadView.setAlpha(1f);
markReadView.setEnabled(true);
} else {
markReadView.setAlpha(0.5f);
markReadView.setEnabled(false);
}
}
}
private void resetEditConversationStatus() {
isShowReadAllButton = false;
isShowReadButton = false;
if (mBottomDialog != null) {
mBottomDialog.dismiss();
}
mConversationLayout.resetTitileBar();
}
private void closeEditConversationDialog() {
if (mBottomDialog != null) {
mBottomDialog.dismiss();
}
}
private void setConversationMenu() {
menu = new Menu(getActivity(), mConversationLayout.getCreateChatView());
PopActionClickListener popActionClickListener = new PopActionClickListener() {
@Override
public void onActionClick(int position, Object data) {
PopMenuAction action = (PopMenuAction) data;
if (TextUtils.equals(action.getActionName(), getResources().getString(R.string.start_conversation))) {
TUICore.startActivity("StartC2CChatMinimalistActivity", null);
}
if (TextUtils.equals(action.getActionName(), getResources().getString(R.string.create_group_chat))) {
Bundle bundle = new Bundle();
bundle.putInt(TUIConversationConstants.GroupType.TYPE, TUIConversationConstants.GroupType.PUBLIC);
TUICore.startActivity("StartGroupChatMinimalistActivity", bundle);
}
menu.hide();
}
};
List<PopMenuAction> menuActions = new ArrayList<>();
PopMenuAction action = new PopMenuAction();
action.setActionName(getResources().getString(R.string.start_conversation));
action.setActionClickListener(popActionClickListener);
action.setIconResId(R.drawable.create_c2c);
menuActions.add(action);
action = new PopMenuAction();
action.setActionName(getResources().getString(R.string.create_group_chat));
action.setIconResId(R.drawable.group_icon);
action.setActionClickListener(popActionClickListener);
menuActions.add(action);
menu.setMenuAction(menuActions);
}
private void showConversationMoreActionDialog(ConversationInfo conversationInfo){
View view = LayoutInflater.from(getContext()).inflate(R.layout.minimalist_more_dialog,null,false);
AlertDialog moreDialog = new AlertDialog.Builder(getContext()).setView(view).create();
TextView setTopView = view.findViewById(R.id.top_set);
TextView notDisplayView = view.findViewById(R.id.not_display);
TextView clearChatView = view.findViewById(R.id.clear_chat);
TextView deleteChatView = view.findViewById(R.id.delete_chat);
TextView cancelView = view.findViewById(R.id.cancel_button);
if (conversationInfo.isTop()) {
setTopView.setText(getString(R.string.quit_chat_top));
} else {
setTopView.setText(getString(R.string.chat_top));
}
setTopView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mConversationLayout.setConversationTop(conversationInfo, new IUIKitCallback() {
@Override
public void onSuccess(Object data) {
super.onSuccess(data);
}
@Override
public void onError(String module, int errCode, String errMsg) {
super.onError(module, errCode, errMsg);
}
});
moreDialog.dismiss();
}
});
notDisplayView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mConversationLayout.markConversationHidden(conversationInfo);
moreDialog.dismiss();
}
});
clearChatView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mConversationLayout.clearConversationMessage(conversationInfo);
if (conversationInfo.isMarkUnread()) {
mConversationLayout.markConversationUnread(conversationInfo, false);
}
moreDialog.dismiss();
}
});
deleteChatView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mConversationLayout.deleteConversation(conversationInfo);
moreDialog.dismiss();
}
});
cancelView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
moreDialog.dismiss();
}
});
moreDialog.setCanceledOnTouchOutside(false);
Window win = moreDialog.getWindow();
WindowManager.LayoutParams lp = win.getAttributes();
lp.width = lp.width - ScreenUtil.getPxByDp(16f);
lp.y = ScreenUtil.getPxByDp(34f);
moreDialog.getWindow().setBackgroundDrawableResource(com.tencent.qcloud.tuicore.R.color.status_bar_color);
win.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
win.setAttributes(lp);
moreDialog.show();
moreDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
moreDialog.dismiss();
}
return false;
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
if (unreadCountReceiver != null) {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(unreadCountReceiver);
unreadCountReceiver = null;
}
}
}

View File

@@ -0,0 +1,24 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.page;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.component.activities.BaseLightActivity;
import com.tencent.qcloud.tuikit.tuiconversation.R;
public class TUIFoldedConversationMinimalistActivity extends BaseLightActivity {
private TUIFoldedConversationMinimalistFragment mTUIFoldedConversationMinimalistFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.folded_activity);
init();
}
private void init() {
mTUIFoldedConversationMinimalistFragment = new TUIFoldedConversationMinimalistFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.empty_view, mTUIFoldedConversationMinimalistFragment).commitAllowingStateLoss();
}
}

View File

@@ -0,0 +1,241 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.page;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupWindow;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.action.PopActionClickListener;
import com.tencent.qcloud.tuicore.component.action.PopDialogAdapter;
import com.tencent.qcloud.tuicore.component.action.PopMenuAction;
import com.tencent.qcloud.tuicore.component.fragments.BaseFragment;
import com.tencent.qcloud.tuicore.component.interfaces.ITitleBarLayout;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.ConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.util.TUIConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.FoldedConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationFoldPresenter;
import java.util.ArrayList;
import java.util.List;
public class TUIFoldedConversationMinimalistFragment extends BaseFragment {
private View mBaseView;
private TitleBarLayout mTitleBarLayout;
private FoldedConversationLayout mFoldedLayout;
private PopDialogAdapter mConversationPopAdapter;
private ListView mConversationPopList;
private PopupWindow mConversationPopWindow;
private String popWindowConversationId;
private List<PopMenuAction> mConversationPopActions = new ArrayList<>();
private ConversationFoldPresenter presenter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mBaseView = inflater.inflate(R.layout.minimalist_folded_fragment, container, false);
initView();
return mBaseView;
}
private void initView() {
mFoldedLayout = mBaseView.findViewById(R.id.folded_conversation_layout);
mTitleBarLayout = mFoldedLayout.getTitleBar();
mTitleBarLayout.setTitle(getResources().getString(R.string.folded_group_chat), ITitleBarLayout.Position.MIDDLE);
mTitleBarLayout.setOnLeftClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().finish();
}
});
presenter = new ConversationFoldPresenter();
presenter.initListener();
mFoldedLayout.setPresenter(presenter);
mFoldedLayout.initDefault();
mFoldedLayout.getConversationList().setOnConversationAdapterListener(new OnConversationAdapterListener() {
@Override
public void onItemClick(View view, int viewType, ConversationInfo conversationInfo) {
TUIConversationUtils.startChatActivity(conversationInfo);
}
@Override
public void OnItemLongClick(View view, ConversationInfo conversationInfo) {
showItemPopMenu(view, conversationInfo);
}
@Override
public void onConversationChanged(List<ConversationInfo> dataSource) {
if (dataSource == null)return;
ConversationInfo conversationInfo = dataSource.get(0);
if (conversationInfo == null)return;
if (!TextUtils.isEmpty(popWindowConversationId) && popWindowConversationId.equals(conversationInfo.getConversationId())) {
if (mConversationPopWindow != null) {
mConversationPopWindow.dismiss();
}
}
}
@Override
public void onMarkConversationUnread(View view, ConversationInfo conversationInfo, boolean markUnread) {
}
@Override
public void onMarkConversationHidden(View view, ConversationInfo conversationInfo) {
}
@Override
public void onClickMoreView(View view, ConversationInfo conversationInfo) {
}
@Override
public void onSwipeConversationChanged(ConversationInfo conversationInfo) {
if (conversationInfo == null) {
popWindowConversationId = "";
return;
}
popWindowConversationId = conversationInfo.getConversationId();
}
});
restoreConversationItemBackground();
}
private void initPopMenuAction() {
// 设置长按conversation显示PopAction
List<PopMenuAction> conversationPopActions = new ArrayList<PopMenuAction>();
PopMenuAction action = new PopMenuAction();
action.setActionName(getResources().getString(R.string.not_display));
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
ConversationInfo conversationInfo = (ConversationInfo) data;
mFoldedLayout.markConversationHidden((ConversationInfo) data);
}
});
conversationPopActions.add(action);
action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mFoldedLayout.deleteConversation((ConversationInfo) data);
}
});
action.setActionName(getResources().getString(R.string.chat_delete));
conversationPopActions.add(action);
mConversationPopActions.clear();
mConversationPopActions.addAll(conversationPopActions);
}
private void restoreConversationItemBackground() {
if (mFoldedLayout.getConversationList().getAdapter() != null &&
mFoldedLayout.getConversationList().getAdapter().isClick()) {
mFoldedLayout.getConversationList().getAdapter().setClick(false);
mFoldedLayout.getConversationList().getAdapter().notifyItemChanged(mFoldedLayout.getConversationList().getAdapter().getCurrentPosition());
}
}
private void addMarkUnreadPopMenuAction(boolean markUnread) {
PopMenuAction action = new PopMenuAction();
action.setActionClickListener(new PopActionClickListener() {
@Override
public void onActionClick(int index, Object data) {
mFoldedLayout.markConversationUnread((ConversationInfo) data, markUnread);
}
});
if (markUnread) {
action.setActionName(getResources().getString(R.string.mark_unread));
} else {
action.setActionName(getResources().getString(R.string.mark_read));
}
mConversationPopActions.add(0, action);
}
private void showItemPopMenu(View view, final ConversationInfo conversationInfo) {
initPopMenuAction();
if (conversationInfo.getUnRead() > 0) {
addMarkUnreadPopMenuAction(false);
} else {
if (conversationInfo.isMarkUnread()) {
addMarkUnreadPopMenuAction(false);
} else {
addMarkUnreadPopMenuAction(true);
}
}
View itemPop = LayoutInflater.from(getActivity()).inflate(R.layout.conversation_pop_menu_layout, null);
mConversationPopList = itemPop.findViewById(R.id.pop_menu_list);
mConversationPopList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PopMenuAction action = mConversationPopActions.get(position);
if (action.getActionClickListener() != null) {
action.getActionClickListener().onActionClick(position, conversationInfo);
}
mConversationPopWindow.dismiss();
restoreConversationItemBackground();
}
});
for (int i = 0; i < mConversationPopActions.size(); i++) {
PopMenuAction action = mConversationPopActions.get(i);
if (conversationInfo.isTop()) {
if (action.getActionName().equals(getResources().getString(R.string.chat_top))) {
action.setActionName(getResources().getString(R.string.quit_chat_top));
}
} else {
if (action.getActionName().equals(getResources().getString(R.string.quit_chat_top))) {
action.setActionName(getResources().getString(R.string.chat_top));
}
}
}
mConversationPopAdapter = new PopDialogAdapter();
mConversationPopList.setAdapter(mConversationPopAdapter);
mConversationPopAdapter.setDataSource(mConversationPopActions);
mConversationPopWindow = new PopupWindow(itemPop, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
mConversationPopWindow.setBackgroundDrawable(new ColorDrawable());
mConversationPopWindow.setOutsideTouchable(true);
popWindowConversationId = conversationInfo.getConversationId();
int width = ConversationUtils.getListUnspecifiedWidth(mConversationPopAdapter, mConversationPopList);
mConversationPopWindow.setWidth(width);
mConversationPopWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
restoreConversationItemBackground();
popWindowConversationId = "";
}
});
int x = view.getWidth() / 2;
int y = - view.getHeight() / 3;
int popHeight = ScreenUtil.dip2px(45) * 3;
if (y + popHeight + view.getY() + view.getHeight() > mFoldedLayout.getBottom()) {
y = y - popHeight;
}
mConversationPopWindow.showAsDropDown(view, x, y, Gravity.TOP | Gravity.START);
}
}

View File

@@ -0,0 +1,42 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.page;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.component.activities.BaseLightActivity;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
public class TUIForwardSelectMinimalistActivity extends BaseLightActivity {
private static final String TAG = TUIForwardSelectMinimalistActivity.class.getSimpleName();
private TUIForwardSelectMinimalistFragment mTUIForwardSelectMinimalistFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.forward_activity);
init();
}
@Override
protected void onNewIntent(Intent intent) {
TUIConversationLog.i(TAG, "onNewIntent");
super.onNewIntent(intent);;
}
@Override
protected void onResume() {
TUIConversationLog.i(TAG, "onResume");
super.onResume();
}
private void init() {
mTUIForwardSelectMinimalistFragment = new TUIForwardSelectMinimalistFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.empty_view, mTUIForwardSelectMinimalistFragment).commitAllowingStateLoss();
}
}

View File

@@ -0,0 +1,352 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.page;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.component.CustomLinearLayoutManager;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.fragments.BaseFragment;
import com.tencent.qcloud.tuicore.component.interfaces.ITitleBarLayout;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationConstants;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationListLayout;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ForwardConversationSelectorAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ForwardSelectLayout;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class TUIForwardSelectMinimalistFragment extends BaseFragment {
private View mBaseView;
private TitleBarLayout mTitleBarLayout;
private ForwardSelectLayout mForwardLayout;
private RecyclerView mForwardSelectlistView;
private ForwardConversationSelectorAdapter mAdapter;
private List<ConversationInfo> mDataSource = new ArrayList<>();
private List<ConversationInfo> mContactDataSource = new ArrayList<>();
private List<ConversationInfo> mAllSelectedConversations = new ArrayList<>();
private RelativeLayout mForwardSelectlistViewLayout;
private TextView mSureView;
private ConversationPresenter presenter;
private static final String TAG = TUIForwardSelectMinimalistFragment.class.getSimpleName();
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
mBaseView = inflater.inflate(R.layout.minimalist_forward_fragment, container, false);
return mBaseView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mForwardLayout = view.findViewById(R.id.forward_conversation_layout);
presenter = new ConversationPresenter();
mForwardLayout.setPresenter(presenter);
mForwardLayout.initDefault();
customizeConversation();
mForwardLayout.getConversationList().setOnConversationAdapterListener(new OnConversationAdapterListener() {
@Override
public void onItemClick(View view, int viewType, ConversationInfo conversationInfo) {
if (viewType == ConversationInfo.TYPE_RECENT_LABEL){
return;
} else if (viewType == ConversationInfo.TYPE_FORWAR_SELECT){
if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_cancle))){
Bundle param = new Bundle();
param.putInt(TUIConversationConstants.GroupType.TYPE, TUIConversationConstants.GroupType.PUBLIC);
param.putBoolean(TUIConversationConstants.FORWARD_CREATE_NEW_CHAT, false);
TUICore.startActivity(TUIForwardSelectMinimalistFragment.this, "ForwardSelectGroupMinimalistActivity", param, TUIConversationConstants.FORWARD_SELECT_MEMBERS_CODE);
}else if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_close))){
Bundle param = new Bundle();
param.putInt(TUIConversationConstants.GroupType.TYPE, TUIConversationConstants.GroupType.PUBLIC);
param.putBoolean(TUIConversationConstants.FORWARD_CREATE_NEW_CHAT, true);
TUICore.startActivity(TUIForwardSelectMinimalistFragment.this, "ForwardSelectGroupMinimalistActivity", param, TUIConversationConstants.FORWARD_CREATE_GROUP_CODE);
}else{
TUIConversationLog.d(TAG,"Titlebar exception");
}
} else {
if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_cancle))) {
mDataSource = mForwardLayout.getConversationList().getAdapter().getSelectedItem();
checkRepeat();
refreshSelectConversations();
} else if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_close))){
forwardMessages(conversationInfo);
} else {
forwardMessages(conversationInfo);
}
}
}
@Override
public void OnItemLongClick(View view, ConversationInfo conversationInfo) {
}
@Override
public void onConversationChanged(List<ConversationInfo> dataSource) {
}
@Override
public void onMarkConversationUnread(View view, ConversationInfo conversationInfo, boolean markUnread) {
}
@Override
public void onMarkConversationHidden(View view, ConversationInfo conversationInfo) {
}
@Override
public void onClickMoreView(View view, ConversationInfo conversationInfo) {
}
@Override
public void onSwipeConversationChanged(ConversationInfo conversationInfo) {
}
});
mForwardSelectlistViewLayout = view.findViewById(R.id.forward_select_list_layout);
mForwardSelectlistViewLayout.setVisibility(View.VISIBLE);
mForwardSelectlistView = view.findViewById(R.id.forward_select_list);
mForwardSelectlistView.setLayoutManager(new CustomLinearLayoutManager(getContext(), CustomLinearLayoutManager.HORIZONTAL, false));
mAdapter = new ForwardConversationSelectorAdapter(this.getContext());
mForwardSelectlistView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new ForwardConversationSelectorAdapter.OnItemClickListener() {
@Override
public void onClick(View view, int position) {
boolean needFresh = false;
if (mDataSource != null && mDataSource.size() != 0){
if(position < mDataSource.size()) {
mDataSource.remove(position);
mForwardLayout.getConversationList().getAdapter().setSelectConversations(mDataSource);
needFresh = true;
}
}
if(!needFresh) {
if (mContactDataSource != null && mContactDataSource.size() != 0) {
int dataSourcePosition = mDataSource == null ? 0 : mDataSource.size();
if (position - dataSourcePosition < mContactDataSource.size()) {
mContactDataSource.remove(position - dataSourcePosition);
needFresh = true;
}
}
}
if (needFresh) {
refreshSelectConversations();
}
}
});
mSureView = view.findViewById(R.id.btn_msg_ok);
mSureView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getActivity() != null) {
HashMap<String, Boolean> conversationMap = new HashMap<>();
if (mDataSource != null && mDataSource.size() != 0){
for (int i=0;i<mDataSource.size();i++){
conversationMap.put(mDataSource.get(i).getId(), mDataSource.get(i).isGroup());
}
}
if (mContactDataSource != null && mContactDataSource.size() != 0){
for (int i=0;i<mContactDataSource.size();i++){
conversationMap.put(mContactDataSource.get(i).getId(), mContactDataSource.get(i).isGroup());
}
}
Intent intent = new Intent();
intent.putExtra(TUIConversationConstants.FORWARD_SELECT_CONVERSATION_KEY, conversationMap);
getActivity().setResult(TUIConversationConstants.FORWARD_SELECT_ACTIVTY_CODE, intent);
getActivity().finish();
}
}
});
refreshSelectConversations();
initTitleAction();
}
private void refreshSelectConversations(){
mAllSelectedConversations.clear();
mDataSource = mForwardLayout.getConversationList().getAdapter().getSelectedItem();
if (mDataSource != null && mDataSource.size() != 0){
mAllSelectedConversations.addAll(mDataSource);
}
if (mContactDataSource != null && mContactDataSource.size() != 0){
mAllSelectedConversations.addAll(mContactDataSource);
}
mAdapter.setDataSource(mAllSelectedConversations);
if (mAllSelectedConversations == null || mAllSelectedConversations.size() == 0){
mSureView.setText(getString(com.tencent.qcloud.tuicore.R.string.sure));
mSureView.setVisibility(View.GONE);
mForwardSelectlistViewLayout.setVisibility(View.GONE);
} else {
mForwardSelectlistViewLayout.setVisibility(View.VISIBLE);
mSureView.setVisibility(View.VISIBLE);
mSureView.setText(getString(com.tencent.qcloud.tuicore.R.string.sure) + "(" + mAllSelectedConversations.size() + ")");
}
}
private void forwardMessages(final ConversationInfo conversationInfo){
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("");
builder.setMessage(getString(R.string.forward_alert_title));
builder.setCancelable(true);
builder.setPositiveButton(getString(com.tencent.qcloud.tuicore.R.string.sure), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (getActivity() != null) {
HashMap<String, Boolean> chatInfo = new HashMap<>();
chatInfo.put(conversationInfo.getId(), conversationInfo.isGroup());
Intent intent = new Intent();
intent.putExtra(TUIConversationConstants.FORWARD_SELECT_CONVERSATION_KEY, chatInfo);
getActivity().setResult(TUIConversationConstants.FORWARD_SELECT_ACTIVTY_CODE, intent);
getActivity().finish();
}
dialog.dismiss();
}
});
builder.setNegativeButton(getString(com.tencent.qcloud.tuicore.R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void customizeConversation(){
mTitleBarLayout = mForwardLayout.getTitleBar();
mTitleBarLayout.setTitle("", TitleBarLayout.Position.MIDDLE);
mTitleBarLayout.getLeftGroup().setVisibility(View.VISIBLE);
mTitleBarLayout.getRightGroup().setVisibility(View.VISIBLE);
mTitleBarLayout.setTitle(getString(R.string.titlebar_close), ITitleBarLayout.Position.LEFT);
mTitleBarLayout.setTitle(getString(R.string.titlebar_mutiselect), TitleBarLayout.Position.RIGHT);
mTitleBarLayout.getLeftIcon().setVisibility(View.GONE);
mTitleBarLayout.getRightIcon().setVisibility(View.GONE);
}
private void initTitleAction() {
mForwardLayout.getTitleBar().setOnLeftClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_cancle))){
mTitleBarLayout.getRightGroup().setVisibility(View.VISIBLE);
mTitleBarLayout.setTitle(getString(R.string.titlebar_close), TitleBarLayout.Position.LEFT);
mTitleBarLayout.setTitle(getString(R.string.titlebar_mutiselect), TitleBarLayout.Position.RIGHT);
ConversationListLayout listLayout = mForwardLayout.getConversationList();
listLayout.getAdapter().setShowMultiSelectCheckBox(false);
listLayout.getAdapter().notifyDataSetChanged();
mForwardSelectlistViewLayout.setVisibility(View.GONE);
mAdapter.setDataSource(null);
mAllSelectedConversations.clear();
}else if(mTitleBarLayout.getLeftTitle().getText().equals(getString(R.string.titlebar_close))){
getActivity().finish();
}else{
TUIConversationLog.d(TAG,"Titlebar exception");
}
}
});
mForwardLayout.getTitleBar().setOnRightClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mTitleBarLayout.getRightGroup().setVisibility(View.GONE);
mTitleBarLayout.setTitle(getString(R.string.titlebar_cancle), TitleBarLayout.Position.LEFT);
ConversationListLayout listLayout = mForwardLayout.getConversationList();
listLayout.getAdapter().setShowMultiSelectCheckBox(true);
listLayout.getAdapter().notifyDataSetChanged();
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == TUIConversationConstants.FORWARD_CREATE_GROUP_CODE && resultCode == TUIConversationConstants.FORWARD_CREATE_GROUP_CODE) {
if (getActivity() != null) {
getActivity().setResult(TUIConversationConstants.FORWARD_SELECT_ACTIVTY_CODE, data);
getActivity().finish();
}
} else if (requestCode == TUIConversationConstants.FORWARD_SELECT_MEMBERS_CODE && resultCode == TUIConversationConstants.FORWARD_SELECT_MEMBERS_CODE){
HashMap<String, String> conversationMap = (HashMap<String, String>) data.getSerializableExtra(TUIConversationConstants.FORWARD_SELECT_CONVERSATION_KEY);
if (conversationMap == null || conversationMap.isEmpty()){
mContactDataSource.clear();
refreshSelectConversations();
return;
}
mContactDataSource.clear();
for (Map.Entry<String, String> entry: conversationMap.entrySet()){
ConversationInfo conversationInfo = new ConversationInfo();
List<Object> iconList = new ArrayList<>();
iconList.add(entry.getValue());
conversationInfo.setIconUrlList(iconList);
conversationInfo.setId(entry.getKey());
conversationInfo.setGroup(false);
mContactDataSource.add(conversationInfo);
}
checkRepeat();
refreshSelectConversations();
}
}
private void checkRepeat() {
Iterator<ConversationInfo> iterator = mContactDataSource.iterator();
while (iterator.hasNext()) {
ConversationInfo conversationInfo = iterator.next();
if (mDataSource != null && mDataSource.size() != 0) {
for (int i = 0; i < mDataSource.size(); i++) {
if (conversationInfo.getId().equals(mDataSource.get(i).getId())) {
iterator.remove();
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.setting;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationListLayout;
public class ConversationLayoutSetting {
public static void customizeConversation(final ConversationLayout layout) {
ConversationListLayout listLayout = (ConversationListLayout) layout.getConversationList();
listLayout.setItemAvatarRadius((int) ScreenUtil.dp2px(49f, listLayout.getResources().getDisplayMetrics()));
// 动态插入删除Item包括自定义会话
// final ConversationInfo customInfo = new ConversationInfo();
// customInfo.setType(ConversationInfo.TYPE_CUSTOM);
// customInfo.setId("自定义会话");
// customInfo.setGroup(false);
// customInfo.setTitle("乔丹风行8代跑鞋 风随我动!");
// customInfo.setIconUrl("https://img1.gtimg.com/ninja/2/2019/03/ninja155375585738456.jpg");
//
//
// new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
// @Override
// public void run() {
// layout.addConversationInfo(0, customInfo);
// }
// }, 3000);
// new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
// @Override
// public void run() {
// layout.removeConversationInfo(0);
// }
// }, 5000);
}
}

View File

@@ -0,0 +1,36 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.util;
import android.os.Bundle;
import com.tencent.imsdk.v2.V2TIMConversation;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.io.Serializable;
import java.util.ArrayList;
public class TUIConversationUtils {
public static void startChatActivity(ConversationInfo conversationInfo) {
Bundle param = new Bundle();
param.putInt(TUIConstants.TUIChat.CHAT_TYPE, conversationInfo.isGroup() ? V2TIMConversation.V2TIM_GROUP : V2TIMConversation.V2TIM_C2C);
param.putString(TUIConstants.TUIChat.CHAT_ID, conversationInfo.getId());
param.putString(TUIConstants.TUIChat.CHAT_NAME, conversationInfo.getTitle());
if (conversationInfo.getDraft() != null) {
param.putString(TUIConstants.TUIChat.DRAFT_TEXT, conversationInfo.getDraft().getDraftText());
param.putLong(TUIConstants.TUIChat.DRAFT_TIME, conversationInfo.getDraft().getDraftTime());
}
param.putBoolean(TUIConstants.TUIChat.IS_TOP_CHAT, conversationInfo.isTop());
param.putString(TUIConstants.TUIChat.FACE_URL, conversationInfo.getIconPath());
if (conversationInfo.isGroup()) {
param.putString(TUIConstants.TUIChat.GROUP_TYPE, conversationInfo.getGroupType());
param.putSerializable(TUIConstants.TUIChat.FACE_URL_LIST, (Serializable) conversationInfo.getIconUrlList());
param.putSerializable(TUIConstants.TUIChat.AT_INFO_LIST, (Serializable) conversationInfo.getGroupAtInfoList());
}
if (conversationInfo.isGroup()) {
TUICore.startActivity("TUIGroupChatMinimalistActivity", param);
} else {
TUICore.startActivity("TUIC2CChatMinimalistActivity", param);
}
}
}

View File

@@ -0,0 +1,25 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
public abstract class ConversationBaseHolder extends RecyclerView.ViewHolder {
protected View rootView;
protected ConversationListAdapter mAdapter;
public ConversationBaseHolder(View itemView) {
super(itemView);
rootView = itemView;
}
public void setAdapter(RecyclerView.Adapter adapter) {
mAdapter = (ConversationListAdapter) adapter;
}
public abstract void layoutViews(ConversationInfo conversationInfo, int position);
}

View File

@@ -0,0 +1,261 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.graphics.Color;
import android.text.Html;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.imsdk.v2.V2TIMUserStatus;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.TUIThemeManager;
import com.tencent.qcloud.tuicore.component.UnreadCountTextView;
import com.tencent.qcloud.tuicore.util.DateTimeUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.bean.DraftInfo;
import com.tencent.qcloud.tuikit.tuiconversation.config.TUIConversationConfig;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeLayout;
import java.util.Date;
import java.util.HashMap;
public class ConversationCommonHolder extends ConversationBaseHolder {
public ConversationIconView conversationIconView;
protected LinearLayout leftItemLayout;
protected TextView titleText;
protected TextView messageText;
protected TextView timelineText;
protected UnreadCountTextView unreadText;
protected TextView atInfoText;
protected ImageView disturbView;
protected CheckBox multiSelectCheckBox;
protected RelativeLayout messageStatusLayout;
public ImageView messageSending;
public ImageView messageFailed;
private boolean isForwardMode = false;
protected View userStatusView;
private boolean showFoldedStyle = true;
protected SwipeLayout swipeLayout;
protected RelativeLayout markReadView, moreView;
protected TextView markReadTextView, notDisplayView;
protected ImageView markReadIconView;
public ConversationCommonHolder(View itemView) {
super(itemView);
leftItemLayout = rootView.findViewById(R.id.item_left);
conversationIconView = rootView.findViewById(R.id.conversation_icon);
titleText = rootView.findViewById(R.id.conversation_title);
messageText = rootView.findViewById(R.id.conversation_last_msg);
timelineText = rootView.findViewById(R.id.conversation_time);
unreadText = rootView.findViewById(R.id.conversation_unread);
atInfoText = rootView.findViewById(R.id.conversation_at_msg);
disturbView = rootView.findViewById(R.id.not_disturb);
multiSelectCheckBox = rootView.findViewById(R.id.select_checkbox);
messageStatusLayout = rootView.findViewById(R.id.message_status_layout);
messageFailed = itemView.findViewById(R.id.message_status_failed);
messageSending = itemView.findViewById(R.id.message_status_sending);
userStatusView = itemView.findViewById(R.id.user_status);
swipeLayout = itemView.findViewById(R.id.swipe);
markReadView = itemView.findViewById(R.id.mark_read);
moreView = itemView.findViewById(R.id.more_view);
markReadTextView = itemView.findViewById(R.id.mark_read_text);
notDisplayView = itemView.findViewById(R.id.not_display);
markReadIconView = itemView.findViewById(R.id.mark_read_image);
}
public void setForwardMode(boolean forwardMode) {
isForwardMode = forwardMode;
}
public void setShowFoldedStyle(boolean showFoldedStyle) {
this.showFoldedStyle = showFoldedStyle;
}
public void layoutViews(ConversationInfo conversation, int position) {
if (conversation.isTop() && !isForwardMode) {
leftItemLayout.setBackgroundColor(rootView.getResources().getColor(R.color.conversation_item_top_color));
} else {
leftItemLayout.setBackgroundColor(Color.WHITE);
}
if (showFoldedStyle && conversation.isMarkFold()) {
titleText.setText(R.string.folded_group_chat);
timelineText.setVisibility(View.GONE);
} else {
titleText.setText(conversation.getTitle());
}
messageText.setText("");
timelineText.setText("");
DraftInfo draftInfo = conversation.getDraft();
String draftText = "";
if (draftInfo != null) {
Gson gson = new Gson();
HashMap draftJsonMap;
draftText = draftInfo.getDraftText();
try {
draftJsonMap = gson.fromJson(draftInfo.getDraftText(), HashMap.class);
if (draftJsonMap != null) {
draftText = (String) draftJsonMap.get("content");
}
} catch (JsonSyntaxException e) {
TUIConversationLog.e("ConversationCommonHolder", " getDraftJsonMap error ");
}
}
if (draftInfo != null) {
messageText.setText(draftText);
timelineText.setText(DateTimeUtil.getTimeFormatText(new Date(draftInfo.getDraftTime() * 1000)));
} else {
HashMap<String, Object> param = new HashMap<>();
param.put(TUIConstants.TUIChat.V2TIMMESSAGE, conversation.getLastMessage());
String lastMsgDisplayString = (String) TUICore.callService(TUIConstants.TUIChat.SERVICE_NAME, TUIConstants.TUIChat.METHOD_GET_DISPLAY_STRING, param);
// 获取要显示的字符
// Get the characters to display
if (lastMsgDisplayString != null) {
messageText.setText(Html.fromHtml(lastMsgDisplayString));
messageText.setTextColor(rootView.getResources().getColor(R.color.list_bottom_text_bg));
}
if (conversation.getLastMessage() != null) {
timelineText.setText(DateTimeUtil.getTimeFormatText(new Date(conversation.getLastMessageTime() * 1000)));
}
}
if (conversation.isShowDisturbIcon()) {
if ((showFoldedStyle && conversation.isMarkFold())) {
if (conversation.isMarkLocalUnread()) {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("");
} else {
unreadText.setVisibility(View.GONE);
}
} else {
if (conversation.getUnRead() == 0) {
if (conversation.isMarkUnread()) {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("");
} else {
unreadText.setVisibility(View.GONE);
}
} else {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("");
if (messageText.getText() != null) {
String text = messageText.getText().toString();
messageText.setText("[" + conversation.getUnRead() + rootView.getContext().getString(R.string.message_num) + "] " + text);
}
}
}
} else if (conversation.getUnRead() > 0) {
unreadText.setVisibility(View.VISIBLE);
if (conversation.getUnRead() > 99) {
unreadText.setText("99+");
} else {
unreadText.setText("" + conversation.getUnRead());
}
} else {
if (conversation.isMarkUnread()) {
unreadText.setVisibility(View.VISIBLE);
unreadText.setText("1");
} else {
unreadText.setVisibility(View.GONE);
}
}
if (draftInfo != null) {
atInfoText.setVisibility(View.VISIBLE);
atInfoText.setText(R.string.drafts);
atInfoText.setTextColor(Color.RED);
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
} else {
if (conversation.getAtInfoText().isEmpty()) {
atInfoText.setVisibility(View.GONE);
} else {
atInfoText.setVisibility(View.VISIBLE);
atInfoText.setText(conversation.getAtInfoText());
atInfoText.setTextColor(Color.RED);
}
V2TIMMessage lastMessage = conversation.getLastMessage();
if (lastMessage != null) {
int status = lastMessage.getStatus();
if (status == V2TIMMessage.V2TIM_MSG_STATUS_SEND_FAIL) {
messageStatusLayout.setVisibility(View.VISIBLE);
messageFailed.setVisibility(View.VISIBLE);
messageSending.setVisibility(View.GONE);
} else if (status == V2TIMMessage.V2TIM_MSG_STATUS_SENDING) {
messageStatusLayout.setVisibility(View.VISIBLE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.VISIBLE);
} else {
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
}
} else {
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
}
}
conversationIconView.setRadius(mAdapter.getItemAvatarRadius());
if (mAdapter.getItemDateTextSize() != 0) {
timelineText.setTextSize(mAdapter.getItemDateTextSize());
}
if (mAdapter.getItemBottomTextSize() != 0) {
messageText.setTextSize(mAdapter.getItemBottomTextSize());
}
if (mAdapter.getItemTopTextSize() != 0) {
titleText.setTextSize(mAdapter.getItemTopTextSize());
}
if (!mAdapter.hasItemUnreadDot()) {
unreadText.setVisibility(View.GONE);
}
conversationIconView.setShowFoldedStyle(showFoldedStyle);
conversationIconView.setConversation(conversation);
if (conversation.isShowDisturbIcon() && !isForwardMode) {
if (showFoldedStyle && conversation.isMarkFold()) {
disturbView.setVisibility(View.GONE);
} else {
disturbView.setVisibility(View.VISIBLE);
}
} else {
disturbView.setVisibility(View.GONE);
}
if (isForwardMode) {
messageText.setVisibility(View.GONE);
timelineText.setVisibility(View.GONE);
unreadText.setVisibility(View.GONE);
atInfoText.setVisibility(View.GONE);
messageStatusLayout.setVisibility(View.GONE);
messageFailed.setVisibility(View.GONE);
messageSending.setVisibility(View.GONE);
}
if (!conversation.isGroup() && TUIConversationConfig.getInstance().isShowUserStatus()) {
if (conversation.getStatusType() == V2TIMUserStatus.V2TIM_USER_STATUS_ONLINE) {
userStatusView.setVisibility(View.VISIBLE);
} else {
userStatusView.setVisibility(View.GONE);
}
} else {
userStatusView.setVisibility(View.GONE);
}
}
}

View File

@@ -0,0 +1,68 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.graphics.Color;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
public class ConversationCustomHolder extends ConversationBaseHolder {
protected LinearLayout leftItemLayout;
protected TextView titleText;
protected TextView messageText;
protected TextView timelineText;
protected TextView unreadText;
protected ConversationIconView conversationIconView;
public ConversationCustomHolder(View itemView) {
super(itemView);
leftItemLayout = rootView.findViewById(R.id.item_left);
conversationIconView = rootView.findViewById(R.id.conversation_icon);
titleText = rootView.findViewById(R.id.conversation_title);
messageText = rootView.findViewById(R.id.conversation_last_msg);
timelineText = rootView.findViewById(R.id.conversation_time);
unreadText = rootView.findViewById(R.id.conversation_unread);
}
@Override
public void layoutViews(ConversationInfo conversation, int position) {
if (conversation.isTop()) {
leftItemLayout.setBackgroundColor(rootView.getResources().getColor(R.color.conversation_item_top_color));
} else {
leftItemLayout.setBackgroundColor(Color.WHITE);
}
conversationIconView.setConversation(conversation);
titleText.setText(conversation.getTitle());
messageText.setText("");
timelineText.setText("");
if (conversation.getUnRead() > 0) {
unreadText.setVisibility(View.VISIBLE);
if (conversation.getUnRead() > 99) {
unreadText.setText("99+");
} else {
unreadText.setText("" + conversation.getUnRead());
}
} else {
unreadText.setVisibility(View.GONE);
}
if (mAdapter.getItemDateTextSize() != 0) {
timelineText.setTextSize(mAdapter.getItemDateTextSize());
}
if (mAdapter.getItemBottomTextSize() != 0) {
messageText.setTextSize(mAdapter.getItemBottomTextSize());
}
if (mAdapter.getItemTopTextSize() != 0) {
titleText.setTextSize(mAdapter.getItemTopTextSize());
}
}
}

View File

@@ -0,0 +1,169 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.tencent.qcloud.tuicore.TUIConfig;
import com.tencent.qcloud.tuicore.component.gatherimage.SynthesizedImageView;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuicore.util.BackgroundTasks;
import com.tencent.qcloud.tuicore.util.ImageUtil;
import com.tencent.qcloud.tuicore.util.ThreadHelper;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationIconPresenter;
import java.util.ArrayList;
import java.util.List;
/**
* 会话列表头像View
*/
public class ConversationIconView extends RelativeLayout {
private ImageView mIconView;
private boolean showFoldedStyle = false;
private ConversationIconPresenter presenter;
public ConversationIconView(Context context) {
super(context);
init();
}
public ConversationIconView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ConversationIconView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
inflate(getContext(), com.tencent.qcloud.tuicore.R.layout.profile_icon_view, this);
mIconView = findViewById(com.tencent.qcloud.tuicore.R.id.profile_icon);
((SynthesizedImageView) mIconView).defaultImage(TUIConfig.getDefaultAvatarImage());
presenter = new ConversationIconPresenter();
}
public void setShowFoldedStyle(boolean showFoldedStyle) {
this.showFoldedStyle = showFoldedStyle;
}
/**
* 设置会话头像的url
*
* @param iconUrls 头像url,最多只取前9个
*/
public void setIconUrls(final List<Object> iconUrls, final String conversationId) {
// 需要在主线程中执行,以免写缓存出现问题
BackgroundTasks.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) (mIconView)).displayImage(iconUrls).load(conversationId);
}
}
});
}
public void setConversation(ConversationInfo conversationInfo) {
if (showFoldedStyle && conversationInfo.isMarkFold()) {
mIconView.setImageResource(R.drawable.ic_fold);
} else if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) (mIconView)).setImageId(conversationInfo.getConversationId());
if (conversationInfo.isGroup()) {
fillConversationUrlForGroup(conversationInfo);
} else {
setIconUrls(conversationInfo.getIconUrlList(), conversationInfo.getConversationId());
}
}
}
private void fillConversationUrlForGroup(final ConversationInfo info) {
List<Object> iconUrlList = info.getIconUrlList();
if (iconUrlList == null || iconUrlList.size() == 0) {
if (!TUIConfig.isEnableGroupGridAvatar()) {
List<Object> faceList = new ArrayList<>();
faceList.add(TUIConfig.getDefaultGroupAvatarImage());
setIconUrls(faceList, info.getConversationId());
return;
}
// 读取文件,在线程池中进行,避免主线程卡顿
ThreadHelper.INST.execute(new Runnable() {
@Override
public void run() {
final String savedIcon = ImageUtil.getGroupConversationAvatar(info.getConversationId());
if (TextUtils.isEmpty(savedIcon)) {
fillFaceUrlList(info.getId(), info);
} else {
List<Object> list = new ArrayList<>();
list.add(savedIcon);
info.setIconUrlList(list);
setIconUrls(list, info.getConversationId());
}
}
});
} else {
if (!TUIConfig.isEnableGroupGridAvatar() && iconUrlList.size() > 1) {
List<Object> faceList = new ArrayList<>();
faceList.add(TUIConfig.getDefaultGroupAvatarImage());
setIconUrls(faceList, info.getConversationId());
} else {
setIconUrls(iconUrlList, info.getConversationId());
}
}
}
private void fillFaceUrlList(final String groupID, final ConversationInfo info) {
BackgroundTasks.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
clearImage();
presenter.getGroupMemberIconList(groupID, new IUIKitCallback<List<Object>>() {
@Override
public void onSuccess(List<Object> data) {
info.setIconUrlList(data);
setIconUrls(data, info.getConversationId());
}
@Override
public void onError(String module, int errCode, String errMsg) {
}
});
}
});
}
public void setRadius(int radius) {
if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) (mIconView)).setRadius(radius);
}
}
public void setDefaultImageResId(int resId) {
BitmapDrawable bd = (BitmapDrawable) getContext().getResources().getDrawable(resId);
mIconView.setImageBitmap(bd.getBitmap());
}
public void setBitmapResId(int resId) {
BitmapDrawable bd = (BitmapDrawable) getContext().getResources().getDrawable(resId);
Bitmap bitmap = ImageUtil.toRoundBitmap(bd.getBitmap());
mIconView.setImageBitmap(bitmap);
}
public void clearImage() {
if (mIconView instanceof SynthesizedImageView) {
((SynthesizedImageView) mIconView).clear();
}
}
}

View File

@@ -0,0 +1,249 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.IConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.page.ConversationMinimalistFragment;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.setting.ConversationLayoutSetting;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.Attributes;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConversationLayout extends RelativeLayout implements IConversationLayout {
private ConversationListLayout mConversationList;
private ViewGroup searchLayout;
private ConversationPresenter presenter;
private ImageView conversationEditView, createChatView;
private TextView conversationEditDoneView;
private ConversationMinimalistFragment.OnClickListener mClickListener = null;
private boolean isMultiSelected = false;
private List<ConversationInfo> mSelectConversations = new ArrayList<>();
public ConversationLayout(Context context) {
super(context);
init();
}
public ConversationLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ConversationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setPresenter(ConversationPresenter presenter) {
this.presenter = presenter;
if (mConversationList != null) {
mConversationList.setPresenter(presenter);
}
}
/**
* 初始化相关UI元素
*/
private void init() {
inflate(getContext(), R.layout.minimalistui_conversation_layout, this);
mConversationList = findViewById(R.id.conversation_list);
searchLayout = findViewById(R.id.search_layout);
conversationEditView = findViewById(R.id.edit_button);
createChatView = findViewById(R.id.create_new_button);
conversationEditDoneView = findViewById(R.id.edit_done);
mSelectConversations.clear();
conversationEditView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (mClickListener != null) {
mClickListener.onEditConversationStartClick();
}
conversationEditView.setVisibility(GONE);
conversationEditDoneView.setVisibility(VISIBLE);
createChatView.setVisibility(GONE);
conversationMutiSelectStart();
}
});
createChatView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (mClickListener != null) {
mClickListener.onStartChatClick();
}
}
});
conversationEditDoneView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (mClickListener != null) {
mClickListener.onEditConversationEndClick();
}
conversationEditView.setVisibility(VISIBLE);
conversationEditDoneView.setVisibility(GONE);
createChatView.setVisibility(VISIBLE);
conversationMutiSelectEnd();
}
});
}
public ImageView getCreateChatView() {
return createChatView;
}
public void resetTitileBar() {
conversationEditView.setVisibility(VISIBLE);
conversationEditDoneView.setVisibility(GONE);
createChatView.setVisibility(VISIBLE);
conversationMutiSelectEnd();
}
public void setOnClickListener(ConversationMinimalistFragment.OnClickListener listener) {
mClickListener = listener;
}
public boolean isMultiSelected() {
return isMultiSelected;
}
private void conversationMutiSelectStart() {
ConversationListAdapter adapter = mConversationList.getAdapter();
if (adapter != null) {
adapter.setShowMultiSelectCheckBox(true);
adapter.notifyDataSetChanged();
adapter.closeAllSwipeItems();
adapter.switchAllSwipeEnable(false);
}
isMultiSelected = true;
mSelectConversations.clear();
}
private void conversationMutiSelectEnd() {
ConversationListAdapter adapter = mConversationList.getAdapter();
if (adapter != null) {
adapter.setShowMultiSelectCheckBox(false);
adapter.notifyDataSetChanged();
adapter.closeAllSwipeItems();
adapter.switchAllSwipeEnable(true);
}
isMultiSelected = false;
mSelectConversations.clear();
}
public void initDefault() {
final ConversationListAdapter adapter = new ConversationListAdapter();
if (presenter != null) {
initSearchView(adapter);
adapter.setShowFoldedStyle(true);
}
mConversationList.setLayoutManager(new LinearLayoutManager(getContext()));
adapter.setMode(Attributes.Mode.Single);
mConversationList.setAdapter((IConversationListAdapter) adapter);
if (presenter != null) {
presenter.setAdapter(adapter);
}
ConversationLayoutSetting.customizeConversation(this);
mConversationList.loadConversation(0);
}
public void initSearchView(ConversationListAdapter adapter) {
Map<String, Object> param = new HashMap<>();
param.put(TUIConstants.TUIConversation.CONTEXT, getContext());
Map<String, Object> searchExtension = TUICore.getExtensionInfo(TUIConstants.TUIConversation.EXTENSION_MINIMALIST_SEARCH, param);
if (searchExtension != null) {
searchLayout.setVisibility(VISIBLE);
if (searchLayout.getChildCount() == 0) {
View searchView = (View) searchExtension.get(TUIConstants.TUIConversation.SEARCH_VIEW);
searchLayout.addView(searchView);
}
} else {
searchLayout.removeAllViews();
searchLayout.setVisibility(GONE);
}
}
@Override
public void setParentLayout(Object parent) {
}
@Override
public ConversationListLayout getConversationList() {
return mConversationList;
}
@Override
public void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack) {
if (presenter != null) {
presenter.setConversationTop(conversation, callBack);
}
}
@Override
public void deleteConversation(ConversationInfo conversation) {
if (presenter != null) {
presenter.deleteConversation(conversation);
}
}
@Override
public void clearConversationMessage(ConversationInfo conversation) {
if (presenter != null) {
presenter.clearConversationMessage(conversation);
}
}
@Override
public void markConversationHidden(ConversationInfo conversation) {
if (presenter != null) {
presenter.markConversationHidden(conversation, true);
}
}
@Override
public void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread) {
if (presenter != null) {
presenter.markConversationUnread(conversationInfo, markUnread);
}
}
@Override
public void hideFoldedItem(boolean needHide) {
if (presenter != null) {
presenter.hideFoldItem(needHide);
}
}
@Override
public void clearUnreadStatusOfFoldItem() {
if (presenter != null) {
presenter.setUnreadStatusOfFoldItem(false);
}
}
@Override
public TitleBarLayout getTitleBar() {
return null;
}
}

View File

@@ -0,0 +1,654 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.graphics.Color;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationService;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.RecyclerSwipeAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SimpleSwipeListener;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ConversationListAdapter extends RecyclerSwipeAdapter<RecyclerView.ViewHolder> implements IConversationListAdapter {
public static final int ITEM_TYPE_HEADER_HIDE = 101;
public static final int ITEM_TYPE_FOOTER_LOADING = -99;
public static final int HEADER_COUNT = 1;
public static final int FOOTER_COUNT = 1;
public static final int SELECT_COUNT = 1;
public static final int SELECT_LABEL_COUNT = 1;
private boolean mHasShowUnreadDot = true;
private int mItemAvatarRadius = ScreenUtil.getPxByDp(5);
private int mTopTextSize;
private int mBottomTextSize;
private int mDateTextSize;
protected List<ConversationInfo> mDataSource = new ArrayList<>();
private OnConversationAdapterListener mOnConversationAdapterListener;
//消息转发
private final HashMap<String, Boolean> mSelectedPositions = new HashMap<>();
private boolean isShowMultiSelectCheckBox = false;
private boolean isForwardFragment = false;
private boolean mIsLoading = false;
// 长按高亮显示
private boolean isClick = false;
private int currentPosition = -1;
private View hideView;
// 展示折叠样式
private boolean showFoldedStyle = true;
public ConversationListAdapter() {
}
public int getCurrentPosition() {
return currentPosition;
}
public boolean isClick() {
return isClick;
}
public void setClick(boolean click) {
isClick = click;
}
public void setCurrentPosition(int currentPosition , boolean isClick) {
this.currentPosition = currentPosition;
this.isClick = isClick;
}
public void setShowMultiSelectCheckBox(boolean show) {
isShowMultiSelectCheckBox = show;
if (!isShowMultiSelectCheckBox) {
mSelectedPositions.clear();
}
}
public void setForwardFragment(boolean forwardFragment) {
isForwardFragment = forwardFragment;
}
public void setShowFoldedStyle(boolean showFoldedStyle) {
this.showFoldedStyle = showFoldedStyle;
}
//设置给定位置条目的选择状态
public void setItemChecked(String conversationId, boolean isChecked) {
mSelectedPositions.put(conversationId, isChecked);
}
//根据位置判断条目是否选中
private boolean isItemChecked(String id) {
if (mSelectedPositions.size() <= 0) {
return false;
}
if (mSelectedPositions.containsKey(id)) {
return mSelectedPositions.get(id);
} else {
return false;
}
}
// 获得选中条目的结果
public List<ConversationInfo> getSelectedItem() {
if (mSelectedPositions.size() == 0) {
return null;
}
List<ConversationInfo> selectList = new ArrayList<>();
for (int i = 0; i < getItemCount() - 1; i++) {
ConversationInfo conversationInfo = getItem(i);
if (conversationInfo == null) {
continue;
}
if (isItemChecked(conversationInfo.getConversationId())) {
selectList.add(conversationInfo);
}
}
return selectList;
}
public void setSelectConversations(List<ConversationInfo> dataSource){
if(dataSource == null || dataSource.size() == 0){
mSelectedPositions.clear();
notifyDataSetChanged();
return;
}
mSelectedPositions.clear();
for (int i = 0; i < dataSource.size(); i++) {
for (int j =0; j<mDataSource.size(); j++){
if (TextUtils.equals(dataSource.get(i).getConversationId(), mDataSource.get(j).getConversationId())){
setItemChecked(mDataSource.get(j).getConversationId(), true);
notifyDataSetChanged();
break;
}
}
}
}
public void setOnConversationAdapterListener(OnConversationAdapterListener listener) {
this.mOnConversationAdapterListener = listener;
}
@Override
public void onDataSourceChanged(List<ConversationInfo> dataSource) {
this.mDataSource = dataSource;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ConversationBaseHolder holder = null;
// 创建不同的 ViewHolder
View view;
// 根据ViewType来创建条目
if (viewType == ITEM_TYPE_HEADER_HIDE) {
// 如果 searchView 不显示,添加一个隐藏的 view防止 recyclerview 自动滑到最底部
return new HeaderViewHolder(new View(parent.getContext()));
} else if (viewType == ConversationInfo.TYPE_CUSTOM) {
view = inflater.inflate(R.layout.conversation_custom_adapter, parent, false);
holder = new ConversationCustomHolder(view);
} else if (viewType == ITEM_TYPE_FOOTER_LOADING) {
view = inflater.inflate(R.layout.loading_progress_bar, parent, false);
return new FooterViewHolder(view);
} else if (viewType == ConversationInfo.TYPE_FORWAR_SELECT) {
view = inflater.inflate(R.layout.conversation_forward_select_adapter, parent, false);
return new ForwardSelectHolder(view);
} else if (viewType == ConversationInfo.TYPE_RECENT_LABEL) {
view = inflater.inflate(R.layout.conversation_forward_label_adapter, parent, false);
return new ForwardLabelHolder(view);
} else {
view = inflater.inflate(R.layout.minimalistui_conversation_list_item_layout, parent, false);
holder = new ConversationCommonHolder(view);
((ConversationCommonHolder) holder).setForwardMode(isForwardFragment);
((ConversationCommonHolder) holder).setShowFoldedStyle(showFoldedStyle);
}
holder.setAdapter(this);
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
final ConversationInfo conversationInfo = getItem(position);
ConversationBaseHolder baseHolder = null;
if (conversationInfo != null) {
baseHolder = (ConversationBaseHolder) holder;
}
switch (getItemViewType(position)) {
case ConversationInfo.TYPE_CUSTOM:
case ConversationInfo.TYPE_RECENT_LABEL:
break;
case ITEM_TYPE_FOOTER_LOADING: {
if (holder instanceof FooterViewHolder) {
((ConversationBaseHolder) holder).layoutViews(null, position);
}
break;
}
case ConversationInfo.TYPE_FORWAR_SELECT : {
ForwardSelectHolder selectHolder = (ForwardSelectHolder) holder;
selectHolder.refreshTitle(!isShowMultiSelectCheckBox);
setOnClickListener(holder, getItemViewType(position), conversationInfo);
break;
}
default: {
if (baseHolder instanceof ConversationCommonHolder) {
ConversationCommonHolder viewHolder = (ConversationCommonHolder) baseHolder;
viewHolder.swipeLayout.setShowMode(SwipeLayout.ShowMode.LayDown);
if (conversationInfo.isMarkFold()) {
viewHolder.swipeLayout.setOnDoubleClickListener(new SwipeLayout.DoubleClickListener() {
@Override
public void onDoubleClick(SwipeLayout layout, boolean surface) {
}
@Override
public void onClick() {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onItemClick(viewHolder.itemView, getItemViewType(position), conversationInfo);
}
}
});
viewHolder.markReadView.setVisibility(View.GONE);
viewHolder.moreView.setVisibility(View.GONE);
viewHolder.notDisplayView.setVisibility(View.VISIBLE);
viewHolder.notDisplayView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnConversationAdapterListener != null) {
mItemManger.removeShownLayouts(viewHolder.swipeLayout);
mOnConversationAdapterListener.onMarkConversationHidden(view, conversationInfo);
}
mItemManger.closeAllSwipeItems();
}
});
mItemManger.bind(viewHolder.itemView, position);
} else {
viewHolder.notDisplayView.setVisibility(View.GONE);
viewHolder.markReadView.setVisibility(View.VISIBLE);
viewHolder.moreView.setVisibility(View.VISIBLE);
viewHolder.swipeLayout.addSwipeListener(new SimpleSwipeListener() {
@Override
public void onOpen(SwipeLayout layout) {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onSwipeConversationChanged(conversationInfo);
}
}
@Override
public void onClose(SwipeLayout layout) {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onSwipeConversationChanged(null);
}
}
@Override
public void onStartOpen(SwipeLayout layout) {
int unReadNum = conversationInfo.getUnRead();
boolean isMarkUnread = conversationInfo.isMarkUnread();
if (unReadNum > 0) {
viewHolder.markReadTextView.setText(R.string.mark_read);
viewHolder.markReadView.setBackgroundColor(viewHolder.itemView.getResources().getColor(R.color.conversation_mark_swipe_bg));
viewHolder.markReadIconView.setBackgroundResource(R.drawable.conversation_minimalist_message_status_send_all_read);
} else {
if (isMarkUnread) {
viewHolder.markReadTextView.setText(R.string.mark_read);
viewHolder.markReadView.setBackgroundColor(viewHolder.itemView.getResources().getColor(R.color.conversation_mark_swipe_bg));
viewHolder.markReadIconView.setBackgroundResource(R.drawable.conversation_minimalist_message_status_send_all_read);
} else {
viewHolder.markReadTextView.setText(R.string.mark_unread);
viewHolder.markReadView.setBackgroundColor(viewHolder.itemView.getResources().getColor(R.color.conversation_mark_swipe_dark_bg));
viewHolder.markReadIconView.setBackgroundResource(R.drawable.conversation_minimalist_message_status_send_no_read);
}
}
}
});
viewHolder.swipeLayout.setOnDoubleClickListener(new SwipeLayout.DoubleClickListener() {
@Override
public void onDoubleClick(SwipeLayout layout, boolean surface) {
}
@Override
public void onClick() {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onItemClick(viewHolder.itemView, getItemViewType(position), conversationInfo);
}
}
});
viewHolder.markReadView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnConversationAdapterListener != null) {
boolean markRead = TUIConversationService.getAppContext().getString(R.string.mark_read).equals(viewHolder.markReadTextView.getText());
mOnConversationAdapterListener.onMarkConversationUnread(view, conversationInfo, !markRead);
}
mItemManger.closeAllSwipeItems();
}
});
viewHolder.moreView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onClickMoreView(view, conversationInfo);
}
mItemManger.closeAllSwipeItems();
}
});
mItemManger.bind(viewHolder.itemView, position);
}
} else {
setOnClickListener(holder, getItemViewType(position), conversationInfo);
}
}
}
if (baseHolder != null) {
baseHolder.layoutViews(conversationInfo, position);
setCheckBoxStatus(conversationInfo, position, baseHolder);
}
if (getCurrentPosition() == position && isClick()){
baseHolder.itemView.setBackgroundResource(R.color.conversation_item_clicked_color);
} else {
if (conversationInfo == null) {
return;
}
if (conversationInfo.isTop() && !isForwardFragment) {
baseHolder.itemView.setBackgroundColor(baseHolder.rootView.getResources().getColor(R.color.conversation_item_top_color));
} else {
baseHolder.itemView.setBackgroundColor(Color.WHITE);
}
}
}
private void setOnClickListener(RecyclerView.ViewHolder holder, int viewType, ConversationInfo conversationInfo) {
if (holder instanceof HeaderViewHolder) {
return;
}
//设置点击和长按事件
if (mOnConversationAdapterListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnConversationAdapterListener.onItemClick(view, viewType, conversationInfo);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mOnConversationAdapterListener.OnItemLongClick(view, conversationInfo);
int position = getIndexInAdapter(conversationInfo);
if (position != -1) {
setCurrentPosition(position, true);
notifyItemChanged(position);
}
return true;
}
});
}
}
// 设置多选框的选中状态和点击事件
private void setCheckBoxStatus(final ConversationInfo conversationInfo, int position, ConversationBaseHolder baseHolder) {
if (!(baseHolder instanceof ConversationCommonHolder) || ((ConversationCommonHolder) baseHolder).multiSelectCheckBox == null) {
return;
}
int viewType = getItemViewType(position);
String conversationId = conversationInfo.getConversationId();
ConversationCommonHolder commonHolder = (ConversationCommonHolder) baseHolder;
if (!isShowMultiSelectCheckBox || conversationInfo.isMarkFold()) {
commonHolder.multiSelectCheckBox.setVisibility(View.GONE);
baseHolder.itemView.setOnClickListener(null);
} else {
commonHolder.multiSelectCheckBox.setVisibility(View.VISIBLE);
//设置条目状态
commonHolder.multiSelectCheckBox.setChecked(isItemChecked(conversationId));
//checkBox的监听
commonHolder.multiSelectCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setItemChecked(conversationId, !isItemChecked(conversationId));
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onItemClick(v, viewType, conversationInfo);
}
}
});
//条目view的监听
baseHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setItemChecked(conversationId, !isItemChecked(conversationId));
int currentPosition = getIndexInAdapter(conversationInfo);
if (currentPosition != -1) {
notifyItemChanged(currentPosition);
}
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onItemClick(v, viewType, conversationInfo);
}
}
});
}
}
public int getIndexInAdapter(ConversationInfo conversationInfo) {
int position = -1;
if (mDataSource != null) {
int indexInData = mDataSource.indexOf(conversationInfo);
if (indexInData != -1) {
position = getItemIndexInAdapter(indexInData);
}
}
return position;
}
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
// ViewHolder 被回收时要清空头像 view 并且停止异步加载头像
if (holder instanceof ConversationCommonHolder) {
((ConversationCommonHolder) holder).conversationIconView.clearImage();
}
}
public ConversationInfo getItem(int position) {
if (mDataSource.isEmpty() || position == getItemCount() - 1) {
return null;
}
int dataPosition;
if (isForwardFragment) {
dataPosition = position - SELECT_COUNT - SELECT_LABEL_COUNT;
} else {
dataPosition = position - HEADER_COUNT;
}
if (dataPosition < mDataSource.size() && dataPosition >= 0) {
return mDataSource.get(dataPosition);
}
return null;
}
@Override
public int getItemCount() {
int listSize = mDataSource.size();
if (isForwardFragment) {
return listSize + SELECT_COUNT + SELECT_LABEL_COUNT + FOOTER_COUNT;
}
return listSize + HEADER_COUNT + FOOTER_COUNT;
}
@Override
public int getItemViewType(int position) {
if (isForwardFragment) {
if (position == 0) {
return ConversationInfo.TYPE_FORWAR_SELECT;
} else if (position == 1) {
return ConversationInfo.TYPE_RECENT_LABEL;
}
} else {
if (position == 0) {
return ITEM_TYPE_HEADER_HIDE;
}
}
if (position == getItemCount() - 1) {
return ITEM_TYPE_FOOTER_LOADING;
} else if (mDataSource != null) {
ConversationInfo conversationInfo = getItem(position);
if (conversationInfo != null) {
return conversationInfo.getType();
}
}
return ConversationInfo.TYPE_COMMON;
}
private int getItemIndexInAdapter(int index) {
int itemIndex;
if (isForwardFragment) {
itemIndex = index + SELECT_LABEL_COUNT + SELECT_COUNT;
} else {
itemIndex = index + HEADER_COUNT;
}
return itemIndex;
}
@Override
public void onItemRemoved(int position) {
int itemIndex = getItemIndexInAdapter(position);
notifyItemRemoved(itemIndex);
}
@Override
public void onItemInserted(int position) {
int itemIndex = getItemIndexInAdapter(position);
notifyItemInserted(itemIndex);
}
@Override
public void onItemChanged(int position) {
int itemIndex = getItemIndexInAdapter(position);
notifyItemChanged(itemIndex);
}
@Override
public void onItemRangeChanged(int startPosition, int count) {
int itemStartIndex = getItemIndexInAdapter(startPosition);
notifyItemRangeChanged(itemStartIndex, count);
}
@Override
public void onConversationChanged(List<ConversationInfo> conversationInfoList) {
if (mOnConversationAdapterListener != null) {
mOnConversationAdapterListener.onConversationChanged(conversationInfoList);
}
}
public void setItemTopTextSize(int size) {
mTopTextSize = size;
}
public int getItemTopTextSize() {
return mTopTextSize;
}
public void setItemBottomTextSize(int size) {
mBottomTextSize = size;
}
public int getItemBottomTextSize() {
return mBottomTextSize;
}
public void setItemDateTextSize(int size) {
mDateTextSize = size;
}
public int getItemDateTextSize() {
return mDateTextSize;
}
public void setItemAvatarRadius(int radius) {
mItemAvatarRadius = radius;
}
public int getItemAvatarRadius() {
return mItemAvatarRadius;
}
public void disableItemUnreadDot(boolean flag) {
mHasShowUnreadDot = !flag;
}
public boolean hasItemUnreadDot() {
return mHasShowUnreadDot;
}
@Override
public void onLoadingStateChanged(boolean isLoading) {
this.mIsLoading = isLoading;
notifyItemChanged(getItemCount() - 1);
}
@Override
public void onViewNeedRefresh() {
notifyDataSetChanged();
}
@Override
public int getSwipeLayoutResourceId(int position) {
return R.id.swipe;
}
//header
static class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(@NonNull View itemView) {
super(itemView);
}
}
//footer
class FooterViewHolder extends ConversationBaseHolder {
public FooterViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
public void layoutViews(ConversationInfo conversationInfo, int position) {
RecyclerView.LayoutParams param = (RecyclerView.LayoutParams) rootView.getLayoutParams();
if (mIsLoading) {
param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
param.width = LinearLayout.LayoutParams.MATCH_PARENT;
rootView.setVisibility(View.VISIBLE);
} else {
param.height = 0;
param.width = 0;
rootView.setVisibility(View.GONE);
}
rootView.setLayoutParams(param);
}
}
static class ForwardLabelHolder extends ConversationBaseHolder {
public ForwardLabelHolder(View itemView) {
super(itemView);
}
@Override
public void layoutViews(ConversationInfo conversationInfo, int position) {
}
}
static class ForwardSelectHolder extends ConversationBaseHolder {
private final TextView titleView;
public ForwardSelectHolder(View itemView) {
super(itemView);
titleView = itemView.findViewById(R.id.forward_title);
}
@Override
public void layoutViews(ConversationInfo conversationInfo, int position) {
}
public void refreshTitle(boolean isCreateGroup){
if (titleView == null)return;
if (isCreateGroup){
titleView.setText(TUIConversationService.getAppContext().getString(R.string.forward_select_new_chat));
} else {
titleView.setText(TUIConversationService.getAppContext().getString(R.string.forward_select_from_contact));
}
}
}
}

View File

@@ -0,0 +1,142 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import com.tencent.qcloud.tuicore.component.CustomLinearLayoutManager;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.IConversationListLayout;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
public class ConversationListLayout extends RecyclerView implements IConversationListLayout {
private ConversationListAdapter mAdapter;
private ConversationPresenter presenter;
private boolean isFolded = false;
public ConversationListLayout(Context context) {
super(context);
init();
}
public ConversationListLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ConversationListLayout(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setPresenter(ConversationPresenter presenter) {
this.presenter = presenter;
}
public void init() {
setLayoutFrozen(false);
setItemViewCacheSize(0);
setHasFixedSize(true);
setFocusableInTouchMode(false);
CustomLinearLayoutManager linearLayoutManager = new CustomLinearLayoutManager(getContext());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
setLayoutManager(linearLayoutManager);
SimpleItemAnimator animator = (SimpleItemAnimator) getItemAnimator();
if (animator != null) {
animator.setSupportsChangeAnimations(false);
}
}
@Override
public void setBackground(int resId) {
setBackgroundColor(resId);
}
@Override
public void disableItemUnreadDot(boolean flag) {
mAdapter.disableItemUnreadDot(flag);
}
@Override
public void setItemAvatarRadius(int radius) {
mAdapter.setItemAvatarRadius(radius);
}
@Override
public void setItemTopTextSize(int size) {
mAdapter.setItemTopTextSize(size);
}
@Override
public void setItemBottomTextSize(int size) {
mAdapter.setItemBottomTextSize(size);
}
@Override
public void setItemDateTextSize(int size) {
mAdapter.setItemDateTextSize(size);
}
@Override
public ConversationListLayout getListLayout() {
return this;
}
@Override
public ConversationListAdapter getAdapter() {
return mAdapter;
}
@Override
public void setAdapter(IConversationListAdapter adapter) {
if (adapter instanceof ConversationListAdapter) {
super.setAdapter((ConversationListAdapter) adapter);
mAdapter = (ConversationListAdapter) adapter;
}
}
@Override
public void setOnConversationAdapterListener(OnConversationAdapterListener listener){
mAdapter.setOnConversationAdapterListener(listener);
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if (state == RecyclerView.SCROLL_STATE_IDLE) {
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
if (layoutManager == null) {
return;
}
int lastPosition = layoutManager.findLastCompletelyVisibleItemPosition();
if (mAdapter != null) {
if (lastPosition == mAdapter.getItemCount() - 1 && !isLoadCompleted()) {
mAdapter.onLoadingStateChanged(true);
if (presenter != null) {
presenter.loadMoreConversation();
}
}
}
}
}
public void loadConversation(long nextSeq) {
if (presenter != null) {
presenter.loadConversation(nextSeq);
}
}
boolean isLoadCompleted(){
if (presenter != null) {
return presenter.isLoadFinished();
}
return false;
}
}

View File

@@ -0,0 +1,112 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.IConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationFoldPresenter;
public class FoldedConversationLayout extends RelativeLayout implements IConversationLayout {
private TitleBarLayout titleBarLayout;
private FoldedConversationListLayout conversationListLayout;
private ConversationFoldPresenter presenter;
public FoldedConversationLayout(Context context) {
super(context);
init();
}
public FoldedConversationLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FoldedConversationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setPresenter(ConversationFoldPresenter presenter) {
this.presenter = presenter;
if (conversationListLayout != null) {
conversationListLayout.setPresenter(presenter);
}
}
private void init() {
inflate(getContext(), R.layout.minimalist_folded_layout, this);
titleBarLayout = findViewById(R.id.conversation_title);
conversationListLayout = findViewById(R.id.folded_conversation_list);
}
public void initDefault() {
final ConversationListAdapter adapter = new ConversationListAdapter();
conversationListLayout.setAdapter((IConversationListAdapter) adapter);
adapter.setShowFoldedStyle(false);
if (presenter != null) {
presenter.setAdapter(adapter);
}
conversationListLayout.loadConversation();
}
@Override
public FoldedConversationListLayout getConversationList() {
return conversationListLayout;
}
@Override
public void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack) {
}
@Override
public void deleteConversation(ConversationInfo conversation) {
if (presenter != null) {
presenter.deleteConversation(conversation);
}
}
@Override
public void clearConversationMessage(ConversationInfo conversation) {
}
@Override
public void markConversationHidden(ConversationInfo conversation) {
if (presenter != null) {
presenter.markConversationHidden(conversation, true);
}
}
@Override
public void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread) {
if (presenter != null) {
presenter.markConversationUnread(conversationInfo, markUnread);
}
}
@Override
public void hideFoldedItem(boolean needHide) {
}
@Override
public void clearUnreadStatusOfFoldItem() {
}
@Override
public TitleBarLayout getTitleBar() {
return titleBarLayout;
}
@Override
public void setParentLayout(Object parent) {
}
}

View File

@@ -0,0 +1,114 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import com.tencent.qcloud.tuicore.component.CustomLinearLayoutManager;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.IConversationListLayout;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.OnConversationAdapterListener;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationFoldPresenter;
public class FoldedConversationListLayout extends RecyclerView implements IConversationListLayout {
private ConversationListAdapter mAdapter;
private ConversationFoldPresenter presenter;
private boolean isFolded = false;
public FoldedConversationListLayout(Context context) {
super(context);
init();
}
public FoldedConversationListLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public FoldedConversationListLayout(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setPresenter(ConversationFoldPresenter presenter) {
this.presenter = presenter;
}
public void init() {
setLayoutFrozen(false);
setItemViewCacheSize(0);
setHasFixedSize(true);
setFocusableInTouchMode(false);
CustomLinearLayoutManager linearLayoutManager = new CustomLinearLayoutManager(getContext());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
setLayoutManager(linearLayoutManager);
SimpleItemAnimator animator = (SimpleItemAnimator) getItemAnimator();
if (animator != null) {
animator.setSupportsChangeAnimations(false);
}
}
@Override
public void setBackground(int resId) {
setBackgroundColor(resId);
}
@Override
public void disableItemUnreadDot(boolean flag) {
mAdapter.disableItemUnreadDot(flag);
}
@Override
public void setItemAvatarRadius(int radius) {
mAdapter.setItemAvatarRadius(radius);
}
@Override
public void setItemTopTextSize(int size) {
mAdapter.setItemTopTextSize(size);
}
@Override
public void setItemBottomTextSize(int size) {
mAdapter.setItemBottomTextSize(size);
}
@Override
public void setItemDateTextSize(int size) {
mAdapter.setItemDateTextSize(size);
}
@Override
public FoldedConversationListLayout getListLayout() {
return this;
}
@Override
public ConversationListAdapter getAdapter() {
return mAdapter;
}
@Override
public void setAdapter(IConversationListAdapter adapter) {
if (adapter instanceof ConversationListAdapter) {
super.setAdapter((ConversationListAdapter) adapter);
mAdapter = (ConversationListAdapter) adapter;
}
}
@Override
public void setOnConversationAdapterListener(OnConversationAdapterListener listener) {
mAdapter.setOnConversationAdapterListener(listener);
}
public void loadConversation() {
if (presenter != null) {
presenter.loadConversation();
}
}
}

View File

@@ -0,0 +1,85 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import java.util.List;
public class ForwardConversationSelectorAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private Context context;
private List<ConversationInfo> list;
private OnItemClickListener mOnItemClickListener;
public ForwardConversationSelectorAdapter(Context context) {
this.context = context;
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
@NonNull
@Override
public ConversationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ConversationViewHolder(LayoutInflater.from(context).inflate(R.layout.minimalist_forward_conversation_selector_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
ConversationViewHolder viewHolder = (ConversationViewHolder) holder;
viewHolder.conversationUserIconView.setVisibility(View.VISIBLE);
viewHolder.conversationUserIconView.setConversation(list.get(position));
viewHolder.conversationUserIconView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onClick(v, position);
}
});
}
public void setDataSource(List<ConversationInfo> dataSource) {
if (dataSource == null) {
if (list != null) {
list.clear();
}
} else {
list = dataSource;
}
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mOnItemClickListener = listener;
}
public interface OnItemClickListener {
void onClick(View view, int position);
}
static class ConversationViewHolder extends RecyclerView.ViewHolder {
public ConversationIconView conversationUserIconView;
public ConversationViewHolder(View itemView) {
super(itemView);
conversationUserIconView = itemView.findViewById(R.id.conversation_user_icon_view);
}
}
}

View File

@@ -0,0 +1,106 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import com.tencent.qcloud.tuicore.component.TitleBarLayout;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.R;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.interfaces.IConversationLayout;
import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter;
public class ForwardSelectLayout extends RelativeLayout implements IConversationLayout {
private TitleBarLayout titleBarLayout;
private ConversationListLayout conversationList;
private ConversationPresenter presenter;
public ForwardSelectLayout(Context context) {
super(context);
init();
}
public ForwardSelectLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ForwardSelectLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setPresenter(ConversationPresenter presenter) {
this.presenter = presenter;
if (conversationList != null) {
conversationList.setPresenter(presenter);
}
}
/**
* 初始化相关UI元素
*/
private void init() {
inflate(getContext(), R.layout.minimalist_forward_layout, this);
titleBarLayout = findViewById(R.id.conversation_title);
conversationList = findViewById(R.id.conversation_list);
}
public void initDefault() {
final ConversationListAdapter adapter = new ConversationListAdapter();
adapter.setForwardFragment(true);
conversationList.setAdapter((IConversationListAdapter) adapter);
presenter.setAdapter(adapter);
presenter.loadConversation(0);
}
public TitleBarLayout getTitleBar() {
return titleBarLayout;
}
@Override
public void setParentLayout(Object parent) {
}
@Override
public ConversationListLayout getConversationList() {
return conversationList;
}
@Override
public void setConversationTop(ConversationInfo conversation, IUIKitCallback callBack) {
}
@Override
public void deleteConversation(ConversationInfo conversation) {
}
@Override
public void clearConversationMessage(ConversationInfo conversation) {
}
@Override
public void markConversationHidden(ConversationInfo conversation) {
}
@Override
public void hideFoldedItem(boolean needHide) {
}
@Override
public void clearUnreadStatusOfFoldItem() {
}
@Override
public void markConversationUnread(ConversationInfo conversationInfo, boolean markRead) {
}
}

View File

@@ -0,0 +1,172 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.PopupWindow;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.R;
import com.tencent.qcloud.tuicore.component.action.PopMenuAction;
import com.tencent.qcloud.tuicore.component.action.PopMenuAdapter;
import com.tencent.qcloud.tuicore.util.ScreenUtil;
import java.util.ArrayList;
import java.util.List;
public class Menu {
private static final int SHADOW_WIDTH = 10;
private static final int Y_OFFSET = 4;
private ListView mMenuList;
private PopMenuAdapter mMenuAdapter;
private PopupWindow mMenuWindow;
private List<PopMenuAction> mActions = new ArrayList<>();
private Activity mActivity;
private View mAttachView;
public Menu(Activity activity, View attach) {
mActivity = activity;
mAttachView = attach;
}
public void setMenuAction(List<PopMenuAction> menuActions) {
mActions.clear();
mActions.addAll(menuActions);
}
public boolean isShowing() {
if (mMenuWindow == null) {
return false;
}
return mMenuWindow.isShowing();
}
public void hide() {
mMenuWindow.dismiss();
}
public void show() {
if (mActions == null || mActions.size() == 0) {
return;
}
mMenuWindow = new PopupWindow(mActivity);
mMenuWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
mMenuWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
mMenuWindow.setBackgroundDrawable(new ColorDrawable());
mMenuAdapter = new PopMenuAdapter();
mMenuAdapter.setDataSource(mActions);
View menuView = LayoutInflater.from(mActivity).inflate(R.layout.core_pop_menu, null);
menuView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mMenuWindow.setContentView(menuView);
mMenuList = menuView.findViewById(R.id.menu_pop_list);
mMenuList.setAdapter(mMenuAdapter);
mMenuList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PopMenuAction action = (PopMenuAction) mMenuAdapter.getItem(position);
if (action != null && action.getActionClickListener() != null) {
action.getActionClickListener().onActionClick(position, mActions.get(position));
}
}
});
int paddingLeftRight = ScreenUtil.dip2px(15.0f);
int paddingTopBottom = ScreenUtil.dip2px(12.0f);
int itemWidth = mActivity.getResources().getDimensionPixelSize(R.dimen.core_pop_menu_item_width);
int itemHeight = mActivity.getResources().getDimensionPixelSize(R.dimen.core_pop_menu_item_height);
float anchorWidth = mAttachView.getWidth();
float anchorHeight = mAttachView.getHeight();
mMenuWindow.getContentView().measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int[] location = new int[2];
mAttachView.getLocationOnScreen(location);
int rowCount = mActions.size();
int indicatorHeight = mActivity.getResources().getDimensionPixelOffset(R.dimen.core_pop_menu_indicator_height);
int popWidth = itemWidth + paddingLeftRight * 2 - SHADOW_WIDTH;
int popHeight = itemHeight * rowCount + paddingTopBottom * 2 - SHADOW_WIDTH;
float indicatorX = anchorWidth / 2;
int screenWidth = ScreenUtil.getScreenWidth(mActivity);
int x = location[0];
int y;
float xOffset = anchorWidth / 2;
// If it is on the right, the x-coordinate of the small arrow and the x-position of the pop-up window will change
if (location[0] * 2 + anchorWidth > screenWidth) {
indicatorX = popWidth - anchorWidth / 2 - xOffset;
x = (int) (location[0] + anchorWidth - popWidth + xOffset);
}
y = (int) (location[1] + anchorHeight) + Y_OFFSET;
popHeight = popHeight - indicatorHeight;
Drawable backgroundDrawable = getBackgroundDrawable(popWidth, popHeight, indicatorX, indicatorHeight, 16);
menuView.setBackground(backgroundDrawable);
mMenuWindow.setFocusable(true);
mMenuWindow.setTouchable(true);
mMenuWindow.setOutsideTouchable(true);
mMenuWindow.showAtLocation(mAttachView, Gravity.NO_GRAVITY, x, y);
}
/**
* Draw a popup background with small triangles
*/
public Drawable getBackgroundDrawable(final float widthPixel, final float heightPixel, float indicatorX, float indicatorHeight, float radius) {
int borderWidth = SHADOW_WIDTH;
Path path = new Path();
Drawable drawable = new Drawable() {
@Override
public void draw(@NonNull Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
paint.setShadowLayer(borderWidth, 0,0,0xFFAAAAAA);
path.addRoundRect(new RectF(borderWidth, indicatorHeight + borderWidth, widthPixel - borderWidth, heightPixel + indicatorHeight - borderWidth), radius, radius, Path.Direction.CW);
path.moveTo(indicatorX - indicatorHeight, indicatorHeight + borderWidth);
path.lineTo(indicatorX, borderWidth);
path.lineTo(indicatorX + indicatorHeight, indicatorHeight + borderWidth);
path.close();
canvas.drawPath(path, paint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
};
return drawable;
}
}

View File

@@ -0,0 +1,9 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe;
public class Attributes {
public enum Mode {
Single, Multiple
}
}

View File

@@ -0,0 +1,84 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.Attributes;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeAdapterInterface;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeItemMangerImpl;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeItemMangerInterface;
import com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeLayout;
import java.util.List;
public abstract class RecyclerSwipeAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> implements SwipeItemMangerInterface, SwipeAdapterInterface {
public SwipeItemMangerImpl mItemManger = new SwipeItemMangerImpl(this);
@Override
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
@Override
public abstract void onBindViewHolder(VH viewHolder, final int position);
@Override
public void notifyDatasetChanged() {
super.notifyDataSetChanged();
}
@Override
public void openItem(int position) {
mItemManger.openItem(position);
}
@Override
public void closeItem(int position) {
mItemManger.closeItem(position);
}
@Override
public void closeAllExcept(SwipeLayout layout) {
mItemManger.closeAllExcept(layout);
}
@Override
public void closeAllSwipeItems() {
mItemManger.closeAllSwipeItems();
}
@Override
public List<Integer> getOpenItems() {
return mItemManger.getOpenItems();
}
@Override
public List<SwipeLayout> getOpenLayouts() {
return mItemManger.getOpenLayouts();
}
@Override
public void removeShownLayouts(SwipeLayout layout) {
mItemManger.removeShownLayouts(layout);
}
@Override
public boolean isOpen(int position) {
return mItemManger.isOpen(position);
}
@Override
public Attributes.Mode getMode() {
return mItemManger.getMode();
}
@Override
public void setMode(Attributes.Mode mode) {
mItemManger.setMode(mode);
}
@Override
public void switchAllSwipeEnable(boolean enable) {
mItemManger.switchAllSwipeEnable(enable);
}
}

View File

@@ -0,0 +1,28 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe;
public class SimpleSwipeListener implements SwipeLayout.SwipeListener {
@Override
public void onStartOpen(SwipeLayout layout) {
}
@Override
public void onOpen(SwipeLayout layout) {
}
@Override
public void onStartClose(SwipeLayout layout) {
}
@Override
public void onClose(SwipeLayout layout) {
}
@Override
public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset) {
}
@Override
public void onHandRelease(SwipeLayout layout, float xvel, float yvel) {
}
}

View File

@@ -0,0 +1,9 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe;
public interface SwipeAdapterInterface {
int getSwipeLayoutResourceId(int position);
void notifyDatasetChanged();
}

View File

@@ -0,0 +1,213 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe;
import android.view.View;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SwipeItemMangerImpl implements SwipeItemMangerInterface {
private Attributes.Mode mode = Attributes.Mode.Single;
public final int INVALID_POSITION = -1;
protected int mOpenPosition = INVALID_POSITION;
protected Set<Integer> mOpenPositions = new HashSet<Integer>();
protected Set<SwipeLayout> mShownLayouts = new HashSet<SwipeLayout>();
protected SwipeAdapterInterface swipeAdapterInterface;
public SwipeItemMangerImpl(SwipeAdapterInterface swipeAdapterInterface) {
if (swipeAdapterInterface == null)
throw new IllegalArgumentException("SwipeAdapterInterface can not be null");
this.swipeAdapterInterface = swipeAdapterInterface;
}
public Attributes.Mode getMode() {
return mode;
}
public void setMode(Attributes.Mode mode) {
this.mode = mode;
mOpenPositions.clear();
mShownLayouts.clear();
mOpenPosition = INVALID_POSITION;
}
public void bind(View view, int position) {
int resId = swipeAdapterInterface.getSwipeLayoutResourceId(position);
SwipeLayout swipeLayout = (SwipeLayout) view.findViewById(resId);
if (swipeLayout == null)
throw new IllegalStateException("can not find SwipeLayout in target view");
if (swipeLayout.getTag(resId) == null) {
OnLayoutListener onLayoutListener = new OnLayoutListener(position);
SwipeMemory swipeMemory = new SwipeMemory(position);
swipeLayout.addSwipeListener(swipeMemory);
swipeLayout.addOnLayoutListener(onLayoutListener);
swipeLayout.setTag(resId, new ValueBox(position, swipeMemory, onLayoutListener));
mShownLayouts.add(swipeLayout);
} else {
ValueBox valueBox = (ValueBox) swipeLayout.getTag(resId);
valueBox.swipeMemory.setPosition(position);
valueBox.onLayoutListener.setPosition(position);
valueBox.position = position;
}
}
@Override
public void openItem(int position) {
if (mode == Attributes.Mode.Multiple) {
if (!mOpenPositions.contains(position))
mOpenPositions.add(position);
} else {
mOpenPosition = position;
}
swipeAdapterInterface.notifyDatasetChanged();
}
@Override
public void closeItem(int position) {
if (mode == Attributes.Mode.Multiple) {
mOpenPositions.remove(position);
} else {
if (mOpenPosition == position)
mOpenPosition = INVALID_POSITION;
}
swipeAdapterInterface.notifyDatasetChanged();
}
@Override
public void closeAllExcept(SwipeLayout layout) {
for (SwipeLayout s : mShownLayouts) {
if (s != layout)
s.close();
}
}
@Override
public void closeAllSwipeItems() {
if (mode == Attributes.Mode.Multiple) {
mOpenPositions.clear();
} else {
mOpenPosition = INVALID_POSITION;
}
for (SwipeLayout s : mShownLayouts) {
s.close();
}
}
@Override
public void switchAllSwipeEnable(boolean enable) {
for (SwipeLayout s : mShownLayouts) {
s.setSwipeEnabled(enable);
}
}
@Override
public void removeShownLayouts(SwipeLayout layout) {
mShownLayouts.remove(layout);
}
@Override
public List<Integer> getOpenItems() {
if (mode == Attributes.Mode.Multiple) {
return new ArrayList<Integer>(mOpenPositions);
} else {
return Collections.singletonList(mOpenPosition);
}
}
@Override
public List<SwipeLayout> getOpenLayouts() {
return new ArrayList<SwipeLayout>(mShownLayouts);
}
@Override
public boolean isOpen(int position) {
if (mode == Attributes.Mode.Multiple) {
return mOpenPositions.contains(position);
} else {
return mOpenPosition == position;
}
}
class ValueBox {
OnLayoutListener onLayoutListener;
SwipeMemory swipeMemory;
int position;
ValueBox(int position, SwipeMemory swipeMemory, OnLayoutListener onLayoutListener) {
this.swipeMemory = swipeMemory;
this.onLayoutListener = onLayoutListener;
this.position = position;
}
}
class OnLayoutListener implements SwipeLayout.OnLayout {
private int position;
OnLayoutListener(int position) {
this.position = position;
}
public void setPosition(int position) {
this.position = position;
}
@Override
public void onLayout(SwipeLayout v) {
if (isOpen(position)) {
v.open(false, false);
} else {
v.close(false, false);
}
}
}
class SwipeMemory extends SimpleSwipeListener {
private int position;
SwipeMemory(int position) {
this.position = position;
}
@Override
public void onClose(SwipeLayout layout) {
if (mode == Attributes.Mode.Multiple) {
mOpenPositions.remove(position);
} else {
mOpenPosition = INVALID_POSITION;
}
}
@Override
public void onStartOpen(SwipeLayout layout) {
if (mode == Attributes.Mode.Single) {
closeAllExcept(layout);
}
}
@Override
public void onOpen(SwipeLayout layout) {
if (mode == Attributes.Mode.Multiple)
mOpenPositions.add(position);
else {
closeAllExcept(layout);
mOpenPosition = position;
}
}
public void setPosition(int position) {
this.position = position;
}
}
}

View File

@@ -0,0 +1,28 @@
package com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe;
import java.util.List;
public interface SwipeItemMangerInterface {
void openItem(int position);
void closeItem(int position);
void closeAllExcept(SwipeLayout layout);
void closeAllSwipeItems();
List<Integer> getOpenItems();
List<SwipeLayout> getOpenLayouts();
void removeShownLayouts(SwipeLayout layout);
boolean isOpen(int position);
Attributes.Mode getMode();
void setMode(Attributes.Mode mode);
void switchAllSwipeEnable(boolean enable);
}

View File

@@ -0,0 +1,489 @@
package com.tencent.qcloud.tuikit.tuiconversation.model;
import android.text.TextUtils;
import android.view.View;
import com.tencent.imsdk.BaseConstants;
import com.tencent.imsdk.v2.V2TIMCallback;
import com.tencent.imsdk.v2.V2TIMConversation;
import com.tencent.imsdk.v2.V2TIMConversationListFilter;
import com.tencent.imsdk.v2.V2TIMConversationOperationResult;
import com.tencent.imsdk.v2.V2TIMConversationResult;
import com.tencent.imsdk.v2.V2TIMGroupMemberFullInfo;
import com.tencent.imsdk.v2.V2TIMGroupMemberInfoResult;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMUserStatus;
import com.tencent.imsdk.v2.V2TIMValueCallback;
import com.tencent.qcloud.tuicore.BuildConfig;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter;
import com.tencent.qcloud.tuicore.util.ToastUtil;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationService;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.config.TUIConversationConfig;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.ConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class ConversationProvider {
private static final String TAG = ConversationProvider.class.getSimpleName();
private boolean isFinished = false;
private long nextLoadSeq = 0L;
private List<ConversationInfo> markConversationInfoList = new ArrayList<>();
private HashMap<String, V2TIMConversation> markUnreadMap = new HashMap<>();
public void loadConversation(long startSeq, int loadCount, final IUIKitCallback<List<ConversationInfo>> callBack) {
isFinished = false;
nextLoadSeq = 0;
V2TIMManager.getConversationManager().getConversationList(startSeq, loadCount, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onError(int code, String desc) {
TUIConversationLog.v(TAG, "loadConversation getConversationList error, code = " + code + ", desc = " + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callBack, TAG, code, desc);
}
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
List<V2TIMConversation> v2TIMConversationList = v2TIMConversationResult.getConversationList();
List<ConversationInfo> conversationInfoList = ConversationUtils.convertV2TIMConversationList(v2TIMConversationList);
isFinished = v2TIMConversationResult.isFinished();
nextLoadSeq = v2TIMConversationResult.getNextSeq();
TUIConversationUtils.callbackOnSuccess(callBack, conversationInfoList);
}
});
}
public void loadMoreConversation(int loadCount, IUIKitCallback<List<ConversationInfo>> callBack) {
if (isFinished) {
return;
}
loadConversation(nextLoadSeq, loadCount, callBack);
}
public boolean isLoadFinished() {
return isFinished;
}
public void getConversation(String conversationID, IUIKitCallback<ConversationInfo> callback) {
V2TIMManager.getConversationManager().getConversation(conversationID, new V2TIMValueCallback<V2TIMConversation>() {
@Override
public void onSuccess(V2TIMConversation v2TIMConversation) {
ConversationInfo conversationInfo = ConversationUtils.convertV2TIMConversation(v2TIMConversation);
TUIConversationUtils.callbackOnSuccess(callback, conversationInfo);
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.v(TAG, "getConversation error, code = " + code + ", desc = " + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callback, TAG, code, desc);
}
});
}
public void getTotalUnreadMessageCount(IUIKitCallback<Long> callBack) {
// 更新消息未读总数
V2TIMManager.getConversationManager().getTotalUnreadMessageCount(new V2TIMValueCallback<Long>() {
@Override
public void onSuccess(Long count) {
TUIConversationUtils.callbackOnSuccess(callBack, count);
}
@Override
public void onError(int code, String desc) {
}
});
}
public void setConversationTop(String conversationId, boolean isTop, IUIKitCallback<Void> callBack) {
V2TIMManager.getConversationManager().pinConversation(conversationId, isTop, new V2TIMCallback() {
@Override
public void onSuccess() {
TUIConversationUtils.callbackOnSuccess(callBack, null);
}
@Override
public void onError(int code, String desc) {
TUIConversationUtils.callbackOnError(callBack, TAG, code, desc);
}
});
}
public void markConversationFold(String conversationID, boolean isFold, IUIKitCallback<Void> callback) {
List<String> conversationIDList = new ArrayList<>();
conversationIDList.add(conversationID);
V2TIMManager.getConversationManager().markConversation(conversationIDList,
V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_FOLD, isFold,
new V2TIMValueCallback<List<V2TIMConversationOperationResult>>() {
@Override
public void onSuccess(List<V2TIMConversationOperationResult> v2TIMConversationOperationResults) {
if (v2TIMConversationOperationResults.size() == 0) {
return;
}
V2TIMConversationOperationResult result = v2TIMConversationOperationResults.get(0);
if (result.getResultCode() == BaseConstants.ERR_SUCC) {
TUIConversationUtils.callbackOnSuccess(callback, null);
} else {
TUIConversationUtils.callbackOnError(callback, TAG, result.getResultCode(), result.getResultInfo());
}
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "markConversationFold error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callback, TAG, code, desc);
}
});
}
public void markConversationHidden(String conversationID, boolean isHidden, IUIKitCallback<Void> callback) {
List<String> conversationIDList = new ArrayList<>();
if (!TextUtils.isEmpty(conversationID)) {
conversationIDList.add(conversationID);
}
V2TIMManager.getConversationManager().markConversation(conversationIDList,
V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_HIDE, isHidden, new V2TIMValueCallback<List<V2TIMConversationOperationResult>>() {
@Override
public void onSuccess(List<V2TIMConversationOperationResult> v2TIMConversationOperationResults) {
if (v2TIMConversationOperationResults.size() == 0) {
return;
}
V2TIMConversationOperationResult result = v2TIMConversationOperationResults.get(0);
if (result.getResultCode() == BaseConstants.ERR_SUCC) {
TUIConversationUtils.callbackOnSuccess(callback, null);
} else {
TUIConversationUtils.callbackOnError(callback, TAG, result.getResultCode(), result.getResultInfo());
}
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "markConversationHidden error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callback, TAG, code, desc);
}
});
}
public void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread, IUIKitCallback<Void> callback) {
List<String> conversationIDList = new ArrayList<>();
if (!TextUtils.isEmpty(conversationInfo.getConversationId())) {
conversationIDList.add(conversationInfo.getConversationId());
}
if (!markUnread && conversationInfo.getUnRead() > 0) {
if (conversationInfo.isGroup()) {
V2TIMManager.getMessageManager().markGroupMessageAsRead(conversationInfo.getId(), new V2TIMCallback() {
@Override
public void onSuccess() {
TUIConversationLog.i(TAG, "markConversationUnread->markGroupMessageAsRead success");
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "markConversationUnread error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
}
});
} else {
V2TIMManager.getMessageManager().markC2CMessageAsRead(conversationInfo.getId(), new V2TIMCallback() {
@Override
public void onSuccess() {
TUIConversationLog.i(TAG, "markConversationUnread->markC2CMessageAsRead success");
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "markConversationUnread error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
}
});
}
}
if (markUnread != conversationInfo.isMarkUnread()) {
V2TIMManager.getConversationManager().markConversation(conversationIDList, V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_UNREAD, markUnread, new V2TIMValueCallback<List<V2TIMConversationOperationResult>>() {
@Override
public void onSuccess(List<V2TIMConversationOperationResult> v2TIMConversationOperationResults) {
if (v2TIMConversationOperationResults.size() == 0) {
return;
}
V2TIMConversationOperationResult result = v2TIMConversationOperationResults.get(0);
if (result.getResultCode() == BaseConstants.ERR_SUCC) {
TUIConversationUtils.callbackOnSuccess(callback, null);
} else {
TUIConversationUtils.callbackOnError(callback, TAG, result.getResultCode(), result.getResultInfo());
}
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "markConversationUnread error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callback, TAG, code, desc);
}
});
}
}
public void deleteConversation(String conversationId, IUIKitCallback<Void> callBack) {
V2TIMManager.getConversationManager().deleteConversation(conversationId, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "deleteConversation error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callBack, TAG, code, desc);
}
@Override
public void onSuccess() {
TUIConversationLog.i(TAG, "deleteConversation success");
TUIConversationUtils.callbackOnSuccess(callBack, null);
}
});
}
public void clearHistoryMessage(String userId, boolean isGroup, IUIKitCallback<Void> callBack) {
if (isGroup) {
V2TIMManager.getMessageManager().clearGroupHistoryMessage(userId, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "clearConversationMessage error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callBack, TAG, code, desc);
}
@Override
public void onSuccess() {
TUIConversationLog.i(TAG, "clearConversationMessage success");
TUIConversationUtils.callbackOnSuccess(callBack, null);
}
});
} else {
V2TIMManager.getMessageManager().clearC2CHistoryMessage(userId, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "clearConversationMessage error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callBack, TAG, code, desc);
}
@Override
public void onSuccess() {
TUIConversationLog.i(TAG, "clearConversationMessage success");
TUIConversationUtils.callbackOnSuccess(callBack, null);
}
});
}
}
public void getGroupMemberIconList(String groupId, int iconCount, IUIKitCallback<List<Object>> callback) {
V2TIMManager.getGroupManager().getGroupMemberList(groupId, V2TIMGroupMemberFullInfo.V2TIM_GROUP_MEMBER_FILTER_ALL, 0, new V2TIMValueCallback<V2TIMGroupMemberInfoResult>() {
@Override
public void onError(int code, String desc) {
TUIConversationUtils.callbackOnError(callback, code, desc);
TUIConversationLog.e("ConversationIconView", "getGroupMemberList failed! groupID:" + groupId + "|code:" + code + "|desc: " + ErrorMessageConverter.convertIMError(code, desc));
}
@Override
public void onSuccess(V2TIMGroupMemberInfoResult v2TIMGroupMemberInfoResult) {
List<V2TIMGroupMemberFullInfo> v2TIMGroupMemberFullInfoList = v2TIMGroupMemberInfoResult.getMemberInfoList();
int faceSize = Math.min(v2TIMGroupMemberFullInfoList.size(), iconCount);
final List<Object> urlList = new ArrayList<>();
for (int i = 0; i < faceSize; i++) {
V2TIMGroupMemberFullInfo v2TIMGroupMemberFullInfo = v2TIMGroupMemberFullInfoList.get(i);
urlList.add(v2TIMGroupMemberFullInfo.getFaceUrl());
}
TUIConversationUtils.callbackOnSuccess(callback, urlList);
}
});
}
public void loadConversationUserStatus(List<ConversationInfo> dataSource, IUIKitCallback<Void> callback) {
if (dataSource == null || dataSource.size() == 0) {
TUIConversationLog.d(TAG, "loadConversationUserStatus datasource is null");
return;
}
HashMap<String, ConversationInfo> dataSourceMap = new HashMap<>();
List<String> userList = new ArrayList<>();
for(ConversationInfo itemBean : dataSource) {
if (itemBean.isGroup()) {
continue;
}
userList.add(itemBean.getId());
dataSourceMap.put(itemBean.getId(), itemBean);
}
if (userList.isEmpty()) {
TUIConversationLog.d(TAG, "loadConversationUserStatus userList is empty");
return;
}
V2TIMManager.getInstance().getUserStatus(userList, new V2TIMValueCallback<List<V2TIMUserStatus>>() {
@Override
public void onSuccess(List<V2TIMUserStatus> v2TIMUserStatuses) {
TUIConversationLog.i(TAG, "getUserStatus success");
for (V2TIMUserStatus item : v2TIMUserStatuses) {
ConversationInfo bean = dataSourceMap.get(item.getUserID());
if (bean != null) {
bean.setStatusType(item.getStatusType());
}
}
TUIConversationUtils.callbackOnSuccess(callback, null);
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "getUserStatus error code = " + code + ",des = " + desc);
TUIConversationUtils.callbackOnError(callback, code, desc);
if (code == TUIConstants.BuyingFeature.ERR_SDK_INTERFACE_NOT_SUPPORT &&
TUIConversationConfig.getInstance().isShowUserStatus() && BuildConfig.DEBUG) {
ToastUtil.toastLongMessage(desc);
}
}
});
}
public void subscribeConversationUserStatus(List<String> userIdList, IUIKitCallback<Void> callback) {
if (userIdList == null || userIdList.size() == 0) {
TUIConversationLog.e(TAG, "subscribeConversationUserStatus userId is null");
TUIConversationUtils.callbackOnError(callback, BaseConstants.ERR_INVALID_PARAMETERS, "userid list is null");
return;
}
V2TIMManager.getInstance().subscribeUserStatus(userIdList, new V2TIMCallback() {
@Override
public void onSuccess() {
TUIConversationUtils.callbackOnSuccess(callback, null);
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "subscribeConversationUserStatus error code = " + code + ",des = " + desc);
TUIConversationUtils.callbackOnError(callback, code, desc);
}
});
}
public void getMarkConversationList(final V2TIMConversationListFilter filter, boolean fromStart, IUIKitCallback<List<ConversationInfo>> callback) {
if (fromStart) {
markConversationInfoList.clear();
}
V2TIMManager.getConversationManager().getConversationListByFilter(filter, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
List<V2TIMConversation> conversationList = v2TIMConversationResult.getConversationList();
List<ConversationInfo> conversationInfoList = ConversationUtils.convertV2TIMConversationList(conversationList);
markConversationInfoList.addAll(conversationInfoList);
if (!v2TIMConversationResult.isFinished()) {
getMarkConversationList(filter, false, callback);
} else {
if (callback != null) {
callback.onSuccess(markConversationInfoList);
}
}
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "getMarkConversationList error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
}
});
}
public void clearAllUnreadMessage(IUIKitCallback<Void> callback) {
V2TIMManager.getMessageManager().markAllMessageAsRead(new V2TIMCallback() {
@Override
public void onSuccess() {
TUIConversationLog.i(TAG, "markAllMessageAsRead success");
TUIConversationUtils.callbackOnSuccess(callback, null);
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.i(TAG, "markAllMessageAsRead error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callback, code, desc);
}
});
V2TIMConversationListFilter filter = new V2TIMConversationListFilter();
filter.setCount(100);
filter.setMarkType(V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_UNREAD);
filter.setNextSeq(0);
getMarkUnreadConversationList(filter, true, new V2TIMValueCallback<HashMap<String, V2TIMConversation>>() {
@Override
public void onSuccess(HashMap<String, V2TIMConversation> stringV2TIMConversationHashMap) {
if (stringV2TIMConversationHashMap.size() == 0) {
return;
}
List<String> unreadConversationIDList = new ArrayList<>();
Iterator<Map.Entry<String, V2TIMConversation>> iterator = markUnreadMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, V2TIMConversation> entry = iterator.next();
unreadConversationIDList.add(entry.getKey());
}
V2TIMManager.getConversationManager().markConversation(unreadConversationIDList,
V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_UNREAD,
false,
new V2TIMValueCallback<List<V2TIMConversationOperationResult>>() {
@Override
public void onSuccess(List<V2TIMConversationOperationResult> v2TIMConversationOperationResults) {
for (V2TIMConversationOperationResult result : v2TIMConversationOperationResults) {
if (result.getResultCode() == BaseConstants.ERR_SUCC) {
V2TIMConversation v2TIMConversation = markUnreadMap.get(result.getConversationID());
if (!v2TIMConversation.getMarkList().contains(V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_HIDE)) {
markUnreadMap.remove(result.getConversationID());
}
}
}
TUIConversationUtils.callbackOnSuccess(callback, null);
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "triggerClearAllUnreadMessage->markConversation error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
TUIConversationUtils.callbackOnError(callback, code, desc);
}
});
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "triggerClearAllUnreadMessage->getMarkUnreadConversationList error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
}
});
}
private void getMarkUnreadConversationList(V2TIMConversationListFilter filter, boolean fromStart, V2TIMValueCallback<HashMap<String, V2TIMConversation>> callback) {
if (fromStart) {
markUnreadMap.clear();
}
V2TIMManager.getConversationManager().getConversationListByFilter(filter, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
List<V2TIMConversation> conversationList = v2TIMConversationResult.getConversationList();
for (V2TIMConversation conversation : conversationList) {
markUnreadMap.put(conversation.getConversationID(), conversation);
}
if (!v2TIMConversationResult.isFinished()) {
getMarkUnreadConversationList(filter, false, callback);
} else {
if (callback != null) {
callback.onSuccess(markUnreadMap);
}
}
}
@Override
public void onError(int code, String desc) {
TUIConversationLog.e(TAG, "getMarkUnreadConversationList error:" + code + ", desc:" + ErrorMessageConverter.convertIMError(code, desc));
}
});
}
}

View File

@@ -0,0 +1,464 @@
package com.tencent.qcloud.tuikit.tuiconversation.presenter;
import android.text.TextUtils;
import com.tencent.imsdk.v2.V2TIMConversation;
import com.tencent.imsdk.v2.V2TIMConversationListFilter;
import com.tencent.imsdk.v2.V2TIMUserStatus;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.TUIConversationService;
import com.tencent.qcloud.tuikit.tuiconversation.bean.ConversationInfo;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.ConversationUtils;
import com.tencent.qcloud.tuikit.tuiconversation.commonutil.TUIConversationLog;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.ConversationEventListener;
import com.tencent.qcloud.tuikit.tuiconversation.interfaces.IConversationListAdapter;
import com.tencent.qcloud.tuikit.tuiconversation.model.ConversationProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
public class ConversationFoldPresenter {
private static final String TAG = ConversationFoldPresenter.class.getSimpleName();
private final static int GET_CONVERSATION_COUNT = 100;
ConversationEventListener conversationEventForMarkObserver;
private final ConversationProvider provider;
private IConversationListAdapter adapter;
private final List<ConversationInfo> loadedConversationInfoList = new ArrayList<>();
public ConversationFoldPresenter() {
provider = new ConversationProvider();
}
public void setAdapter(IConversationListAdapter adapter) {
this.adapter = adapter;
}
public void initListener() {
conversationEventForMarkObserver = new ConversationEventListener() {
@Override
public void deleteConversation(String chatId, boolean isGroup) {
ConversationFoldPresenter.this.deleteConversationFromUI(chatId, isGroup);
}
@Override
public void clearConversationMessage(String chatId, boolean isGroup) {
}
@Override
public void clearFoldMarkAndDeleteConversation(String conversationId) {
ConversationFoldPresenter.this.deleteConversationFromUI(conversationId);
}
@Override
public void setConversationTop(String chatId, boolean isChecked, IUIKitCallback<Void> iuiKitCallBack) {
}
@Override
public boolean isTopConversation(String chatId) {
return false;
}
@Override
public long getUnreadTotal() {
return 0;
}
@Override
public void onSyncServerFinish() {
}
@Override
public void updateTotalUnreadMessageCount(long count) {
}
@Override
public void onNewConversation(List<ConversationInfo> conversationList) {
ConversationFoldPresenter.this.onNewConversation(conversationList);
}
@Override
public void onConversationChanged(List<ConversationInfo> conversationList) {
ConversationFoldPresenter.this.onConversationChanged(conversationList);
}
@Override
public void onFriendRemarkChanged(String id, String remark) {
}
@Override
public void onUserStatusChanged(List<V2TIMUserStatus> userStatusList) {
}
@Override
public void refreshUserStatusFragmentUI() {
}
@Override
public void onReceiveMessage(String conversationID, boolean isTypingMessage) {
processNewMessage(conversationID, isTypingMessage);
}
@Override
public void onMessageSendForHideConversation(String conversationID) {
}
};
TUIConversationService.getInstance().addConversationEventListener(conversationEventForMarkObserver);
}
public void loadConversation() {
TUIConversationLog.i(TAG, "loadConversation");
V2TIMConversationListFilter filter = new V2TIMConversationListFilter();
filter.setCount(GET_CONVERSATION_COUNT);
long markType = V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_FOLD;
filter.setMarkType(markType);
filter.setNextSeq(0);
provider.getMarkConversationList(filter, true, new IUIKitCallback<List<ConversationInfo>>() {
@Override
public void onSuccess(List<ConversationInfo> conversationInfoList) {
if (conversationInfoList.size() == 0) {
return;
}
Collections.sort(conversationInfoList);
List<ConversationInfo> loadList = new ArrayList<>();
for (ConversationInfo conversationInfo : conversationInfoList) {
if (!conversationInfo.isMarkHidden()) {
loadList.add(conversationInfo);
}
}
onLoadConversationCompleted(loadList);
}
@Override
public void onError(String module, int errCode, String errMsg) {
TUIConversationLog.e(TAG, "loadConversation error:" + errCode + ", " + errMsg);
if (adapter != null) {
adapter.onLoadingStateChanged(false);
}
}
});
}
private void onLoadConversationCompleted(List<ConversationInfo> conversationInfoList) {
onNewConversation(conversationInfoList);
if (adapter != null) {
adapter.onLoadingStateChanged(false);
}
}
/**
* 有新的会话
* @param conversationInfoList 新的会话列表
*/
public void onNewConversation(List<ConversationInfo> conversationInfoList) {
TUIConversationLog.i(TAG, "onNewConversation conversations:" + conversationInfoList);
if (conversationInfoList.size() == 0) {
return;
}
ArrayList<ConversationInfo> processedInfoList = processFoldedAndHiddenConversation(conversationInfoList);
List<ConversationInfo> exists = new ArrayList<>();
Iterator<ConversationInfo> iterator = processedInfoList.iterator();
while (iterator.hasNext()) {
ConversationInfo update = iterator.next();
for (int i = 0; i < loadedConversationInfoList.size(); i++) {
ConversationInfo cacheInfo = loadedConversationInfoList.get(i);
// 去重
if (cacheInfo.getConversationId().equals(update.getConversationId())) {
loadedConversationInfoList.set(i, update);
iterator.remove();
exists.add(update);
break;
}
}
}
// 对新增会话排序,避免插入 recyclerview 时错乱
Collections.sort(processedInfoList);
loadedConversationInfoList.addAll(processedInfoList);
if (adapter != null) {
Collections.sort(loadedConversationInfoList);
adapter.onDataSourceChanged(loadedConversationInfoList);
for (ConversationInfo info : processedInfoList) {
int index = loadedConversationInfoList.indexOf(info);
if (index != -1) {
adapter.onItemInserted(index);
}
}
for (ConversationInfo info : exists) {
int index = loadedConversationInfoList.indexOf(info);
if (index != -1) {
adapter.onItemChanged(index);
}
}
}
}
public void onConversationChanged(List<ConversationInfo> conversationInfoList) {
TUIConversationLog.i(TAG, "onConversationChanged conversations:" + conversationInfoList);
ArrayList<ConversationInfo> addInfoList = new ArrayList<>();
ArrayList<ConversationInfo> infoList = processFoldedAndHiddenConversation(conversationInfoList);
ArrayList<ConversationInfo> changedInfoList = new ArrayList<>();
for (ConversationInfo conversationInfo : infoList) {
if (!ConversationUtils.isIgnored(conversationInfo)) {
boolean exists = false;
for (ConversationInfo loadedInfo : loadedConversationInfoList) {
if (TextUtils.equals(conversationInfo.getConversationId(), loadedInfo.getConversationId())) {
exists = true;
break;
}
}
if (exists) {
TUIConversationLog.i(TAG, "onConversationChanged conversationInfo " + conversationInfo);
changedInfoList.add(conversationInfo);
} else {
addInfoList.add(conversationInfo);
}
}
}
if (!addInfoList.isEmpty()) {
onNewConversation(addInfoList);
}
if (changedInfoList.size() == 0) {
return;
}
refreshChangedInfo(loadedConversationInfoList, changedInfoList);
}
private void refreshChangedInfo(List<ConversationInfo> uiSourceInfoList,
ArrayList<ConversationInfo> changedInfoList) {
Collections.sort(changedInfoList);
HashMap<ConversationInfo, Integer> indexMap = new HashMap<>();
for (int j = 0; j < changedInfoList.size(); j++) {
ConversationInfo update = changedInfoList.get(j);
for (int i = 0; i < uiSourceInfoList.size(); i++) {
ConversationInfo cacheInfo = uiSourceInfoList.get(i);
//单个会话刷新时找到老的会话数据,替换
if (cacheInfo.getConversationId().equals(update.getConversationId())) {
if (update.getStatusType() == V2TIMUserStatus.V2TIM_USER_STATUS_UNKNOWN) {
update.setStatusType(cacheInfo.getStatusType());
}
uiSourceInfoList.set(i, update);
indexMap.put(update, i);
break;
}
}
}
if (adapter != null) {
Collections.sort(uiSourceInfoList);
adapter.onDataSourceChanged(uiSourceInfoList);
int minRefreshIndex = Integer.MAX_VALUE;
int maxRefreshIndex = Integer.MIN_VALUE;
for (ConversationInfo info : changedInfoList) {
Integer oldIndexObj = indexMap.get(info);
if (oldIndexObj == null) {
continue;
}
int oldIndex = oldIndexObj;
int newIndex = uiSourceInfoList.indexOf(info);
if (newIndex != -1) {
minRefreshIndex = Math.min(minRefreshIndex, Math.min(oldIndex, newIndex));
maxRefreshIndex = Math.max(maxRefreshIndex, Math.max(oldIndex, newIndex));
}
}
int count;
if (minRefreshIndex == maxRefreshIndex) {
count = 1;
} else {
count = maxRefreshIndex - minRefreshIndex + 1;
}
if (count > 0 && maxRefreshIndex >= minRefreshIndex) {
adapter.onItemRangeChanged(minRefreshIndex, count);
}
}
}
private ArrayList<ConversationInfo> processFoldedAndHiddenConversation(List<ConversationInfo> infoList) {
ArrayList<ConversationInfo> changedInfoList = new ArrayList<>();
for (ConversationInfo conversationInfo : infoList) {
int uiIndex = -1;
for (int i = 0; i < loadedConversationInfoList.size(); i++) {
ConversationInfo loadedInfo = loadedConversationInfoList.get(i);
if (TextUtils.equals(conversationInfo.getConversationId(), loadedInfo.getConversationId())) {
uiIndex = i;
break;
}
}
if (uiIndex >= 0) {
if (!conversationInfo.isMarkFold() || conversationInfo.isMarkHidden()) {
loadedConversationInfoList.remove(uiIndex);
if (adapter != null) {
adapter.onItemRemoved(uiIndex);
}
} else if (conversationInfo.isMarkFold()) {
changedInfoList.add(conversationInfo);
}
} else {
if (conversationInfo.isMarkFold() && !conversationInfo.isMarkHidden()) {
changedInfoList.add(conversationInfo);
}
}
}
return changedInfoList;
}
private void processNewMessage(String conversationID, boolean isTypingMessage) {
if (TextUtils.isEmpty(conversationID)) {
return;
}
if (isTypingMessage) {
return;
}
ConversationInfo cacheInfo = null;
for (ConversationInfo conversationInfo : loadedConversationInfoList) {
if (TextUtils.equals(conversationID, conversationInfo.getConversationId())) {
cacheInfo = conversationInfo;
break;
}
}
if (cacheInfo != null) {
if (cacheInfo.isMarkUnread()) {
markConversationUnread(cacheInfo, false);
}
} else {
provider.getConversation(conversationID, new IUIKitCallback<ConversationInfo>() {
@Override
public void onSuccess(ConversationInfo conversationInfo) {
if (conversationInfo.isMarkHidden()) {
markConversationHidden(conversationInfo, false);
}
if (conversationInfo.isMarkUnread()) {
markConversationUnread(conversationInfo, false);
}
}
@Override
public void onError(String module, int errCode, String errMsg) {
}
});
}
}
/**
* 删除会话会将本地会话数据从imsdk中删除
*
* @param conversation 会话信息
*/
public void deleteConversation(ConversationInfo conversation) {
HashMap<String, Object> param = new HashMap<>();
param.put(TUIConstants.TUIConversation.CONVERSATION_ID, conversation.getConversationId());
TUICore.callService(TUIConstants.TUIConversation.SERVICE_NAME, TUIConstants.TUIConversation.METHOD_DELETE_CONVERSATION, param);
}
/**
* 隐藏会话
* hide conversation
* @param conversationInfo 会话信息 conversation info
*/
public void markConversationHidden(ConversationInfo conversationInfo, boolean isHidden) {
if (conversationInfo == null || TextUtils.isEmpty(conversationInfo.getConversationId())) {
TUIConversationLog.e(TAG, "markConversationHidden error: invalid conversationInfo");
return;
}
provider.markConversationHidden(conversationInfo.getConversationId(), isHidden, new IUIKitCallback<Void>() {
@Override
public void onSuccess(Void data) {
conversationInfo.setMarkHidden(isHidden);
TUIConversationLog.i(TAG, "markConversationHidden success, conversationID:" +
conversationInfo.getConversationId() + ", isHidden:" + isHidden);
}
@Override
public void onError(String module, int errCode, String errMsg) {
TUIConversationLog.e(TAG, "markConversationHidden error, conversationID:" +
conversationInfo.getConversationId() + ", code:" + errCode + "|msg:" + errMsg);
}
});
}
public void markConversationUnread(ConversationInfo conversationInfo, boolean markUnread) {
if (conversationInfo == null || TextUtils.isEmpty(conversationInfo.getConversationId())) {
TUIConversationLog.e(TAG, "markConversationUnread error: invalid conversationInfo");
return;
}
provider.markConversationUnread(conversationInfo, markUnread, new IUIKitCallback<Void>() {
@Override
public void onSuccess(Void data) {
conversationInfo.setMarkUnread(markUnread);
TUIConversationLog.i(TAG, "markConversationRead success, conversationID:" +
conversationInfo.getConversationId());
}
@Override
public void onError(String module, int errCode, String errMsg) {
TUIConversationLog.e(TAG, "markConversationRead error, conversationID:" +
conversationInfo.getConversationId() + ", code:" + errCode + "|msg:" + errMsg);
}
});
}
public void deleteConversationFromUI(String id, boolean isGroup) {
if (!isGroup) {
return;
}
for (int i = 0; i < loadedConversationInfoList.size(); i++) {
ConversationInfo info = loadedConversationInfoList.get(i);
if (TextUtils.equals(info.getId(), id)) {
boolean isRemove = loadedConversationInfoList.remove(info);
if (adapter != null && isRemove) {
adapter.onItemRemoved(i);
}
break;
}
}
}
public void deleteConversationFromUI(String conversationId) {
if (TextUtils.isEmpty(conversationId)) {
return;
}
for (int i = 0; i < loadedConversationInfoList.size(); i++) {
ConversationInfo info = loadedConversationInfoList.get(i);
if (TextUtils.equals(info.getConversationId(), conversationId)) {
boolean isRemove = loadedConversationInfoList.remove(info);
if (adapter != null && isRemove) {
adapter.onItemRemoved(i);
}
break;
}
}
}
}

View File

@@ -0,0 +1,19 @@
package com.tencent.qcloud.tuikit.tuiconversation.presenter;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuiconversation.model.ConversationProvider;
import java.util.List;
public class ConversationIconPresenter {
private final ConversationProvider provider;
public ConversationIconPresenter() {
provider = new ConversationProvider();
}
public void getGroupMemberIconList(String groupId, IUIKitCallback<List<Object>> callback) {
provider.getGroupMemberIconList(groupId, 9, callback);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#1F767680"/>
<corners android:radius="10dp"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,64 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bottom_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/conversation_bottom_bg"
android:orientation="vertical"
android:visibility="visible"
tools:visibility="visible">
<TextView
android:id="@+id/divide_line"
android:layout_width="match_parent"
android:layout_marginTop="1dp"
android:layout_height="1dp"
android:background="@color/dialog_line_bg" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/conversation_bottom_bg"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:paddingLeft="38.4dp"
android:paddingRight="38.4dp"
android:layout_marginTop="1.36dp"
android:layout_marginBottom="46.08dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/not_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:layout_marginTop="5.76dp"
android:text="@string/not_display"
android:textColor="#147AFF"
android:textSize="14sp" />
<TextView
android:id="@+id/mark_read"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="5.76dp"
android:layout_weight="1"
android:text="@string/mark_read"
android:textColor="#147AFF"
android:textSize="14sp" />
<TextView
android:id="@+id/delete_chat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:layout_marginTop="5.76dp"
android:text="@string/chat_delete"
android:textColor="#147AFF"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>

View File

@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center_vertical"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal">
<RelativeLayout
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationIconView
android:id="@+id/conversation_icon"
android:layout_width="40dp"
android:layout_height="40dp"
tools:background="@android:drawable/ic_menu_gallery"/>
<View
android:id="@+id/user_status"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_alignBottom="@id/conversation_icon"
android:layout_alignEnd="@id/conversation_icon"
android:layout_alignRight="@id/conversation_icon"
android:visibility="visible"
android:background="@drawable/conversation_minimalist_online_icon" />
</RelativeLayout>
<RelativeLayout
android:gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/conversation_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="180dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ellipsize="end"
android:gravity="top|start"
android:singleLine="true"
android:textColor="@color/black_font_color"
android:textStyle="bold"
android:textSize="14sp"
tools:text="Daniel"/>
<TextView
android:id="@+id/conversation_at_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/conversation_title"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#FF666666"
android:textSize="12sp"
android:visibility="gone"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
tools:visibility="visible"
tools:text="\@You" />
<TextView
android:id="@+id/conversation_last_msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:layout_gravity="start"
android:layout_below="@id/conversation_title"
android:layout_toEndOf="@id/conversation_at_msg"
android:layout_toStartOf="@id/message_status_layout"
android:layout_marginEnd="29dp"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#FF666666"
android:textSize="12sp"
tools:text="Hello"
android:layout_toRightOf="@id/conversation_at_msg"
android:layout_toLeftOf="@id/message_status_layout"
android:layout_marginRight="29dp" />
<RelativeLayout
android:id="@+id/message_status_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/view_line"
android:layout_toStartOf="@id/conversation_time"
android:layout_alignBottom="@id/conversation_time"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:visibility="gone"
android:layout_marginRight="2dp"
tools:visibility="visible"
android:layout_toLeftOf="@id/conversation_time">
<ImageView
android:id="@+id/message_status_sending"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="center_vertical"
android:background="@drawable/ic_sending_status"
android:visibility="gone"
tools:visibility="visible"/>
<ImageView
android:id="@+id/message_status_failed"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="center_vertical"
android:scaleType="fitCenter"
android:src="@drawable/ic_send_failed"
android:visibility="gone"/>
</RelativeLayout>
<TextView
android:id="@+id/conversation_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/conversation_title"
android:layout_alignParentRight="true"
android:textColor="#FF666666"
android:textSize="12sp"
android:lineHeight="14.32sp"
android:layout_alignParentEnd="true"
tools:text="12:00"/>
<LinearLayout
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_alignParentRight="true"
android:layout_marginBottom="3dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/not_disturb"
android:layout_width="16dp"
android:layout_height="16dp"
android:includeFontPadding="false"
android:background="@drawable/conversation_minimalist_not_disturb_icon"
android:visibility="gone"
tools:visibility="visible"/>
<com.tencent.qcloud.tuicore.component.UnreadCountTextView
android:id="@+id/conversation_unread"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/conversation_time"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="#FFFFFF"
android:textSize="11sp"
app:paint_color="#FF584C"
android:layout_alignParentEnd="true"
tools:text="2"
tools:visibility="visible"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,12 @@
<?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:background="@color/conversation_page_bg">
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.FoldedConversationLayout
android:id="@+id/folded_conversation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@@ -0,0 +1,16 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.tencent.qcloud.tuicore.component.TitleBarLayout
android:id="@+id/conversation_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.FoldedConversationListLayout
android:id="@+id/folded_conversation_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/btn_margin_bottom"
android:clickable="true">
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationIconView
android:id="@+id/conversation_user_icon_view"
android:layout_width="41dp"
android:layout_height="41dp"
app:default_image="?attr/core_default_user_icon"
android:visibility="gone"/>
</LinearLayout>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ForwardSelectLayout
android:id="@+id/forward_conversation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/btn_height"/>
<RelativeLayout
android:id="@+id/forward_select_list_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingLeft="14.85dp"
android:paddingRight="14.85dp"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/forward_select_list"
android:layout_width="wrap_content"
android:layout_alignParentLeft="true"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/forward_margin"/>
<TextView
android:id="@+id/btn_msg_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/btn_margin_right"
android:text="@string/sure"
android:textColor="@color/bg_positive_btn"
android:textSize="14sp"
android:visibility="visible" />
</RelativeLayout>
</RelativeLayout>

View File

@@ -0,0 +1,16 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.tencent.qcloud.tuicore.component.TitleBarLayout
android:id="@+id/conversation_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationListLayout
android:id="@+id/conversation_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="34sp"
android:lineHeight="41dp"
android:textStyle="bold"
android:textColor="@color/black_font_color"
android:text="@string/conversation_minimalist_chat"/>
<ImageView
android:id="@+id/edit_button"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/conversation_minimalist_edit_icon"/>
<ImageView
android:id="@+id/create_new_button"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="25dp"
android:layout_marginStart="25dp"
android:background="@drawable/conversation_minimalist_create_icon" />
<TextView
android:id="@+id/edit_done"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@color/font_blue"
android:text="@string/conversation_minimalist_done"
android:visibility="gone"/>
</LinearLayout>

View File

@@ -0,0 +1,88 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/more_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:gravity="center"
android:orientation="vertical"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="34dp"
android:visibility="visible"
tools:visibility="visible">
<LinearLayout
android:id="@+id/layout_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/alert_bg"
android:alpha="0.95">
<TextView
android:id="@+id/not_display"
android:text="@string/not_display"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center"
android:textColor="#147AFF"
android:textSize="17sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/white" />
<TextView
android:id="@+id/top_set"
android:text="@string/chat_top"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center"
android:textColor="#147AFF"
android:textSize="17sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/white" />
<TextView
android:id="@+id/clear_chat"
android:text="@string/clear_message"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center"
android:textColor="#147AFF"
android:textSize="17sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/white" />
<TextView
android:id="@+id/delete_chat"
android:text="@string/chat_delete"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center"
android:textColor="#FF584C"
android:textSize="17sp" />
</LinearLayout>
<TextView
android:id="@+id/cancel_button"
android:layout_below="@+id/layout_actions"
android:background="@drawable/alert_bg"
android:layout_marginTop="12dp"
android:text="@string/cancel"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center"
android:textColor="#147AFF"
android:textSize="17sp" />
</RelativeLayout>

View File

@@ -0,0 +1,17 @@
<?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:background="@color/conversation_page_bg">
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationLayout
android:id="@+id/conversation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include layout="@layout/minimalist_bottom_bar"
android:layout_marginBottom="@dimen/page_margin"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</LinearLayout>

View File

@@ -0,0 +1,29 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/minimalist_header_view_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"/>
<FrameLayout
android:id="@+id/search_layout"
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_marginTop="9dp"
android:layout_marginBottom="15dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:visibility="gone"
/>
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.ConversationListLayout
android:id="@+id/conversation_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipe"
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="#FFFFFF"
app:clickToClose="false">
<LinearLayout
android:id="@+id/bottom_wrapper_2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:tag="Bottom4">
<RelativeLayout
android:id="@+id/more_view"
android:layout_width="70dp"
android:layout_height="match_parent"
android:background="@color/black"
android:gravity="center">
<ImageView
android:id="@+id/more_image"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/conversation_minimalist_more_icon" />
<TextView
android:id="@+id/more_text"
android:layout_width="70dp"
android:layout_height="match_parent"
android:layout_below="@+id/more_image"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/more_text"
android:textColor="@color/white"
android:textSize="12sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/mark_read"
android:layout_width="70dp"
android:layout_height="match_parent"
android:background="@color/conversation_mark_swipe_bg"
android:gravity="center">
<ImageView
android:id="@+id/mark_read_image"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/mark_read_text"
android:layout_width="70dp"
android:layout_height="match_parent"
android:layout_below="@+id/mark_read_image"
android:layout_centerInParent="true"
android:background="@color/transparent"
android:gravity="center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/mark_read"
android:textColor="@color/white"
android:textSize="12sp" />
</RelativeLayout>
<TextView
android:id="@+id/not_display"
android:layout_width="70dp"
android:layout_height="match_parent"
android:background="@color/conversation_mark_swipe_bg"
android:gravity="center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/not_display"
android:textColor="@color/white"
android:textSize="12sp"
android:visibility="gone" />
</LinearLayout>
<LinearLayout
android:id="@+id/item_left"
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="#FFFFFF"
android:clipChildren="false"
android:clipToPadding="false"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<CheckBox
android:id="@+id/select_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_gravity="center_vertical"
android:layout_marginRight="6.23dp"
android:button="@drawable/checkbox_selector"
android:visibility="gone" />
<include
layout="@layout/minimalist_conversation_list_item_sub_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:tag="Hover" />
</LinearLayout>
</com.tencent.qcloud.tuikit.tuiconversation.minimalistui.widget.swipe.SwipeLayout>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="conversation_minimalist_chat">聊天</string>
<string name="conversation_minimalist_search">搜索</string>
<string name="conversation_minimalist_done">完成</string>
<string name="has_all_read">全部已读</string>
<string name="start_conversation">发起会话</string>
<string name="create_group_chat">创建群聊</string>
<string name="more_text">更多</string>
<string name="clear_message">清除聊天记录</string>
</resources>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MinimalistHeaderView">
<attr name="header_title" format="string" />
</declare-styleable>
<declare-styleable name="SwipeLayout">
<attr name="drag_edge">
<flag name="left" value="1" />
<flag name="right" value="2" />
<flag name="top" value="4" />
<flag name="bottom" value="8" />
</attr>
<attr name="leftEdgeSwipeOffset" format="dimension" />
<attr name="rightEdgeSwipeOffset" format="dimension" />
<attr name="topEdgeSwipeOffset" format="dimension" />
<attr name="bottomEdgeSwipeOffset" format="dimension" />
<attr name="show_mode" format="enum">
<enum name="lay_down" value="0" />
<enum name="pull_out" value="1" />
</attr>
<attr name="clickToClose" format="boolean" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="conversation_delete_swipe_bg">#F24D4C</color>
<color name="conversation_mark_swipe_bg">#147AFF</color>
<color name="conversation_mark_swipe_dark_bg">#666666</color>
<color name="conversation_hide_swipe_bg">#F29340</color>
<color name="conversation_bottom_bg">#F9F9F9</color>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="conversation_minimalist_chat">Chat</string>
<string name="conversation_minimalist_search">Search</string>
<string name="conversation_minimalist_done">Done</string>
<string name="has_all_read">Read All</string>
<string name="start_conversation">New Chat</string>
<string name="create_group_chat">Create Group Chat</string>
<string name="more_text">More</string>
<string name="clear_message">Clear Chat History</string>
</resources>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="@color/btn_positive_hover" >
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="5dp" />
<solid android:color="@color/btn_positive_hover" />
</shape>
</item>
<item android:color="@color/btn_positive" >
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="5dp" />
<solid android:color="@color/btn_positive" />
</shape>
</item>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Some files were not shown because too many files have changed in this diff Show More