feat(emergency): 新增应急就医群聊功能

- 工作台新增"应急就医"入口,支持多工单选择弹窗
- 新增应急就医相关 API:参与工单列表、群成员增减、专家/员工搜索
- 群聊页面集成侧边导航抽屉(DrawerLayout),展示群成员并支持添加/移除
- 新增添加成员页面(AddMemberActivity),支持搜索专家和员工
- InputActionSetting 扩展:新增结束会话、结束问诊名称、评价等控制字段
- IMManager.startGroupChat 支持传入 InputActionSetting 定制输入区行为
- TUIUtils 新增 WORK_TYPE_EMERGENCY 类型常量
- 新增 ParamedicOperateHelper 统一管理应急群聊操作回调

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
zhanglei
2026-08-04 17:27:23 +08:00
co-authored by Claude Opus 4.7
parent 2c4b640adb
commit f61d8c90c9
89 changed files with 3409 additions and 69 deletions
@@ -44,6 +44,10 @@
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustNothing|stateHidden"/>
<activity
android:name=".classicui.page.AddMemberActivity"
android:screenOrientation="portrait" />
<activity
android:name=".classicui.page.MessageReceiptDetailActivity"
android:screenOrientation="portrait" />
@@ -38,6 +38,8 @@ public class TUIChatConstants {
public static final int GET_MESSAGE_LOCATE = 3;
public static final String CHAT_INFO = "chatInfo";
public static final String WEEK_STATE = "weekState";
public static final String CHAT_IS_LIAISON_USER = "chat_is_liaison_user";
public static final String MESSAGE_BEAN = "messageBean";
@@ -194,4 +194,23 @@ public class ChatInfo implements Serializable {
public void setInputActionSetting(InputActionSetting inputActionSetting) {
this.inputActionSetting = inputActionSetting;
}
private String autoSendMessage;
private String consultantId;
public String getAutoSendMessage() {
return autoSendMessage;
}
public void setAutoSendMessage(String autoSendMessage) {
this.autoSendMessage = autoSendMessage;
}
public String getConsultantId() {
return consultantId;
}
public void setConsultantId(String consultantId) {
this.consultantId = consultantId;
}
}
@@ -0,0 +1,67 @@
package com.tencent.qcloud.tuikit.tuichat.bean;
public class EmployeeBean {
private String userId;
private String realname;
private String avatar;
private String orgCode;
private String orgName;
private String deptName;
private String phone;
private String workNo;
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserId() {
return userId;
}
public void setRealname(String realname) {
this.realname = realname;
}
public String getRealname() {
return realname;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getAvatar() {
return avatar;
}
public void setOrgCode(String orgCode) {
this.orgCode = orgCode;
}
public String getOrgCode() {
return orgCode;
}
public void setOrgName(String orgName) {
this.orgName = orgName;
}
public String getOrgName() {
return orgName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDeptName() {
return deptName;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPhone() {
return phone;
}
public void setWorkNo(String workNo) {
this.workNo = workNo;
}
public String getWorkNo() {
return workNo;
}
}
@@ -0,0 +1,112 @@
package com.tencent.qcloud.tuikit.tuichat.bean;
public class ExpertBean {
private String userId;
private String realname;
private String avatar;
private String type;
private String centerId;
private String post;
private String post_dictText;
private String school;
private String edu;
private String goodAt;
private String deptName;
private String phone;
public String getPost_dictText() {
return post_dictText;
}
public void setPost_dictText(String post_dictText) {
this.post_dictText = post_dictText;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealname() {
return realname;
}
public void setRealname(String realname) {
this.realname = realname;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCenterId() {
return centerId;
}
public void setCenterId(String centerId) {
this.centerId = centerId;
}
public String getPost() {
return post;
}
public void setPost(String post) {
this.post = post;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getEdu() {
return edu;
}
public void setEdu(String edu) {
this.edu = edu;
}
public String getGoodAt() {
return goodAt;
}
public void setGoodAt(String goodAt) {
this.goodAt = goodAt;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
@@ -21,7 +21,7 @@ public class GroupInfo extends ChatInfo {
private int memberCount;
private String groupName;
private String notice;
private List<GroupMemberInfo> memberDetails = new ArrayList<>();
private List<? extends GroupMemberInfo> memberDetails = new ArrayList<>();
private int joinType;
private String owner;
private boolean messageReceiveOption;
@@ -125,7 +125,7 @@ public class GroupInfo extends ChatInfo {
*
* @return
*/
public List<GroupMemberInfo> getMemberDetails() {
public List<? extends GroupMemberInfo> getMemberDetails() {
return memberDetails;
}
@@ -136,7 +136,7 @@ public class GroupInfo extends ChatInfo {
*
* @param memberDetails
*/
public void setMemberDetails(List<GroupMemberInfo> memberDetails) {
public void setMemberDetails(List<? extends GroupMemberInfo> memberDetails) {
this.memberDetails = memberDetails;
}
@@ -223,4 +223,14 @@ public class GroupInfo extends ChatInfo {
setMessageReceiveOption(infoResult.getGroupInfo().getRecvOpt() == V2TIMMessage.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE ? true : false);
return this;
}
private boolean initiateVideoCall;
public boolean isInitiateVideoCall() {
return initiateVideoCall;
}
public void setInitiateVideoCall(boolean initiateVideoCall) {
this.initiateVideoCall = initiateVideoCall;
}
}
@@ -0,0 +1,109 @@
package com.tencent.qcloud.tuikit.tuichat.bean;
import java.util.ArrayList;
import java.util.List;
/**
* 群成员信息扩展类,在 GroupMemberInfo 基础上补充 GroupMemberBean 中的业务字段
*/
public class GroupMember extends GroupMemberInfo {
private String orderId;
private String userId;
private String userName;
private String avatar;
private String phone;
private int isGroupMember;
private int isSelf;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getIsGroupMember() {
return isGroupMember;
}
public void setIsGroupMember(int isGroupMember) {
this.isGroupMember = isGroupMember;
}
public int getIsSelf() {
return isSelf;
}
public void setIsSelf(int isSelf) {
this.isSelf = isSelf;
}
/**
* 将 GroupMemberBean 转换为 GroupMember
*/
public static GroupMember convertFromBean(GroupMemberBean bean) {
if (bean == null) {
return null;
}
GroupMember member = new GroupMember();
// 映射到父类字段
member.setAccount(bean.getUserId());
member.setMemberType(bean.getMemberType());
// 映射到自身扩展字段
member.setOrderId(bean.getOrderId());
member.setUserId(bean.getUserId());
member.setUserName(bean.getUserName());
member.setAvatar(bean.getAvatar());
member.setPhone(bean.getPhone());
member.setIsGroupMember(bean.getIsGroupMember());
member.setIsSelf(bean.getIsSelf());
return member;
}
/**
* 批量将 List<GroupMemberBean> 转换为 List<GroupMember>
*/
public static List<GroupMember> convertFromBeanList(List<GroupMemberBean> beans) {
List<GroupMember> members = new ArrayList<>();
if (beans != null) {
for (GroupMemberBean bean : beans) {
members.add(convertFromBean(bean));
}
}
return members;
}
}
@@ -0,0 +1,76 @@
package com.tencent.qcloud.tuikit.tuichat.bean;
public class GroupMemberBean {
private String orderId;
private String userId;
private String userName;
private String avatar;
private String phone;
private int isGroupMember;
private int memberType;
private int isSelf;
public int getIsSelf() {
return isSelf;
}
public void setIsSelf(int isSelf) {
this.isSelf = isSelf;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getIsGroupMember() {
return isGroupMember;
}
public void setIsGroupMember(int isGroupMember) {
this.isGroupMember = isGroupMember;
}
public int getMemberType() {
return memberType;
}
public void setMemberType(int memberType) {
this.memberType = memberType;
}
}
@@ -0,0 +1,9 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.event
/**
* @author nanfeifei
* @time 2023/7/5 14:32
* @description
*/
class CustomMessageEvent(var chatId: String, var messageJson: String) {
}
@@ -0,0 +1,79 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.event;
public class IMChatEvent {
public int type;//0 医生卡片 1 仅提示message信息 2聊天头像id
public String doctor;
public String message = "";
public long time;
//新疆项目新增字段
public String groupId = "";
public String fromAccount = "";//小助手id
public String toAccount = "";//当前登录用户id
public String msgId = "";
public String getMessage() {
return message == null ? "" : message;
}
public void setMessage(String message) {
this.message = message;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getDoctor() {
return doctor == null ? "" : doctor;
}
public void setDoctor(String doctor) {
this.doctor = doctor;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getFromAccount() {
return fromAccount;
}
public void setFromAccount(String fromAccount) {
this.fromAccount = fromAccount;
}
public String getToAccount() {
return toAccount;
}
public void setToAccount(String toAccount) {
this.toAccount = toAccount;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
}
@@ -0,0 +1,70 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.interfaces;
import androidx.core.util.Consumer;
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean;
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean;
import java.util.List;
/**
* 急救调度相关操作的对外接口。
* 由宿主 App(如 EmergencyFragment)实现并注册到 {@link com.tencent.qcloud.tuikit.tuichat.presenter.ParamedicOperateHelper}
* 供 tuichat 模块反向调用宿主能力(加成员、查专家/员工、移除成员等)。
*/
public interface OnParamedicOperateListener {
/**
* 获取指定会话(群组)当前实际成员列表。
*
* @param sessionId 群组会话 ID
* @return 成员列表,可能为空,但不为 null
*/
List<GroupMemberBean> getActualGroupMemberList(String sessionId);
/**
* 邀请一批用户加入指定群组。操作为异步执行,结果通过 callback 回传。
*
* @param groupId 目标群组 ID
* @param memberList 待加入成员的 userId 列表
* @param memberType 成员类型,由业务侧约定语义
* @param callback 操作结果回调:true 表示服务器侧写入成功;false 表示失败(含网络异常、业务错误等)。
* 回调触发线程不限定,调用方需自行切回主线程操作 UI。不允许传 null。
*/
void addGroupUser(String groupId, List<String> memberList, int memberType, Consumer<Boolean> callback);
/**
* 按条件检索专家。
*
* @param realname 真实姓名关键字,可空
* @param centerId 中心 ID,可空
* @param excludeSessionId 需排除的会话 ID(避免重复添加),可空
* @param pageNo 页码
* @param pageSize 每页条数
* @return 专家列表,可能为空
*/
List<ExpertBean> searchExpert(String realname, String centerId, String excludeSessionId, int pageNo, int pageSize);
/**
* 按条件检索员工。
*
* @param realname 真实姓名关键字,可空
* @param orgCode 机构编码,可空
* @param workNo 工号,可空
* @param phone 电话,可空
* @param excludeSessionId 需排除的会话 ID,可空
* @param pageNo 页码
* @param pageSize 每页条数
* @return 员工列表,可能为空
*/
List<EmployeeBean> searchEmployee(String realname, String orgCode, String workNo, String phone, String excludeSessionId, int pageNo, int pageSize);
/**
* 从指定群组移除一批成员。当前为 fire-and-forget,无回调。
*
* @param groupId 目标群组 ID
* @param memberList 待移除成员的 userId 列表
*/
void removeGroupUser(String groupId, List<String> memberList);
}
@@ -0,0 +1,267 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.page;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.tabs.TabLayout;
import com.tencent.qcloud.tuicore.component.activities.BaseLightActivity;
import com.tencent.qcloud.tuikit.tuichat.R;
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean;
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean;
import java.util.ArrayList;
import java.util.List;
public class AddMemberActivity extends BaseLightActivity {
public static final int REQUEST_CODE_ADD_MEMBER = 12;
public static final String EXTRA_SELECTED_USER_IDS = "extra_selected_user_ids";
private static final int TAB_EMPLOYEE = 0;
private static final int TAB_EXPERT = 1;
private LinearLayout llBack;
private TabLayout tabLayout;
private EditText etSearch;
private RecyclerView rvMembers;
private TextView tvConfirm;
private TextView tvSearchAction;
private AddMemberViewModel viewModel;
private AddMemberAdapter<ExpertBean> expertAdapter;
private AddMemberAdapter<EmployeeBean> employeeAdapter;
private int currentTab = TAB_EMPLOYEE;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_member);
viewModel = new ViewModelProvider(this).get(AddMemberViewModel.class);
initViews();
initAdapters();
initObservers();
initListeners();
viewModel.loadExperts("");
viewModel.loadEmployees("");
}
private void initViews() {
llBack = findViewById(R.id.ll_back);
tabLayout = findViewById(R.id.tab_layout);
etSearch = findViewById(R.id.et_search);
rvMembers = findViewById(R.id.rv_members);
tvConfirm = findViewById(R.id.tv_confirm);
tvSearchAction = findViewById(R.id.tv_search_action);
rvMembers.setLayoutManager(new LinearLayoutManager(this));
rvMembers.setHasFixedSize(false);
tabLayout.addTab(tabLayout.newTab().setText(R.string.add_member_tab_employee));
tabLayout.addTab(tabLayout.newTab().setText(R.string.add_member_tab_expert));
setupSearchBox();
}
private void setupSearchBox() {
etSearch.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_search, 0, 0, 0);
etSearch.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
updateClearIconVisibility(s.length() > 0);
}
});
etSearch.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH
|| (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
&& event.getAction() == KeyEvent.ACTION_DOWN)) {
onSearch(v.getText().toString().trim());
return true;
}
return false;
});
etSearch.setOnTouchListener((v, event) -> {
if (event.getAction() != MotionEvent.ACTION_UP) {
return false;
}
Drawable clearIcon = etSearch.getCompoundDrawables()[2];
if (clearIcon == null) {
return false;
}
int iconWidth = clearIcon.getIntrinsicWidth();
int rightEdge = etSearch.getWidth() - etSearch.getPaddingRight();
int leftEdge = rightEdge - iconWidth;
float touchX = event.getX();
if (touchX >= leftEdge && touchX <= rightEdge) {
etSearch.setText("");
if (currentTab == TAB_EXPERT) {
viewModel.loadExperts("");
} else {
viewModel.loadEmployees("");
}
return true;
}
return false;
});
}
private void updateClearIconVisibility(boolean hasText) {
etSearch.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_search, 0,
hasText ? R.drawable.ic_clear : 0, 0);
}
protected void onSearch(String keyword) {
if (currentTab == TAB_EXPERT) {
viewModel.loadExperts(keyword);
} else {
viewModel.loadEmployees(keyword);
}
}
private void initAdapters() {
expertAdapter = new AddMemberAdapter<>(new AddMemberAdapter.ItemBinder<ExpertBean>() {
@Override
public String getUserId(@NonNull ExpertBean item) {
return item.getUserId();
}
@Override
public String getDisplayName(@NonNull ExpertBean item) {
return item.getRealname();
}
@Override
public String getDeptName(@NonNull ExpertBean item) {
return item.getDeptName();
}
@Override
public String getAvatar(@NonNull ExpertBean item) {
return item.getAvatar();
}
@Override
public String getPost(@NonNull ExpertBean item) {
return item.getPost_dictText();
}
});
expertAdapter.setOnItemClickListener((item, position) -> onItemClicked(item.getUserId()));
employeeAdapter = new AddMemberAdapter<>(new AddMemberAdapter.ItemBinder<EmployeeBean>() {
@Override
public String getUserId(@NonNull EmployeeBean item) {
return item.getUserId();
}
@Override
public String getDisplayName(@NonNull EmployeeBean item) {
return item.getRealname();
}
@Override
public String getDeptName(@NonNull EmployeeBean item) {
return item.getDeptName();
}
@Override
public String getAvatar(@NonNull EmployeeBean item) {
return item.getAvatar();
}
@Override
public String getPost(@NonNull EmployeeBean item) {
return null;
}
});
employeeAdapter.setOnItemClickListener((item, position) -> onItemClicked(item.getUserId()));
rvMembers.setAdapter(employeeAdapter);
}
private void initObservers() {
viewModel.getExpertsLiveData().observe(this, this::applyExpertData);
viewModel.getEmployeesLiveData().observe(this, this::applyEmployeeData);
}
private void initListeners() {
llBack.setOnClickListener(v -> finish());
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
int position = tab.getPosition();
currentTab = position;
if (position == TAB_EXPERT) {
rvMembers.setAdapter(expertAdapter);
expertAdapter.setSelectedIds(viewModel.getSelectedUserIds());
} else if (position == TAB_EMPLOYEE) {
rvMembers.setAdapter(employeeAdapter);
employeeAdapter.setSelectedIds(viewModel.getSelectedUserIds());
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {}
@Override
public void onTabReselected(TabLayout.Tab tab) {}
});
tvSearchAction.setOnClickListener(v -> onSearch(etSearch.getText().toString().trim()));
tvConfirm.setOnClickListener(v -> onConfirm());
}
private void onItemClicked(String userId) {
viewModel.toggleSelected(userId);
refreshSelectionUi();
}
private void applyExpertData(List<ExpertBean> experts) {
expertAdapter.setData(experts);
expertAdapter.setSelectedIds(viewModel.getSelectedUserIds());
}
private void applyEmployeeData(List<EmployeeBean> employees) {
employeeAdapter.setData(employees);
employeeAdapter.setSelectedIds(viewModel.getSelectedUserIds());
}
private void refreshSelectionUi() {
int count = viewModel.getSelectedCount();
tvConfirm.setText(count > 0 ? getString(R.string.add_member_confirm) + " (" + count + ")" : getString(R.string.add_member_confirm));
if (currentTab == TAB_EXPERT) {
expertAdapter.setSelectedIds(viewModel.getSelectedUserIds());
} else {
employeeAdapter.setSelectedIds(viewModel.getSelectedUserIds());
}
}
private void onConfirm() {
ArrayList<String> selected = viewModel.snapshotSelectedUserIds();
if (selected.isEmpty()) {
Toast.makeText(this, R.string.add_member_empty, Toast.LENGTH_SHORT).show();
return;
}
Intent data = new Intent();
data.putStringArrayListExtra(EXTRA_SELECTED_USER_IDS, selected);
setResult(Activity.RESULT_OK, data);
finish();
}
}
@@ -0,0 +1,126 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.page;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuicore.component.imageEngine.impl.GlideEngine;
import com.tencent.qcloud.tuikit.tuichat.R;
import com.tencent.qcloud.tuikit.tuichat.presenter.FileBaseUrlHelper;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class AddMemberAdapter<T> extends RecyclerView.Adapter<AddMemberAdapter.MemberViewHolder> {
private final List<T> data = new ArrayList<>();
private final ItemBinder<T> binder;
private final Set<String> selectedIds = new HashSet<>();
private OnItemClickListener<T> itemClickListener;
public AddMemberAdapter(@NonNull ItemBinder<T> binder) {
this.binder = binder;
}
public void setData(List<T> items) {
data.clear();
if (items != null) {
data.addAll(items);
}
notifyDataSetChanged();
}
public void setSelectedIds(Set<String> ids) {
selectedIds.clear();
if (ids != null) {
selectedIds.addAll(ids);
}
notifyDataSetChanged();
}
public void setOnItemClickListener(OnItemClickListener<T> listener) {
this.itemClickListener = listener;
}
@NonNull
@Override
public MemberViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_add_member, parent, false);
return new MemberViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull MemberViewHolder holder, int position) {
T item = data.get(position);
if (item == null) {
return;
}
final String userId = binder.getUserId(item);
String name = binder.getDisplayName(item);
String dept = binder.getDeptName(item);
String avatar = binder.getAvatar(item);
String post = binder.getPost(item);
holder.tvName.setText(name);
holder.tvDept.setText(dept == null ? "" : dept);
holder.tvPost.setText(post == null ? "" : post);
String avatarFullPath = FileBaseUrlHelper.getInstance().getIconBaseUrl() + avatar;
GlideEngine.loadUserCircleIcon(holder.ivAvatar, avatarFullPath, R.drawable.default_user_icon);
boolean checked = userId != null && selectedIds.contains(userId);
holder.cbSelect.setChecked(checked);
holder.itemView.setOnClickListener(v -> {
if (itemClickListener != null) {
int adapterPosition = holder.getBindingAdapterPosition();
if (adapterPosition == RecyclerView.NO_POSITION) {
return;
}
itemClickListener.onItemClick(item, adapterPosition);
}
});
}
@Override
public int getItemCount() {
return data.size();
}
static class MemberViewHolder extends RecyclerView.ViewHolder {
ImageView ivAvatar;
TextView tvName;
TextView tvDept;
TextView tvPost;
CheckBox cbSelect;
MemberViewHolder(@NonNull View itemView) {
super(itemView);
ivAvatar = itemView.findViewById(R.id.iv_avatar);
tvName = itemView.findViewById(R.id.tv_name);
tvDept = itemView.findViewById(R.id.tv_dept);
cbSelect = itemView.findViewById(R.id.cb_select);
tvPost = itemView.findViewById(R.id.tv_post);
}
}
public interface ItemBinder<T> {
String getUserId(@NonNull T item);
String getDisplayName(@NonNull T item);
String getDeptName(@NonNull T item);
String getAvatar(@NonNull T item);
String getPost(@NonNull T item);
}
public interface OnItemClickListener<T> {
void onItemClick(@NonNull T item, int position);
}
}
@@ -0,0 +1,68 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.page;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean;
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean;
import com.tencent.qcloud.tuikit.tuichat.presenter.ParamedicOperateHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class AddMemberViewModel extends ViewModel {
private final MutableLiveData<List<ExpertBean>> expertsLiveData = new MutableLiveData<>();
private final MutableLiveData<List<EmployeeBean>> employeesLiveData = new MutableLiveData<>();
private final Set<String> selectedUserIds = new HashSet<>();
public LiveData<List<ExpertBean>> getExpertsLiveData() {
return expertsLiveData;
}
public LiveData<List<EmployeeBean>> getEmployeesLiveData() {
return employeesLiveData;
}
public Set<String> getSelectedUserIds() {
return Collections.unmodifiableSet(selectedUserIds);
}
public boolean isSelected(String userId) {
return userId != null && selectedUserIds.contains(userId);
}
public boolean toggleSelected(String userId) {
if (userId == null) {
return false;
}
if (selectedUserIds.contains(userId)) {
selectedUserIds.remove(userId);
return false;
}
selectedUserIds.add(userId);
return true;
}
public int getSelectedCount() {
return selectedUserIds.size();
}
public ArrayList<String> snapshotSelectedUserIds() {
return new ArrayList<>(selectedUserIds);
}
public void loadExperts(String searchKey) {
List<ExpertBean> experts = ParamedicOperateHelper.getInstance().searchExpert(searchKey, "", "", 1, 10);
expertsLiveData.postValue(experts);
}
public void loadEmployees(String searchKey) {
List<EmployeeBean> employees = ParamedicOperateHelper.getInstance().searchEmployee(searchKey, "", "", "", "", 1, 50);
employeesLiveData.postValue(employees);
}
}
@@ -1,46 +1,99 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.page;
import static com.tencent.qcloud.tuikit.tuichat.TUIChatConstants.CHAT_IS_LIAISON_USER;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.navigation.NavigationView;
import com.tencent.imsdk.v2.V2TIMGroupAtInfo;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.TUILogin;
import com.tencent.qcloud.tuicore.component.activities.BaseLightActivity;
import com.tencent.qcloud.tuicore.util.SPUtils;
import com.tencent.qcloud.tuicore.util.ToastUtil;
import com.tencent.qcloud.tuikit.tuichat.R;
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.DraftInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMember;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.WorkBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.TUIMessageBean;
import com.tencent.qcloud.tuikit.tuichat.classicui.event.CustomMessageEvent;
import com.tencent.qcloud.tuikit.tuichat.classicui.setting.InputActionSetting;
import com.tencent.qcloud.tuikit.tuichat.config.TUIChatConfigs;
import com.tencent.qcloud.tuikit.tuichat.presenter.ParamedicOperateHelper;
import com.tencent.qcloud.tuikit.tuichat.util.ChatMessageBuilder;
import com.tencent.qcloud.tuikit.tuichat.util.ChatMessageParser;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatLog;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public abstract class TUIBaseChatActivity extends BaseLightActivity {
private static final String TAG = TUIBaseChatActivity.class.getSimpleName();
private int mWirkState = -1;
public InputActionSetting inputActionSetting;
private DrawerLayout drawerLayout;
public TextView tvTitle;
/** 右侧抽屉中的群成员列表,供子类(如 TUIGroupChatActivity)绑定 Adapter */
public RecyclerView rvMembers;
public TextView tvAddMember;
public TextView tvUpdateMember;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
TUIChatLog.i(TAG, "onCreate " + this);
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_activity);
setContentView(R.layout.chat_activity_with_navigation);
drawerLayout = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view_right);
View headerView = navigationView.getHeaderView(0);
tvTitle = headerView.findViewById(R.id.tv_title);
rvMembers = headerView.findViewById(R.id.rv_members);
tvAddMember = headerView.findViewById(R.id.tv_add_member);
tvUpdateMember = headerView.findViewById(R.id.tv_update_member);
chat(getIntent());
}
public void openDrawer() {
if (drawerLayout != null) {
drawerLayout.openDrawer(GravityCompat.END);
}
}
public boolean closeDrawer() {
if (drawerLayout != null && drawerLayout.isDrawerOpen(GravityCompat.END)) {
drawerLayout.closeDrawer(GravityCompat.END);
return true;
}
return false;
}
public int getmWirkState() {
return mWirkState;
}
@Override
protected void onNewIntent(Intent intent) {
TUIChatLog.i(TAG, "onNewIntent");
@@ -48,12 +101,47 @@ public abstract class TUIBaseChatActivity extends BaseLightActivity {
chat(intent);
}
@Override
protected void onStart() {
super.onStart();
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
@Override
protected void onResume() {
TUIChatLog.i(TAG, "onResume");
super.onResume();
}
@Override
protected void onStop() {
super.onStop();
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(CustomMessageEvent event) {
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public void onBackPressed() {
if (!closeDrawer()) {
if (mWirkState != -1) {
TUIChatConfigs.getConfigs().getImInputViewActionListener().finishActivityToGuidanceHome(mWirkState);
}
super.onBackPressed();
}
}
private void chat(Intent intent) {
Bundle bundle = intent.getExtras();
TUIChatLog.i(TAG, "bundle: " + bundle + " intent: " + intent);
@@ -62,11 +150,16 @@ public abstract class TUIBaseChatActivity extends BaseLightActivity {
finish();
return;
}
if(inputActionSetting == null){
inputActionSetting = InputActionSetting.createInstance().copy();
if (inputActionSetting == null) {
InputActionSetting fromIntent = (InputActionSetting) intent.getSerializableExtra("inputActionSetting");
if (fromIntent != null) {
inputActionSetting = fromIntent;
} else {
inputActionSetting = InputActionSetting.createInstance().copy();
}
}
startVideoCall(intent);
ChatInfo chatInfo = getChatInfo(intent);
chatInfo.setInputActionSetting(inputActionSetting);
TUIChatLog.i(TAG, "start chatActivity chatInfo: " + chatInfo);
if (chatInfo != null) {
@@ -85,6 +178,8 @@ public abstract class TUIBaseChatActivity extends BaseLightActivity {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 3 && data != null) {
if (requestCode == 11) {
ArrayList<String> stringList2 = data.getStringArrayListExtra("user_namecard_select");
ChatMessageParser.setSelectName(stringList2);
List<String> stringList = data.getStringArrayListExtra("list");
if (stringList != null && !stringList.isEmpty()) {
String[] stringArray = stringList.toArray(new String[]{});
@@ -101,6 +196,12 @@ public abstract class TUIBaseChatActivity extends BaseLightActivity {
}
/**
* 添加成员回传结果处理:由子类(如 TUIGroupChatActivity)实现具体逻辑
*/
protected void onAddMemberResult(ArrayList<String> selectedUserIds) {
}
private ChatInfo getChatInfo(Intent intent) {
int chatType = intent.getIntExtra(TUIConstants.TUIChat.CHAT_TYPE, ChatInfo.TYPE_INVALID);
ChatInfo chatInfo;
@@ -125,7 +226,13 @@ public abstract class TUIBaseChatActivity extends BaseLightActivity {
chatInfo.setLocateMessage(messageInfo);
chatInfo.setAtInfoList((List<V2TIMGroupAtInfo>) intent.getSerializableExtra(TUIConstants.TUIChat.AT_INFO_LIST));
chatInfo.setFaceUrl(intent.getStringExtra(TUIConstants.TUIChat.FACE_URL));
chatInfo.setWorkBean((WorkBean) intent.getSerializableExtra(TUIConstants.TUIChat.WORK_BEAN));
chatInfo.setAutoSendMessage(intent.getStringExtra(TUIConstants.TUIChat.AUTO_SEND_MESSAGE));
chatInfo.setConsultantId(intent.getStringExtra(TUIConstants.TUIChat.CONSULTANT_ID));
WorkBean woekBean = (WorkBean) intent.getSerializableExtra(TUIConstants.TUIChat.WORK_BEAN);
chatInfo.setWorkBean(woekBean);
if (woekBean != null) {
mWirkState = woekBean.getWorkState();
}
if (chatType == ChatInfo.TYPE_GROUP) {
GroupInfo groupInfo = (GroupInfo) chatInfo;
groupInfo.setGroupName(intent.getStringExtra(TUIConstants.TUIChat.GROUP_NAME));
@@ -136,11 +243,35 @@ public abstract class TUIBaseChatActivity extends BaseLightActivity {
groupInfo.setNotice(intent.getStringExtra(TUIConstants.TUIChat.NOTICE));
groupInfo.setOwner(intent.getStringExtra(TUIConstants.TUIChat.OWNER));
groupInfo.setMemberDetails((List<GroupMemberInfo>) intent.getSerializableExtra(TUIConstants.TUIChat.MEMBER_DETAILS));
List<GroupMemberBean> list = ParamedicOperateHelper.getInstance().getActualGroupMemberList(chatInfo.getId());
if (list != null && !list.isEmpty()) {
groupInfo.setMemberDetails(GroupMember.convertFromBeanList(list));
}
}
if (TextUtils.isEmpty(chatInfo.getId())) {
return null;
}
return chatInfo;
}
/**
* 跳转视频通话
*/
private void startVideoCall(Intent intent) {
Boolean initiateVideoCall = intent.getBooleanExtra(TUIConstants.TUIChat.INITIATE_VIDEO_CALL, false);
if (!initiateVideoCall) {
return;
}
String groupId = intent.getStringExtra(TUIConstants.TUIChat.CHAT_ID);
List<String> userIDs = intent.getStringArrayListExtra(TUIConstants.TUICalling.PARAM_NAME_USERIDS);
if (userIDs == null || userIDs.isEmpty()) {
return;
}
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put(TUIConstants.TUICalling.PARAM_NAME_GROUPID, groupId);
hashMap.put(TUIConstants.TUICalling.PARAM_NAME_USERIDS, userIDs.toArray(new String[]{}));
hashMap.put(TUIConstants.TUICalling.PARAM_NAME_TYPE, TUIConstants.TUICalling.TYPE_VIDEO);
TUICore.callService(TUIConstants.TUICalling.SERVICE_NAME,
TUIConstants.TUICalling.METHOD_NAME_CALL, hashMap);
}
}
@@ -22,6 +22,8 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.qcloud.tuicore.TUIConfig;
import com.tencent.qcloud.tuicore.TUIConstants;
@@ -33,22 +35,30 @@ import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuicore.util.ToastUtil;
import com.tencent.qcloud.tuikit.tuichat.R;
import com.tencent.qcloud.tuikit.tuichat.TUIChatConstants;
import com.tencent.qcloud.tuikit.tuichat.TUIChatService;
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.message.CallingMessageBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.LocationMessageBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.TUIMessageBean;
import com.tencent.qcloud.tuikit.tuichat.classicui.event.CustomMessageEvent;
import com.tencent.qcloud.tuikit.tuichat.classicui.setting.ChatLayoutSetting;
import com.tencent.qcloud.tuikit.tuichat.classicui.setting.InputActionSetting;
import com.tencent.qcloud.tuikit.tuichat.component.AudioPlayer;
import com.tencent.qcloud.tuikit.tuichat.classicui.interfaces.OnItemClickListener;
import com.tencent.qcloud.tuikit.tuichat.classicui.widget.ChatView;
import com.tencent.qcloud.tuikit.tuichat.classicui.widget.input.InputView;
import com.tencent.qcloud.tuikit.tuichat.classicui.widget.message.MessageRecyclerView;
import com.tencent.qcloud.tuikit.tuichat.config.TUIChatConfigs;
import com.tencent.qcloud.tuikit.tuichat.presenter.ChatPresenter;
import com.tencent.qcloud.tuikit.tuichat.util.ChatMessageBuilder;
import com.tencent.qcloud.tuikit.tuichat.util.DataStoreUtil;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatLog;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -86,6 +96,17 @@ public class TUIBaseChatFragment extends BaseFragment {
return baseView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
protected void finishEvent(){
}
protected void initView() {
chatView = baseView.findViewById(R.id.chat_layout);
chatView.setFragment(TUIBaseChatFragment.this);
@@ -97,6 +118,7 @@ public class TUIBaseChatFragment extends BaseFragment {
public void onClick(View view) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(chatView.getWindowToken(), 0);
finishEvent();
getActivity().finish();
}
});
@@ -267,6 +289,10 @@ public class TUIBaseChatFragment extends BaseFragment {
String messageJson = data.getStringExtra(ChatLayoutSetting.KEY_CUSTOM_MESSAGE);
if (ChatLayoutSetting.RESULT_CODE_LOCATION == resultCode) {
sendLocationMessage(messageJson);
} else if (ChatLayoutSetting.RESULT_CODE_ARCHIVES == resultCode) {
sendCustomMessage(messageJson);
} else if (ChatLayoutSetting.RESULT_CODE_MEDICAL_EXAMINATION_REPORT == resultCode) {
sendCustomMessage(messageJson);
}
}
}
@@ -319,6 +345,49 @@ public class TUIBaseChatFragment extends BaseFragment {
public ChatPresenter getPresenter() {
return null;
}
public InputActionSetting getInputActionSetting(){
return null;
}
@Override
public void onStart() {
super.onStart();
TUIChatLog.e(TAG, "onStart");
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
@Override
public void onStop() {
super.onStop();
TUIChatLog.e(TAG, "onStop");
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(CustomMessageEvent customMessageEvent) {
if (customMessageEvent == null) {
return;
}
if (isVisible() && customMessageEvent.getChatId().equals(getChatInfo().getId())) {
sendCustomMessage(customMessageEvent.getMessageJson());
}
}
public void sendCustomMessage(String messageJson) {
if (chatView != null && !TextUtils.isEmpty(messageJson)) {
JsonObject tuiMessageObj = new Gson().fromJson(messageJson, JsonObject.class);
TUIChatLog.i(TAG, "customMessageEvent msgContent:" + new Gson().toJson(tuiMessageObj));
JsonElement extensionJson = tuiMessageObj.get("extension");
String extension = extensionJson == null ? TUIChatService.getAppContext().getString(R.string.custom_msg) : extensionJson.getAsString();
TUIMessageBean info = ChatMessageBuilder.buildCustomMessage(messageJson, extension
, extension.getBytes());
chatView.sendMessage(info, false);
}
}
protected void initChatViewBackground() {
if (getChatInfo() == null) {
@@ -1,21 +1,38 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.page;
import static com.tencent.qcloud.tuicore.util.ToastUtil.toastShortMessage;
import static com.tencent.qcloud.tuikit.tuichat.classicui.page.AddMemberActivity.EXTRA_SELECTED_USER_IDS;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.tencent.qcloud.tuicore.util.ToastUtil;
import com.tencent.qcloud.tuikit.tuichat.R;
import com.tencent.qcloud.tuikit.tuichat.TUIChatConstants;
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMember;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.TipsMessageBean;
import com.tencent.qcloud.tuikit.tuichat.classicui.widget.ChatView;
import com.tencent.qcloud.tuikit.tuichat.classicui.widget.GroupMemberNavAdapter;
import com.tencent.qcloud.tuikit.tuichat.presenter.GroupChatPresenter;
import com.tencent.qcloud.tuikit.tuichat.presenter.ParamedicOperateHelper;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatLog;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatUtils;
import java.util.List;
public class TUIGroupChatActivity extends TUIBaseChatActivity {
private static final String TAG = TUIGroupChatActivity.class.getSimpleName();
private TUIGroupChatFragment chatFragment;
private GroupChatPresenter presenter;
private GroupInfo groupInfo;
private GroupMemberNavAdapter adapter;
@Override
public void initChat(ChatInfo chatInfo) {
@@ -25,15 +42,84 @@ public class TUIGroupChatActivity extends TUIBaseChatActivity {
TUIChatLog.e(TAG, "init group chat failed , chatInfo = " + chatInfo);
ToastUtil.toastShortMessage("init group chat failed.");
}
GroupInfo groupInfo = (GroupInfo) chatInfo;
groupInfo = (GroupInfo) chatInfo;
chatFragment = new TUIGroupChatFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(TUIChatConstants.CHAT_INFO, groupInfo);
bundle.putSerializable("inputActionSetting", inputActionSetting);
bundle.putInt(TUIChatConstants.WEEK_STATE, getmWirkState());
chatFragment.setArguments(bundle);
presenter = new GroupChatPresenter();
presenter.initListener();
chatFragment.setPresenter(presenter);
getSupportFragmentManager().beginTransaction().replace(R.id.empty_view, chatFragment).commitAllowingStateLoss();
if (tvTitle != null) {
tvTitle.setText(String.format("群成员 %d", groupInfo.getMemberCount()));
}
// 绑定群成员列表 Adapter,数据来源于 GroupInfo.memberDetails
if (rvMembers != null) {
rvMembers.setLayoutManager(new LinearLayoutManager(this));
adapter = new GroupMemberNavAdapter();
List<GroupMember> memberList = (List<GroupMember>) groupInfo.getMemberDetails();
adapter.setMembers(memberList);
rvMembers.setAdapter(adapter);
}
if (tvAddMember != null) {
tvAddMember.setOnClickListener(v -> {
// 跳转添加成员页面
Intent intent = new Intent(TUIGroupChatActivity.this, AddMemberActivity.class);
intent.putExtra(TUIChatConstants.GROUP_ID, groupInfo.getId());
startActivityForResult(intent, AddMemberActivity.REQUEST_CODE_ADD_MEMBER);
});
}
if (tvUpdateMember != null) {
tvUpdateMember.setOnClickListener(v -> {
List<GroupMemberBean> list = ParamedicOperateHelper.getInstance()
.getActualGroupMemberList(groupInfo.getId());
runOnUiThread(() -> {
adapter.setMembers(GroupMember.convertFromBeanList(list));
tvTitle.setText(String.format("群成员 %d", list.size()));
toastShortMessage("群成员已更新");
});
});
}
// OnGroupTipsListener:群成员加入时自动刷新列表
ChatView.OnGroupTipsListener onGroupTipsListener = new ChatView.OnGroupTipsListener() {
@Override
public void onGroupJoin(TipsMessageBean message) {
List<GroupMemberBean> list = ParamedicOperateHelper.getInstance()
.getActualGroupMemberList(groupInfo.getId());
runOnUiThread(() -> {
adapter.setMembers(GroupMember.convertFromBeanList(list));
tvTitle.setText(String.format("群成员 %d", list.size()));
});
}
};
chatFragment.setOnGroupTipsListener(onGroupTipsListener);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AddMemberActivity.REQUEST_CODE_ADD_MEMBER && resultCode == RESULT_OK) {
if (data != null) {
List<String> memberList = (List<String>) data.getSerializableExtra(EXTRA_SELECTED_USER_IDS);
if (memberList != null && !memberList.isEmpty() && adapter != null && groupInfo != null) {
ParamedicOperateHelper.getInstance().addGroupUser(groupInfo.getId(), memberList, 0, success -> {
if (!success) {
runOnUiThread(() -> ToastUtil.toastShortMessage("添加群成员失败"));
return;
}
List<GroupMemberBean> list = ParamedicOperateHelper.getInstance()
.getActualGroupMemberList(groupInfo.getId());
runOnUiThread(() -> adapter.setMembers(GroupMember.convertFromBeanList(list)));
});
}
}
}
}
}
@@ -1,29 +1,61 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.page;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
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.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.qcloud.tuicore.TUIConstants;
import com.tencent.qcloud.tuicore.TUICore;
import com.tencent.qcloud.tuicore.TUILogin;
import com.tencent.qcloud.tuicore.component.imageEngine.impl.GlideEngine;
import com.tencent.qcloud.tuicore.component.interfaces.IUIKitCallback;
import com.tencent.qcloud.tuikit.tuichat.R;
import com.tencent.qcloud.tuikit.tuichat.TUIChatConstants;
import com.tencent.qcloud.tuikit.tuichat.TUIChatService;
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMember;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberInfo;
import com.tencent.qcloud.tuikit.tuichat.bean.message.TUIMessageBean;
import com.tencent.qcloud.tuikit.tuichat.classicui.interfaces.OnItemClickListener;
import com.tencent.qcloud.tuikit.tuichat.classicui.setting.InputActionSetting;
import com.tencent.qcloud.tuikit.tuichat.classicui.widget.ChatView;
import com.tencent.qcloud.tuikit.tuichat.config.TUIChatConfigs;
import com.tencent.qcloud.tuikit.tuichat.presenter.FileBaseUrlHelper;
import com.tencent.qcloud.tuikit.tuichat.presenter.GroupChatPresenter;
import com.tencent.qcloud.tuikit.tuichat.util.ChatMessageBuilder;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatLog;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class TUIGroupChatFragment extends TUIBaseChatFragment {
private static final String TAG = TUIGroupChatFragment.class.getSimpleName();
private GroupChatPresenter presenter;
private GroupInfo groupInfo;
private InputActionSetting inputActionSetting;
private int mWeekState = -1;
private ChatView.OnGroupTipsListener cachedGroupTipsListener;
@Nullable
@Override
@@ -35,7 +67,9 @@ public class TUIGroupChatFragment extends TUIBaseChatFragment {
if (bundle == null) {
return baseView;
}
mWeekState = bundle.getInt(TUIChatConstants.WEEK_STATE);
groupInfo = (GroupInfo) bundle.getSerializable(TUIChatConstants.CHAT_INFO);
inputActionSetting = (InputActionSetting) bundle.getSerializable("inputActionSetting");
if (groupInfo == null) {
return baseView;
}
@@ -44,17 +78,30 @@ public class TUIGroupChatFragment extends TUIBaseChatFragment {
return baseView;
}
@Override
protected void finishEvent() {
if (mWeekState != -1) {
TUIChatConfigs.getConfigs().getImInputViewActionListener().finishActivityToGuidanceHome(mWeekState);
}
super.finishEvent();
}
public void setOnGroupTipsListener(ChatView.OnGroupTipsListener listener){
// 始终缓存 listener,避免因 commitAllowingStateLoss() 异步导致的时序问题
this.cachedGroupTipsListener = listener;
}
@Override
protected void initView() {
super.initView();
chatView.setPresenter(presenter);
presenter.setGroupInfo(groupInfo);
chatView.setChatInfo(groupInfo);
autoSendMessage();
chatView.getMessageLayout().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onMessageLongClick(View view, int position, TUIMessageBean messageBean) {
// 因为adapter中第一条为加载条目,位置需减1
// Because the first entry in the adapter is the load entry, the position needs to be decremented by 1
chatView.getMessageLayout().showItemPopMenu(position - 1, messageBean, view);
}
@@ -63,14 +110,13 @@ public class TUIGroupChatFragment extends TUIBaseChatFragment {
if (null == messageBean) {
return;
}
//当前项目不需要跳转个人信息
// ChatInfo info = new ChatInfo();
// info.setId(messageBean.getSender());
//
// Bundle bundle = new Bundle();
// bundle.putString(TUIConstants.TUIChat.CHAT_ID, info.getId());
// TUICore.startActivity("FriendProfileActivity", bundle);
String id = messageBean.getSender();
for (GroupMemberInfo groupMemberInfo : groupInfo.getMemberDetails()) {
if (groupMemberInfo.getAccount().equals(id)) {
showPhoneCallDialog((GroupMember) groupMemberInfo);
break;
}
}
}
@Override
@@ -86,7 +132,7 @@ public class TUIGroupChatFragment extends TUIBaseChatFragment {
return;
}
int messageType = messageInfo.getMsgType();
if (messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT){
if (messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) {
chatView.getInputLayout().appendText(messageInfo.getV2TIMMessage().getTextElem().getText());
} else {
TUIChatLog.e(TAG, "error type: " + messageType);
@@ -105,21 +151,23 @@ public class TUIGroupChatFragment extends TUIBaseChatFragment {
}
});
chatView.getTitleBar().setOnRightClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (TUIChatUtils.isTopicGroup(groupInfo.getId())) {
Bundle bundle = new Bundle();
bundle.putString(TUIConstants.TUICommunity.TOPIC_ID, groupInfo.getId());
TUICore.startActivity(getContext(), "TopicInfoActivity", bundle);
} else {
Bundle bundle = new Bundle();
bundle.putString(TUIChatConstants.Group.GROUP_ID, groupInfo.getId());
bundle.putString(TUIConstants.TUIChat.CHAT_BACKGROUND_URI, mChatBackgroundThumbnailUrl);
TUICore.startActivity(getContext(), "GroupInfoActivity", bundle);
}
chatView.getTitleBar().setOnRightClickListener(view -> {
// 打开右侧抽屉
TUIGroupChatActivity activity = (TUIGroupChatActivity) getActivity();
if (activity != null) {
activity.openDrawer();
}
});
titleBar.getRightGroup().setVisibility(View.VISIBLE);
titleBar.getRightTitle().setVisibility(View.GONE);
titleBar.getRightIcon().setVisibility(View.VISIBLE);
titleBar.getRightIcon().setImageResource(R.drawable.chat_title_bar_more_menu_lively);
// 应用缓存的 OnGroupTipsListener,解决 Activity 中提前设置 listener 的时序问题
if (cachedGroupTipsListener != null && chatView != null) {
chatView.setOnGroupTipsListener(cachedGroupTipsListener);
}
}
public void setPresenter(GroupChatPresenter presenter) {
@@ -135,4 +183,139 @@ public class TUIGroupChatFragment extends TUIBaseChatFragment {
public ChatInfo getChatInfo() {
return groupInfo;
}
@Override
public InputActionSetting getInputActionSetting() {
return inputActionSetting;
}
private void autoSendMessage() {
String message = groupInfo.getAutoSendMessage();
if (TextUtils.isEmpty(message)) {
return;
}
JsonObject tuiMessageObj = new Gson().fromJson(message, JsonObject.class);
JsonElement extensionJson = tuiMessageObj.get("extension");
String extension = extensionJson == null ? TUIChatService.getAppContext().getString(R.string.custom_msg) : extensionJson.getAsString();
TUIMessageBean info = ChatMessageBuilder.buildCustomMessage(message, extension
, extension.getBytes());
chatView.sendMessage(info, false);
}
/**
* 显示电话拨打弹窗
*/
private void showPhoneCallDialog(GroupMember groupMember) {
if (groupMember == null || getActivity() == null) {
return;
}
String phone = groupMember.getPhone();
Dialog dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.dialog_phone_call);
Window window = dialog.getWindow();
if (window != null) {
// 背景透明,使用布局自身的圆角白色背景
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams params = window.getAttributes();
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(true);
// 绑定视图
ImageView ivAvatar = dialog.findViewById(R.id.iv_avatar);
ImageView ivClose = dialog.findViewById(R.id.iv_close);
TextView tvName = dialog.findViewById(R.id.tv_name);
TextView tvPhone = dialog.findViewById(R.id.tv_phone);
View btnCall = dialog.findViewById(R.id.btn_call);
View btnCancel = dialog.findViewById(R.id.btn_cancel);
// 头像加载(圆形)
String avatar = FileBaseUrlHelper.getInstance().getIconBaseUrl() + groupMember.getAvatar();
GlideEngine.loadUserCircleIcon(ivAvatar, avatar, R.drawable.default_user_icon);
// 姓名
String name = groupMember.getUserName();
if (groupMember.getIsSelf() == 1) {
name = "";
}
tvName.setText(name);
// 电话号码占位
tvPhone.setText(phone);
// 关闭按钮与取消按钮
ivClose.setOnClickListener(v -> dialog.dismiss());
btnCancel.setOnClickListener(v -> dialog.dismiss());
// 拨打电话:拉起系统拨号界面
btnCall.setOnClickListener(v -> {
try {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phone));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch (Exception e) {
TUIChatLog.e(TAG, "拉起系统拨号失败: " + e.getMessage());
}
dialog.dismiss();
});
dialog.show();
}
/**
* 发起视频通话
*/
private void initiateVideoCall() {
presenter.loadGroupMembers(groupInfo.getId(), new IUIKitCallback<List<GroupMemberInfo>>() {
@Override
public void onSuccess(List<GroupMemberInfo> data) {
startVideoCall(data);
}
});
}
/**
* 跳转视频通话
*/
private void startVideoCall(List<GroupMemberInfo> data) {
if (data == null || data.isEmpty()) {
return;
}
data = filterMember(data);
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put(TUIConstants.TUICalling.PARAM_NAME_GROUPID, groupInfo.getId());
hashMap.put(TUIConstants.TUICalling.PARAM_NAME_USERIDS, getMembersAccount(data).toArray(new String[]{}));
hashMap.put(TUIConstants.TUICalling.PARAM_NAME_TYPE, TUIConstants.TUICalling.TYPE_VIDEO);
TUICore.callService(TUIConstants.TUICalling.SERVICE_NAME,
TUIConstants.TUICalling.METHOD_NAME_CALL, hashMap);
}
private List<GroupMemberInfo> filterMember(List<GroupMemberInfo> list) {
for (int i = list.size() - 1; i >= 0; i--) {
if (TUILogin.getUserId().equals(list.get(i).getAccount())) {
list.remove(i);
}
if ("000000".equals(list.get(i).getAccount())) {
list.remove(i);
}
}
return list;
}
private List<String> getMembersAccount(List<GroupMemberInfo> mMembers) {
if (mMembers.size() == 0) {
return new ArrayList<>();
}
List<String> friendIdList = new ArrayList<>();
for (int i = 0; i < mMembers.size(); i++) {
friendIdList.add(mMembers.get(i).getAccount());
}
return friendIdList;
}
}
@@ -61,7 +61,7 @@ public class ChatLayoutSetting {
}
}
public void customizeChatLayout(final ChatView layout) {
public void customizeChatLayout(final ChatView layout, InputActionSetting inputActionSetting) {
// //====== NoticeLayout使用范例 ======//
//====== NoticeLayout example======//
@@ -187,6 +187,13 @@ public class ChatLayoutSetting {
//====== InputLayout使用范例 ======//
//====== InputLayout example ======//
final InputView inputView = layout.getInputLayout();
InputActionSetting mInputActionSetting = inputActionSetting;
if (mInputActionSetting == null){
mInputActionSetting = InputActionSetting.getsInstance();
if (mInputActionSetting == null) {
mInputActionSetting = new InputActionSetting();
}
}
// // TODO 隐藏音频输入的入口,可以打开下面代码测试
// // To hide the entrance of audio input, you can open the following code to test
@@ -220,7 +227,7 @@ public class ChatLayoutSetting {
//隐藏音频通话
inputView.disableAudioCall(true);
//隐藏视频通话
inputView.disableVideoCall(true);
inputView.disableVideoCall(mInputActionSetting.isDisableVideoCall());
// 增加名片
InputMoreActionUnit businessCardUnit = new InputMoreActionUnit() {
@@ -291,7 +298,9 @@ public class ChatLayoutSetting {
actionClick(layout, endConsultUnit.getActionId());
}
});
inputView.addAction(endConsultUnit);
if(!mInputActionSetting.isDisableFinishSession()){
inputView.addAction(endConsultUnit);
}
// 评价
InputMoreActionUnit evaluationUnit = new InputMoreActionUnit() {
};
@@ -26,6 +26,43 @@ public class InputActionSetting implements Serializable {
private boolean disableAudioCall = false;
private boolean disableVideoCall = false;
private boolean disableSendMessage = false;
private boolean disableFinishSession = false;
public boolean disableFinishName = false;
public String packageName="";
public String CurrentResourceHost="";
public boolean disableEvaluate = false;
public String getCurrentResourceHost() {
return CurrentResourceHost == null ? "" : CurrentResourceHost;
}
public void setCurrentResourceHost(String currentResourceHost) {
CurrentResourceHost = currentResourceHost;
}
public String getPackageName() {
return packageName == null ? "" : packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public static InputActionSetting getsInstance() {
return sInstance;
}
public static void setsInstance(InputActionSetting sInstance) {
InputActionSetting.sInstance = sInstance;
}
public boolean isDisableEvaluate() {
return disableEvaluate;
}
public void setDisableEvaluate(boolean disableEvaluate) {
this.disableEvaluate = disableEvaluate;
}
public boolean isDisableVideoRecord() {
return disableVideoRecord;
@@ -74,6 +111,23 @@ public class InputActionSetting implements Serializable {
public void setDisableSendMessage(boolean disableSendMessage) {
this.disableSendMessage = disableSendMessage;
}
public boolean isDisableFinishSession() {
return disableFinishSession;
}
public void setDisableFinishSession(boolean disableFinishSession) {
this.disableFinishSession = disableFinishSession;
}
public boolean isDisableFinishName() {
return disableFinishName;
}
public void setDisableFinishName(boolean disableFinishName) {
this.disableFinishName = disableFinishName;
}
public InputActionSetting copy(){
InputActionSetting inputActionSetting = new InputActionSetting();
inputActionSetting.setDisableArchives(disableArchives);
@@ -82,6 +136,8 @@ public class InputActionSetting implements Serializable {
inputActionSetting.setDisableVideoCall(disableVideoCall);
inputActionSetting.setDisableVideoRecord(disableVideoRecord);
inputActionSetting.setDisableMedicalExaminationReport(disableMedicalExaminationReport);
inputActionSetting.setDisableFinishSession(disableFinishSession);
inputActionSetting.setDisableFinishName(disableFinishName);
return inputActionSetting;
}
}
@@ -51,6 +51,7 @@ import com.tencent.qcloud.tuikit.tuichat.bean.MessageTyping;
import com.tencent.qcloud.tuikit.tuichat.bean.ReplyPreviewBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.ReplyMessageBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.SystemMessageBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.TipsMessageBean;
import com.tencent.qcloud.tuikit.tuichat.bean.message.TUIMessageBean;
import com.tencent.qcloud.tuikit.tuichat.classicui.setting.InputActionSetting;
import com.tencent.qcloud.tuikit.tuichat.component.AudioPlayer;
@@ -148,6 +149,7 @@ public class ChatView extends LinearLayout implements IChatLayout {
private boolean isSupportTyping = false;
private ChatPresenter presenter;
private OnGroupTipsListener onGroupTipsListener;
ChatLayoutSetting chatLayoutSetting;
public ChatView(Context context) {
@@ -261,6 +263,15 @@ public class ChatView extends LinearLayout implements IChatLayout {
public void setFragment(Fragment fragment) {
this.fragment = fragment;
}
public interface OnGroupTipsListener {
void onGroupJoin(TipsMessageBean message);
}
public void setOnGroupTipsListener(OnGroupTipsListener onGroupTipsListener) {
this.onGroupTipsListener = onGroupTipsListener;
}
private void initGroupAtInfoLayout() {
if (mChatInfo != null) {
List<V2TIMGroupAtInfo> groupAtInfos = mChatInfo.getAtInfoList();
@@ -458,6 +469,14 @@ public class ChatView extends LinearLayout implements IChatLayout {
goneInputLayout();
}
}
if (message instanceof TipsMessageBean) {
TipsMessageBean tips = (TipsMessageBean) message;
if (tips.getTipType() == TipsMessageBean.MSG_TYPE_GROUP_JOIN
&& onGroupTipsListener != null) {
onGroupTipsListener.onGroupJoin(tips);
}
}
}
@Override
@@ -923,7 +942,7 @@ public class ChatView extends LinearLayout implements IChatLayout {
mMessageRecyclerView.setAdapter(mAdapter);
}
chatLayoutSetting = new ChatLayoutSetting(getContext());
chatLayoutSetting.customizeChatLayout(this);
chatLayoutSetting.customizeChatLayout(this,inputActionSetting);
initListener();
resetForwardState("");
if(inputActionSetting != null&&inputActionSetting.isDisableSendMessage()){
@@ -0,0 +1,100 @@
package com.tencent.qcloud.tuikit.tuichat.classicui.widget;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.tencent.qcloud.tuicore.component.imageEngine.impl.GlideEngine;
import com.tencent.qcloud.tuikit.tuichat.R;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMember;
import com.tencent.qcloud.tuikit.tuichat.presenter.FileBaseUrlHelper;
import com.tencent.qcloud.tuikit.tuichat.util.TUIChatLog;
import java.util.ArrayList;
import java.util.List;
/**
* NavigationView 右侧抽屉中群成员列表的适配器。
*/
public class GroupMemberNavAdapter extends RecyclerView.Adapter<GroupMemberNavAdapter.MemberViewHolder> {
private final List<GroupMember> members = new ArrayList<>();
public void setMembers(List<GroupMember> data) {
members.clear();
if (data != null) {
members.addAll(data);
}
notifyDataSetChanged();
}
@NonNull
@Override
public MemberViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_group_member_nav, parent, false);
return new MemberViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull MemberViewHolder holder, int position) {
GroupMember member = members.get(position);
if (member == null) {
return;
}
String avatar = FileBaseUrlHelper.getInstance().getIconBaseUrl() + member.getAvatar();
GlideEngine.loadUserCircleIcon(holder.ivAvatar, avatar, R.drawable.default_user_icon);
String name = member.getUserName();
if (member.getIsSelf() == 1) {
name = "";
}
holder.tvName.setText(name);
String type = "员工";
if (member.getMemberType() == 1) {
type = "专业人员";
} else if (member.getMemberType() == 2) {
type = "员工";
} else if (member.getMemberType() == 0) {
type = "操作人员";
} else if (member.getMemberType() == -1) {
type = "发起人";
}
holder.tvType.setText(type);
holder.ivCall.setOnClickListener(v -> {
try {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + member.getPhone()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
v.getContext().startActivity(intent);
} catch (Exception e) {
TUIChatLog.e("GroupMemberNavAdapter", "拉起系统拨号失败: " + e.getMessage());
}
});
}
@Override
public int getItemCount() {
return members.size();
}
static class MemberViewHolder extends RecyclerView.ViewHolder {
ImageView ivAvatar;
ImageView ivCall;
TextView tvName;
TextView tvType;
MemberViewHolder(@NonNull View itemView) {
super(itemView);
ivAvatar = itemView.findViewById(R.id.iv_avatar);
tvName = itemView.findViewById(R.id.tv_name);
tvType = itemView.findViewById(R.id.tv_type);
ivCall = itemView.findViewById(R.id.iv_call);
}
}
}
@@ -0,0 +1,5 @@
package com.tencent.qcloud.tuikit.tuichat.interfaces;
public interface FileBaseUrlListener {
String getIconBaseUrl();
}
@@ -6,4 +6,6 @@ package com.tencent.qcloud.tuikit.tuichat.interfaces;
*/
public interface IMInputViewActionListener {
void finishAction(int workType, String workId);
void appraiseAction(String chatId, int workType, String workId);
void finishActivityToGuidanceHome(int workType);
}
@@ -0,0 +1,31 @@
package com.tencent.qcloud.tuikit.tuichat.presenter;
import com.tencent.qcloud.tuikit.tuichat.interfaces.FileBaseUrlListener;
public class FileBaseUrlHelper {
private FileBaseUrlListener listener;
private static FileBaseUrlHelper instance;
public void setListener(FileBaseUrlListener listener) {
this.listener = listener;
}
private FileBaseUrlHelper() {
// 私有构造
}
public static synchronized FileBaseUrlHelper getInstance() {
if (instance == null) {
instance = new FileBaseUrlHelper();
}
return instance;
}
public String getIconBaseUrl() {
if (listener != null) {
return listener.getIconBaseUrl();
} else {
return null;
}
}
}
@@ -0,0 +1,74 @@
package com.tencent.qcloud.tuikit.tuichat.presenter;
import androidx.core.util.Consumer;
import com.tencent.qcloud.tuikit.tuichat.bean.EmployeeBean;
import com.tencent.qcloud.tuikit.tuichat.bean.ExpertBean;
import com.tencent.qcloud.tuikit.tuichat.bean.GroupMemberBean;
import com.tencent.qcloud.tuikit.tuichat.classicui.interfaces.OnParamedicOperateListener;
import java.util.List;
public class ParamedicOperateHelper {
private OnParamedicOperateListener listener;
private static ParamedicOperateHelper instance;
public void setListener(OnParamedicOperateListener listener) {
this.listener = listener;
}
private ParamedicOperateHelper() {
// 私有构造
}
public static synchronized ParamedicOperateHelper getInstance() {
if (instance == null) {
instance = new ParamedicOperateHelper();
}
return instance;
}
public List<GroupMemberBean> getActualGroupMemberList(String sessionId) {
if (listener != null) {
return listener.getActualGroupMemberList(sessionId);
}
return null;
}
/**
* 邀请成员加入群组。操作异步执行,结果通过 callback 回传。
*
* @param groupId 目标群组 ID
* @param memberList 待加入成员的 userId 列表
* @param memberType 成员类型
* @param callback 结果回调;当未注册 listener 时直接回调 false,避免调用方无限等待
*/
public void addGroupUser(String groupId, List<String> memberList, int memberType, Consumer<Boolean> callback) {
if (listener != null) {
listener.addGroupUser(groupId, memberList, memberType, callback);
} else if (callback != null) {
callback.accept(false);
}
}
public List<ExpertBean> searchExpert(String realname, String centerId, String excludeSessionId, int pageNo, int pageSize) {
if (listener != null) {
return listener.searchExpert(realname, centerId, excludeSessionId, pageNo, pageSize);
}
return null;
}
public List<EmployeeBean> searchEmployee(String realname, String orgCode, String workNo, String phone, String excludeSessionId, int pageNo, int pageSize) {
if (listener != null) {
return listener.searchEmployee(realname, orgCode, workNo, phone, excludeSessionId, pageNo, pageSize);
}
return null;
}
public void removeGroupUser(String groupId, List<String> memberList) {
if (listener != null) {
listener.removeGroupUser(groupId, memberList);
}
}
}
@@ -46,6 +46,12 @@ import java.util.Map;
public class ChatMessageParser {
private static final String TAG = ChatMessageParser.class.getSimpleName();
private static ArrayList<String> mSelectName = new ArrayList<String>();
public static void setSelectName(ArrayList<String> list) {
mSelectName.clear();
mSelectName.addAll(list);
}
public static TUIMessageBean parseMessage(V2TIMMessage v2TIMMessage) {
System.out.println("聊天消息接受"+v2TIMMessage);
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#E6F6F6" />
<corners android:radius="8dp" />
<stroke
android:width="1dp"
android:color="#ff2eb8b2" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/tab_track_color" />
<corners android:radius="8dp" />
</shape>
@@ -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="#FF1AAD19" />
<corners android:radius="22dp" />
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 电话拨打 Dialog 白色圆角背景 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFFFF" />
<corners android:radius="16dp" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="6dp" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/theme_color" />
<corners android:radius="12dp" />
</shape>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="8dp" />
<stroke
android:width="1dp"
android:color="#666666" />
</shape>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/ic_check_circle"/>
<item android:drawable="@drawable/ic_circle_stroke"/>
</selector>
@@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2A10,10 0 0 1 22,12A10,10 0 0 1 12,22A10,10 0 0 1 2,12A10,10 0 0 1 12,2z"
android:strokeColor="#2EB8B2"
android:strokeWidth="2"
android:fillColor="#00000000"/>
<path
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"
android:fillColor="#2EB8B2"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2A10,10 0 0 1 22,12A10,10 0 0 1 12,22A10,10 0 0 1 2,12A10,10 0 0 1 12,2z"
android:strokeColor="#666666"
android:strokeWidth="2"
android:fillColor="#00000000"/>
</vector>
@@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2A10,10 0,1 0,12 22A10,10 0,1 0,12 2Z"
android:fillColor="#CCCCCC" />
<path
android:pathData="M8.5,8.5L15.5,15.5M15.5,8.5L8.5,15.5"
android:strokeWidth="2"
android:strokeColor="#FFFFFF"
android:strokeLineCap="round" />
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFFFF">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6.62,10.79c1.44,2.83 3.76,5.15 6.59,6.59l2.2,-2.2c0.28,-0.28 0.67,-0.36 1.02,-0.25 1.12,0.37 2.33,0.57 3.57,0.57 0.55,0 1,0.45 1,1V20c0,0.55 -0.45,1 -1,1 -9.39,0 -17,-7.61 -17,-17 0,-0.55 0.45,-1 1,-1h3.5c0.55,0 1,0.45 1,1 0,1.25 0.2,2.45 0.57,3.57 0.11,0.35 0.03,0.74 -0.25,1.02l-2.2,2.2z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF999999"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
</vector>
@@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#999999">
<path
android:pathData="M10,2A8,8 0,1 0,10 18A8,8 0,1 0,10 2Z M10,4A6,6 0,1 1,10 16A6,6 0,1 1,10 4Z"
android:fillColor="#F6F6F6" />
<path
android:pathData="M14.5,14.5L20,20L20,20L14.5,14.5Z"
android:strokeWidth="2"
android:strokeColor="#F6F6F6"
android:strokeLineCap="round" />
</vector>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<layer-list>
<item
android:left="2dp"
android:top="2dp"
android:right="2dp"
android:bottom="2dp"
android:drawable="@drawable/bg_tab_selected_white"/>
</layer-list>
</item>
<item android:drawable="@android:color/transparent" />
</selector>
@@ -0,0 +1,140 @@
<?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="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/white">
<LinearLayout
android:id="@+id/ll_back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="12dp"
android:paddingEnd="12dp">
<ImageView
android:id="@+id/iv_back"
android:layout_width="20dp"
android:layout_height="20dp"
android:contentDescription="@null"
android:src="@drawable/chat_back"
app:tint="@color/text_color_black_33" />
</LinearLayout>
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/add_member_title"
android:textColor="@color/text_color_title"
android:textSize="18sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
android:background="@color/split_lint_color" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<EditText
android:id="@+id/et_search"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_marginEnd="12dp"
android:layout_weight="1"
android:background="@drawable/bg_gray_round_8"
android:drawableStart="@drawable/ic_search"
android:drawablePadding="6dp"
android:hint="@string/add_member_search_hint"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:textColor="@color/text_color_black_33"
android:textColorHint="@color/text_color_search_hint"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_search_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_member_search_action"
android:textColor="@color/text_color_search"
android:textSize="13sp" />
</LinearLayout>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_gray_round_8"
app:tabBackground="@drawable/selector_tab_bg"
app:tabGravity="fill"
app:tabIndicator="@null"
app:tabIndicatorColor="@color/transparent"
app:tabIndicatorHeight="0dp"
app:tabMinWidth="0dp"
app:tabMode="fixed"
app:tabRippleColor="@color/transparent"
app:tabSelectedTextColor="@color/theme_color"
app:tabTextColor="@color/text_color_unselected" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_members"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:overScrollMode="never" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/split_lint_color" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="72dp"
android:gravity="center"
android:orientation="horizontal"
android:layout_marginStart="48dp"
android:paddingTop="12dp"
android:layout_marginEnd="48dp"
android:paddingBottom="12dp">
<TextView
android:id="@+id/tv_confirm"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@drawable/bg_theme_round_24"
android:gravity="center"
android:text="@string/add_member_confirm"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view_right"
android:layout_width="280dp"
android:layout_height="match_parent"
app:headerLayout="@layout/chat_navigation_header"
android:layout_gravity="end" />
</androidx.drawerlayout.widget.DrawerLayout>
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 顶部:群成员标题 -->
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginBottom="16dp"
android:background="@color/split_lint_color" />
<!-- 中部:群成员列表 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_members"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:overScrollMode="never" />
<TextView
android:id="@+id/tv_update_member"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="40dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:paddingStart="60dp"
android:paddingEnd="60dp"
android:drawableLeft="@drawable/ic_update_circle"
android:background="@drawable/bg_update_member_button"
android:textColor="#2C2C2C"
android:textSize="16sp"
android:text="更新群成员" />
<!-- 底部:添加成员入口 -->
<TextView
android:id="@+id/tv_add_member"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:paddingStart="60dp"
android:paddingEnd="60dp"
android:drawableLeft="@drawable/ic_plus_circle"
android:background="@drawable/bg_add_member_button"
android:textColor="#ff2eb8b2"
android:textSize="16sp"
android:text="添加成员" />
</LinearLayout>
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 电话拨打 Dialog 布局:白色圆角弹窗,包含关闭按钮、头像、姓名、电话、拨打/取消按钮 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_phone_call_dialog"
android:padding="24dp">
<!-- 右上角关闭按钮 -->
<ImageView
android:id="@+id/iv_close"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="end|top"
android:contentDescription="@null"
android:src="@drawable/ic_phone_call_close" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<!-- 成员头像 -->
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="80dp"
android:layout_height="80dp"
android:contentDescription="@null" />
<!-- 成员姓名 -->
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:textColor="#333333"
android:textSize="18sp"
android:textStyle="bold" />
<!-- 电话号码 -->
<TextView
android:id="@+id/tv_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:textColor="#999999"
android:textSize="14sp" />
<!-- 拨打电话按钮 -->
<LinearLayout
android:id="@+id/btn_call"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginTop="24dp"
android:background="@drawable/bg_phone_call_btn"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="18dp"
android:layout_height="18dp"
android:contentDescription="@null"
android:src="@drawable/ic_phone_call" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/phone_call_dialog_call"
android:textColor="#FFFFFFFF"
android:textSize="16sp" />
</LinearLayout>
<!-- 取消按钮 -->
<TextView
android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginTop="12dp"
android:gravity="center"
android:text="@string/phone_call_dialog_cancel"
android:textColor="#666666"
android:textSize="15sp" />
</LinearLayout>
</FrameLayout>
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="?android:attr/selectableItemBackground">
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="44dp"
android:layout_height="44dp"
android:contentDescription="@null"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:textStyle="bold"
android:maxLines="1"
android:textColor="@color/text_color_black_33"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_post"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/text_gray1"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_dept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/text_gray1"
android:textSize="12sp" />
</LinearLayout>
<CheckBox
android:id="@+id/cb_select"
android:layout_width="24dp"
android:layout_height="24dp"
android:clickable="false"
android:focusable="false"
android:button="@drawable/checkbox_custom"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_gravity="top"
android:background="@color/split_lint_color" />
</FrameLayout>
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- NavigationView 右侧抽屉中的群成员列表项 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:scaleType="centerCrop" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal">
<LinearLayout
android:layout_marginTop="8dp"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:textStyle="bold"
android:maxLines="1"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_type"
android:layout_marginTop="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/text_gray1"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:id="@+id/iv_call"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
android:src="@drawable/chat_phone_call"
android:contentDescription="@null"
android:scaleType="centerCrop" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_gravity="bottom"
android:layout_height="0.5dp"
android:background="@color/split_lint_color" />
</FrameLayout>
</LinearLayout>
@@ -59,4 +59,10 @@
<color name="text_color_black_4A">#4A4A4A</color>
<color name="rating_bar_color">#F19927</color>
<color name="tab_track_color">#F2F3F5</color>
<color name="text_color_title">#252535</color>
<color name="text_color_unselected">#808080</color>
<color name="text_color_search">#77849E</color>
<color name="text_color_search_hint">#B6B6B6</color>
</resources>
@@ -263,4 +263,20 @@
<string name="chat_message_system_go_perfect">去完善</string>
<!--评价-->
<string name="chat_message_appraise_title">服务评价</string>
<!--电话拨打弹窗-->
<string name="phone_call_dialog_call">拨打电话</string>
<string name="phone_call_dialog_cancel">取消</string>
<!--添加成员-->
<string name="add_member_back">返回</string>
<string name="add_member_title">选择联系人</string>
<string name="add_member_tab_expert">邀请专家</string>
<string name="add_member_tab_employee">邀请员工</string>
<string name="add_member_selected_count">已选择 0 人</string>
<string name="add_member_confirm">确定</string>
<string name="add_member_empty">暂无数据</string>
<string name="add_member_search_hint">搜索联系人</string>
<string name="add_member_search_action">搜索</string>
</resources>
@@ -85,6 +85,7 @@ public class StartGroupMemberSelectActivity extends BaseLightActivity {
limit = getIntent().getIntExtra(TUIContactConstants.Selection.LIMIT, Integer.MAX_VALUE);
alreadySelectedList = getIntent().getStringArrayListExtra(TUIContactConstants.Selection.SELECTED_LIST);
mTitleBar = findViewById(R.id.group_create_title_bar);
mTitleBar.setTitle(getString(R.string.select_group_member), ITitleBarLayout.Position.MIDDLE);
mTitleBar.setTitle(getResources().getString(com.tencent.qcloud.tuicore.R.string.sure), ITitleBarLayout.Position.RIGHT);
mTitleBar.getRightIcon().setVisibility(View.GONE);
mTitleBar.setOnRightClickListener(new View.OnClickListener() {
@@ -16,12 +16,13 @@
android:paddingLeft="15.36dp">
<CheckBox
android:layout_marginTop="5dp"
android:id="@+id/contact_check_box"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginRight="10dp"
android:button="@null"
android:background="@drawable/contact_checkbox_selector"
android:button="@null"
android:clickable="false"
android:focusable="false"
android:visibility="gone" />
@@ -30,24 +31,24 @@
android:layout_width="45dp"
android:layout_height="@dimen/contact_avatar_width">
<com.tencent.qcloud.tuicore.component.gatherimage.ShadeImageView
android:id="@+id/ivAvatar"
android:layout_width="@dimen/contact_avatar_width"
android:layout_height="@dimen/contact_avatar_height"
android:clickable="false"
android:focusable="false" />
<com.tencent.qcloud.tuicore.component.gatherimage.ShadeImageView
android:id="@+id/ivAvatar"
android:layout_width="@dimen/contact_avatar_width"
android:layout_height="@dimen/contact_avatar_height"
android:clickable="false"
android:focusable="false" />
<View
android:id="@+id/user_status"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="0dp"
android:layout_marginBottom="1dp"
android:background="?attr/user_status_offline"
android:visibility="gone"
android:elevation="4dp" />
android:elevation="4dp"
android:visibility="gone" />
</RelativeLayout>
@@ -62,13 +63,13 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:singleLine="true"
android:ellipsize="end"
android:textSize="17.28sp"
android:lineHeight="23.04sp"
android:clickable="false"
android:ellipsize="end"
android:focusable="false"
android:lineHeight="23.04sp"
android:singleLine="true"
android:textColor="@color/black_font_color"
android:textSize="17.28sp"
tools:text="@string/default_friend" />
<com.tencent.qcloud.tuicore.component.UnreadCountTextView
@@ -92,6 +92,7 @@
<string name="modify_group_name">Edit Group Name</string>
<string name="add_group_member">Add Member</string>
<string name="select_group_member">选择群成员</string>
<string name="group_join_type">Group Joining Method</string>
<string name="forbid_join">Prohibited from Joining</string>
<string name="manager_judge">Admin Approval</string>
@@ -113,6 +113,9 @@ public final class TUIConstants {
public static final String FACE_URL_LIST = "faceUrlList";
/*当下公司业务传输数据使用*/
public static final String WORK_BEAN = "workBean";
public static final String INITIATE_VIDEO_CALL = "initiateVideoCall";
public static final String AUTO_SEND_MESSAGE = "autoSendMessage";
public static final String CONSULTANT_ID = "consultantId";
public static final String JOIN_TYPE = "joinType";
public static final String MEMBER_COUNT = "memberCount";
public static final String RECEIVE_OPTION = "receiveOption";