From 8115209dafc178f61ca3b8b8772138aaf085071e Mon Sep 17 00:00:00 2001 From: huangjian Date: Fri, 22 Apr 2022 18:03:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=88=BF=E9=97=B4@=E4=BA=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erban/avroom/ButtonItemFactory.java | 11 ++ .../erban/avroom/fragment/BaseRoomFragment.kt | 38 +++++- .../fragment/HomePartyRoomFragment.java | 3 + .../avroom/presenter/BaseRoomPresenter.java | 6 +- .../avroom/presenter/HomePartyPresenter.java | 10 -- .../erban/avroom/widget/MessageView.java | 121 +++++++++++++++++- .../avroom/widget/OnMsgLongClickListener.java | 7 + .../yizhuan/erban/avroom/widget/ViewItem.java | 5 + .../erban/ui/widget/UserInfoDialog.java | 17 ++- .../res/drawable-xhdpi/icon_dialog_ait.png | Bin 0 -> 2415 bytes app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../xchat_android_core/helper/AtProxy.java | 65 ++++++++++ .../manager/IMNetEaseManager.java | 9 +- .../yizhuan/xchat_android_core/DemoCache.java | 23 ++++ .../room/event/RoomAtEvent.java | 11 ++ .../user/bean/UserInfo.java | 2 + .../utils/ExtensionUtil.java | 36 +++++- .../uikit/business/ait/AitContactsModel.java | 6 +- .../nim/uikit/business/ait/AitManager.java | 8 ++ 20 files changed, 355 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/com/yizhuan/erban/avroom/widget/OnMsgLongClickListener.java create mode 100644 app/src/main/res/drawable-xhdpi/icon_dialog_ait.png create mode 100644 core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/helper/AtProxy.java create mode 100644 core/src/main/java/com/yizhuan/xchat_android_core/room/event/RoomAtEvent.java diff --git a/app/src/main/java/com/yizhuan/erban/avroom/ButtonItemFactory.java b/app/src/main/java/com/yizhuan/erban/avroom/ButtonItemFactory.java index 2492947d8..3a5fed5d4 100644 --- a/app/src/main/java/com/yizhuan/erban/avroom/ButtonItemFactory.java +++ b/app/src/main/java/com/yizhuan/erban/avroom/ButtonItemFactory.java @@ -167,6 +167,8 @@ public class ButtonItemFactory { //关注 buttonItems.add(createAttentItem()); + //关注 + buttonItems.add(createAtItem()); final RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; if (currentRoom == null) return buttonItems; @@ -303,6 +305,15 @@ public class ButtonItemFactory { return viewItem; } + /** + * @Ta + */ + public static ViewItem createAtItem() { + ViewItem viewItem = new ViewItem("@Ta", R.drawable.icon_dialog_ait, null); + viewItem.isAt = true; + return viewItem; + } + /** * 踢出房间: 先强制下麦,再踢出房间 */ diff --git a/app/src/main/java/com/yizhuan/erban/avroom/fragment/BaseRoomFragment.kt b/app/src/main/java/com/yizhuan/erban/avroom/fragment/BaseRoomFragment.kt index 0bf293862..428f8f6c2 100644 --- a/app/src/main/java/com/yizhuan/erban/avroom/fragment/BaseRoomFragment.kt +++ b/app/src/main/java/com/yizhuan/erban/avroom/fragment/BaseRoomFragment.kt @@ -50,6 +50,7 @@ import com.yizhuan.erban.avroom.view.IBaseRoomView import com.yizhuan.erban.avroom.widget.BottomView import com.yizhuan.erban.avroom.widget.MessageView import com.yizhuan.erban.avroom.widget.MicroView +import com.yizhuan.erban.avroom.widget.OnMsgLongClickListener import com.yizhuan.erban.base.BaseMvpActivity import com.yizhuan.erban.base.BaseMvpFragment import com.yizhuan.erban.event.OpenRoomIntroEvent @@ -79,6 +80,7 @@ import com.yizhuan.xchat_android_core.auth.AuthModel import com.yizhuan.xchat_android_core.bean.RoomMicInfo import com.yizhuan.xchat_android_core.gift.GiftModel import com.yizhuan.xchat_android_core.gift.bean.GiftInfo +import com.yizhuan.xchat_android_core.helper.AtProxy import com.yizhuan.xchat_android_core.home.bean.BannerInfo import com.yizhuan.xchat_android_core.im.custom.bean.RoomFollowOwnerAttachment import com.yizhuan.xchat_android_core.im.custom.bean.RoomFollowOwnerAttachment2 @@ -91,6 +93,7 @@ import com.yizhuan.xchat_android_core.mentoring_relationship.event.MentoringStop import com.yizhuan.xchat_android_core.room.anotherroompk.ShowGiftDialogEvent import com.yizhuan.xchat_android_core.room.anotherroompk.ShowUserInfoDialogEvent import com.yizhuan.xchat_android_core.room.bean.RoomInfo +import com.yizhuan.xchat_android_core.room.event.RoomAtEvent import com.yizhuan.xchat_android_core.room.event.RoomClearScreenEvent import com.yizhuan.xchat_android_core.room.game.GameStatus import com.yizhuan.xchat_android_core.room.giftvalue.helper.GiftValueMrg @@ -115,8 +118,6 @@ import io.reactivex.disposables.Disposable import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -import java.util.* -import kotlin.collections.ArrayList /** @@ -171,6 +172,9 @@ open class BaseRoomFragment?> : private var dynamicFaceDialog: DynamicFaceDialog? = null private var giftDialog: GiftDialog? = null + private var atProxy: AtProxy? = null + + @CallSuper override fun onFindViews() { messageView = mView.findViewById(R.id.message_view) @@ -207,6 +211,13 @@ open class BaseRoomFragment?> : KeyBoardUtils.hideKeyBoard(activity, inputEdit) false } + + + messageView.setOnLongClickListener { _, account, name -> + showInputLayout() + if (atProxy == null) atProxy = AtProxy(inputEdit) + atProxy?.insertAitMember(account, name) + } softKeyboardListener() } @@ -670,7 +681,7 @@ open class BaseRoomFragment?> : toast("房间公屏已关闭") return } - mvpPresenter?.sendTextMsg(msg) + mvpPresenter?.sendTextMsg(msg, atProxy) messageView.setNeedAutoScroll(true) // 发送后自动滚动公屏列表 inputEdit.setText("") } @@ -1158,6 +1169,27 @@ open class BaseRoomFragment?> : } } + /** + * 用户弹窗点击@Ta + * + * @param event + */ + @Subscribe(threadMode = ThreadMode.MAIN) + open fun onRoomAtEvent(event: RoomAtEvent) { + if (atProxy == null) atProxy = AtProxy(inputEdit) + showInputLayout() + atProxy?.insertAitMember(event.account, event.name) + } + + private fun showInputLayout() { + inputLayout.postDelayed({ + inputLayout.visibility = View.VISIBLE + inputEdit.isFocusableInTouchMode = true + inputEdit.requestFocus() + KeyBoardUtils.showKeyBoard(context, inputEdit) + },200) + } + /** * 底部按钮点击处理 */ diff --git a/app/src/main/java/com/yizhuan/erban/avroom/fragment/HomePartyRoomFragment.java b/app/src/main/java/com/yizhuan/erban/avroom/fragment/HomePartyRoomFragment.java index 5abd2194e..2bd59ba9f 100644 --- a/app/src/main/java/com/yizhuan/erban/avroom/fragment/HomePartyRoomFragment.java +++ b/app/src/main/java/com/yizhuan/erban/avroom/fragment/HomePartyRoomFragment.java @@ -28,6 +28,7 @@ import com.yizhuan.erban.avroom.firstcharge.FirstChargeDialog; import com.yizhuan.erban.avroom.firstcharge.FirstChargePrizeDialog; import com.yizhuan.erban.avroom.giftvalue.GiftValueDialogUiHelper; import com.yizhuan.erban.avroom.ktv.KtvSongListActivity; +import com.yizhuan.xchat_android_core.helper.AtProxy; import com.yizhuan.erban.avroom.presenter.HomePartyPresenter; import com.yizhuan.erban.avroom.view.IHomePartyView; import com.yizhuan.erban.avroom.widget.PKBoardView; @@ -51,6 +52,7 @@ import com.yizhuan.xchat_android_core.pay.event.FirstChargeEvent; import com.yizhuan.xchat_android_core.room.bean.RoomInfo; import com.yizhuan.xchat_android_core.room.event.DatingSelectUserEvent; import com.yizhuan.xchat_android_core.room.face.DynamicFaceModel; +import com.yizhuan.xchat_android_core.room.event.RoomAtEvent; import com.yizhuan.xchat_android_core.room.face.FaceInfo; import com.yizhuan.xchat_android_core.room.model.AvRoomModel; import com.yizhuan.xchat_android_core.room.model.MicQueueModel; @@ -529,6 +531,7 @@ public class HomePartyRoomFragment extends BaseRoomFragment extends BaseMvpPresenter * @param message */ @SuppressLint("CheckResult") - public void sendTextMsg(String message) { + public void sendTextMsg(String message, @Nullable AtProxy atProxy) { RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; if (roomInfo == null || TextUtils.isEmpty(message)) return; - IMNetEaseManager.get().sendTextMsg(roomInfo.getRoomId(), message) + IMNetEaseManager.get().sendTextMsg(roomInfo.getRoomId(), message, atProxy) .subscribe(new BiConsumer() { @Override public void accept(ChatRoomMessage chatRoomMessage, diff --git a/app/src/main/java/com/yizhuan/erban/avroom/presenter/HomePartyPresenter.java b/app/src/main/java/com/yizhuan/erban/avroom/presenter/HomePartyPresenter.java index 2049edb59..ee0130e03 100644 --- a/app/src/main/java/com/yizhuan/erban/avroom/presenter/HomePartyPresenter.java +++ b/app/src/main/java/com/yizhuan/erban/avroom/presenter/HomePartyPresenter.java @@ -4,15 +4,12 @@ import static com.yizhuan.xchat_android_core.manager.RoomEvent.DRAGON_BAR_CANCEL import static com.yizhuan.xchat_android_core.manager.RoomEvent.DRAGON_BAR_END; import android.annotation.SuppressLint; -import android.text.TextUtils; -import android.util.Log; import androidx.annotation.NonNull; import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder; import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; -import com.orhanobut.logger.Logger; import com.yizhuan.erban.avroom.view.IHomePartyView; import com.yizhuan.erban.utils.UserUtils; import com.yizhuan.xchat_android_core.Constants; @@ -23,13 +20,9 @@ import com.yizhuan.xchat_android_core.im.custom.bean.FaceAttachment; import com.yizhuan.xchat_android_core.manager.AvRoomDataManager; import com.yizhuan.xchat_android_core.manager.IMNetEaseManager; import com.yizhuan.xchat_android_core.manager.RoomEvent; -import com.yizhuan.xchat_android_core.mentoring_relationship.model.MentoringRelationshipModel; -import com.yizhuan.xchat_android_core.miniworld.bean.MiniWorldInWorldInfo; -import com.yizhuan.xchat_android_core.miniworld.model.MiniWorldModel; import com.yizhuan.xchat_android_core.room.bean.DragonBarInfo; import com.yizhuan.xchat_android_core.room.bean.RoomInfo; import com.yizhuan.xchat_android_core.room.dragonball.DragonBallModel; -import com.yizhuan.xchat_android_core.room.exception.AntiSpamHitException; import com.yizhuan.xchat_android_core.room.face.FaceInfo; import com.yizhuan.xchat_android_core.room.face.FaceReceiveInfo; import com.yizhuan.xchat_android_core.room.giftvalue.helper.GiftValueMrg; @@ -38,8 +31,6 @@ import com.yizhuan.xchat_android_core.room.queue.bean.MicMemberInfo; import com.yizhuan.xchat_android_core.user.UserModel; import com.yizhuan.xchat_android_core.user.bean.UserInfo; import com.yizhuan.xchat_android_core.utils.net.BeanObserver; -import com.yizhuan.xchat_android_core.utils.net.RxHelper; -import com.yizhuan.xchat_android_library.base.PresenterEvent; import com.yizhuan.xchat_android_library.utils.SingleToastUtil; import com.yizhuan.xchat_android_library.utils.config.BasicConfig; @@ -47,7 +38,6 @@ import java.util.ArrayList; import java.util.List; import io.reactivex.Single; -import io.reactivex.functions.BiConsumer; /** diff --git a/app/src/main/java/com/yizhuan/erban/avroom/widget/MessageView.java b/app/src/main/java/com/yizhuan/erban/avroom/widget/MessageView.java index 4ac14c812..49e6c5c83 100644 --- a/app/src/main/java/com/yizhuan/erban/avroom/widget/MessageView.java +++ b/app/src/main/java/com/yizhuan/erban/avroom/widget/MessageView.java @@ -9,14 +9,17 @@ import static com.yizhuan.xchat_android_core.redpackage.RedPackageTypeKt.ROOM_GI import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Color; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.text.Editable; +import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; @@ -64,6 +67,8 @@ import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil; import com.yizhuan.erban.ui.widget.marqueeview.Utils; import com.yizhuan.erban.utils.RegexUtil; import com.yizhuan.xchat_android_constants.XChatConstants; +import com.yizhuan.xchat_android_core.DemoCache; +import com.yizhuan.xchat_android_core.auth.AuthModel; import com.yizhuan.xchat_android_core.Constants; import com.yizhuan.xchat_android_core.bean.attachmsg.RoomQueueMsgAttachment; import com.yizhuan.xchat_android_core.decoration.car.bean.CarInfo; @@ -143,6 +148,7 @@ import com.yizhuan.xchat_android_core.statistic.protocol.StatisticsProtocol; import com.yizhuan.xchat_android_core.user.UserModel; import com.yizhuan.xchat_android_core.user.bean.UserInfo; import com.yizhuan.xchat_android_core.utils.ExtensionUtil; +import com.yizhuan.xchat_android_core.utils.LogUtils; import com.yizhuan.xchat_android_core.utils.net.DontWarnObserver; import com.yizhuan.xchat_android_core.utils.net.RxHelper; import com.yizhuan.xchat_android_core.vip.VipMessageInfo; @@ -154,13 +160,18 @@ import com.yizhuan.xchat_android_library.utils.SizeUtils; import org.greenrobot.eventbus.EventBus; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.reactivex.Single; import io.reactivex.SingleSource; @@ -168,6 +179,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Consumer; import io.reactivex.functions.Function; +import lombok.Setter; /** * 直播间消息界面 @@ -181,10 +193,12 @@ public class MessageView extends FrameLayout { private final static int BLOCK_MAX_MESSAGE_SIZE = MAX_MESSAGE_SIZE * 3 / 2;//在查看消息停住的时候 最多消息条数. private static final int LOAD_MESSAGE_COUNT = 10; private final int textColor = 0x80ffffff; + private final List atMessages = new ArrayList<>(); + private final List chatRoomMessages = new LinkedList<>(); private RecyclerView messageListView; private TextView tvBottomTip; + private TextView tvAtTip; private MessageAdapter mMessageAdapter; - private List chatRoomMessages = new LinkedList<>(); private LinearLayoutManager layoutManger; private Disposable disposable; private int paddingWidth; @@ -205,6 +219,8 @@ public class MessageView extends FrameLayout { private Consumer clickConsumer; private OnClick onClick; + private OnMsgLongClickListener onLongClickListener; + public MessageView(Context context) { this(context, null); } @@ -218,6 +234,10 @@ public class MessageView extends FrameLayout { init(context); } + public void setOnLongClickListener(OnMsgLongClickListener onLongClickListener) { + this.onLongClickListener = onLongClickListener; + } + public void setClickConsumer(Consumer clickConsumer) { this.clickConsumer = clickConsumer; } @@ -309,12 +329,33 @@ public class MessageView extends FrameLayout { tvBottomTip.setLayoutParams(params1); tvBottomTip.setVisibility(GONE); tvBottomTip.setOnClickListener(v -> { - Logger.e(TAG, "mMessageAdapter.getItemCount()->" + mMessageAdapter.getItemCount()); tvBottomTip.setVisibility(GONE); needAutoScroll = true; messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); }); addView(tvBottomTip); + + //有人@我 + tvAtTip = new TextView(context); + FrameLayout.LayoutParams params2 = new LayoutParams( + Utils.dip2px(context, 115F), Utils.dip2px(context, 27)); + params2.gravity = Gravity.BOTTOM; + params2.leftMargin = UIUtil.getScreenWidth(context) / 2 - UIUtil.dip2px(context, 115 / 2); + tvAtTip.setBackgroundResource(R.drawable.bg_messge_view_bottom_tip); + tvAtTip.setGravity(Gravity.CENTER); + tvAtTip.setText(context.getString(R.string.message_view_bottom_tip)); + tvAtTip.setTextColor(context.getResources().getColor(R.color.color_FD85C9)); + tvAtTip.setLayoutParams(params2); + tvAtTip.setVisibility(GONE); + tvAtTip.setOnClickListener(v -> { + if (!atMessages.isEmpty()) { + messageListView.smoothScrollToPosition(chatRoomMessages.indexOf(atMessages.remove(0))); + } + needAutoScroll = false; + checkShowAtTip(); + }); + addView(tvAtTip); + messageListView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { @@ -332,9 +373,12 @@ public class MessageView extends FrameLayout { // Logger.e(TAG, "onScrollStateChanged: SCROLL_STATE_IDLE"); int lastVisibleItemPosition = layoutManger.findLastVisibleItemPosition(); + if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { // Logger.e(TAG, "lastCompletelyVisibleItemPosition : RecyclerView.NO_POSITION"); needAutoScroll = true; + } else if (!atMessages.isEmpty() && atMessages.remove(chatRoomMessages.get(lastVisibleItemPosition))) { + checkShowAtTip(); } // Log.e(TAG, "lastVisibleItemPosition:" + lastVisibleItemPosition // + " mMessageAdapter.getItemCount()-1:" + (recyclerView.getAdapter().getItemCount()-1) @@ -365,6 +409,7 @@ public class MessageView extends FrameLayout { //通知adapter 刷新 mMessageAdapter.notifyItemInserted(mMessageAdapter.getItemCount() - 1); showTipsOrScrollToBottom(); + checkAtMe(msg, false); return chatRoomMessages.size() - 1; } @@ -372,16 +417,49 @@ public class MessageView extends FrameLayout { chatRoomMessages.addAll(chatRoomMessages.size() > 0 ? 1 : 0, messages); mMessageAdapter.notifyDataSetChanged(); messageListView.scrollToPosition(mMessageAdapter.getItemCount() - 1); + for (ChatRoomMessage message : messages) { + checkAtMe(message, true); + } } private void keepSizeUnderLimit() { while (chatRoomMessages.size() > MAX_MESSAGE_SIZE) { Log.i("keepSizeUnderLimit", "size" + chatRoomMessages.size()); - chatRoomMessages.remove(0); + ChatRoomMessage message = chatRoomMessages.remove(0); + if (atMessages.remove(message)) { + checkShowAtTip(); + } mMessageAdapter.notifyItemRemoved(0); } } + private void checkShowAtTip() { + tvAtTip.setText(getContext().getString(R.string.message_at_tip, atMessages.size())); + tvAtTip.setVisibility(atMessages.size() == 0 ? GONE : VISIBLE); + } + + private void checkAtMe(ChatRoomMessage msg, boolean history) { + if (msg.getMsgType() != MsgTypeEnum.text) return; + List atUids = ExtensionUtil.getListExtension(msg, UserInfo.AT_UIDS); + List atNames = ExtensionUtil.getListExtension(msg, UserInfo.AT_NAMES); + if (!ListUtils.isListEmpty(atUids) && !ListUtils.isListEmpty(atNames)) { + for (int i = 0; i < atUids.size(); i++) { + String uid = atUids.get(i); + // 只有当被 @ 人的数组中包含自己的时候才会去变色 + if (Objects.equals(uid, String.valueOf(AuthModel.get().getCurrentUid()))) { + Map atMap = DemoCache.readAtMsgUuid(); + if (atMap == null || !atMap.containsKey(msg.getUuid())) { + if (!atMessages.contains(msg) && (!needAutoScroll || history)) { + atMessages.add(msg); + checkShowAtTip(); + } + DemoCache.saveAtMsgUuid(msg.getUuid()); + } + } + } + } + } + private void showTipsOrScrollToBottom() { if (!needAutoScroll) { tvBottomTip.setVisibility(VISIBLE); @@ -650,6 +728,7 @@ public class MessageView extends FrameLayout { tvContent.setLineSpacing(0, 1); tvContent.setTextColor(Color.WHITE); tvContent.setOnClickListener(this); + tvContent.setOnLongClickListener(null); tvContent.setTag(chatRoomMessage); clearBackground(tvContent); try { @@ -880,6 +959,7 @@ public class MessageView extends FrameLayout { } } catch (UnsupportedOperationException e) { e.printStackTrace(); + clearBackground(tvContent); tvContent.setTextColor(Color.WHITE); tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); } @@ -1712,8 +1792,39 @@ public class MessageView extends FrameLayout { ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); SpannableBuilder text = new SpannableBuilder(tvContent); addCommonTag(chatRoomMessage, text, tvContent); - text.append(extension == null ? "我" : RegexUtil.getPrintableString(extension.getSenderNick()), new ForegroundColorSpan(greyColor)) - .append(":" + chatRoomMessage.getContent(), new ForegroundColorSpan(getResources().getColor(R.color.white))); + String nickName = extension == null ? "我" : RegexUtil.getPrintableString(extension.getSenderNick()); + text.append(nickName, new ForegroundColorSpan(greyColor)) + .append(": " + chatRoomMessage.getContent(), new ForegroundColorSpan(getResources().getColor(R.color.white))); + List atUids = ExtensionUtil.getListExtension(chatRoomMessage, UserInfo.AT_UIDS); + List atNames = ExtensionUtil.getListExtension(chatRoomMessage, UserInfo.AT_NAMES); + if (!ListUtils.isListEmpty(atUids) && !ListUtils.isListEmpty(atNames)) { + for (int i = 0; i < atUids.size(); i++) { + String name = atNames.get(i); + String uid = atUids.get(i); + // 只有当被 @ 人的数组中包含自己的时候才会去变色 + if (Objects.equals(uid, String.valueOf(AuthModel.get().getCurrentUid()))) { + Pattern pattern = Pattern.compile(Pattern.quote("@" + name)); + Matcher matcher = pattern.matcher(text.build().toString()); + while (matcher.find()) { + int start = matcher.start(); + int end = matcher.end(); + text.build().setSpan(new ForegroundColorSpan(getContext().getResources().getColor(R.color.color_FD85C9)), + start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + } + } + } + + if (Objects.equals(chatRoomMessage.getFromAccount(), String.valueOf(AuthModel.get().getCurrentUid()))) { + tvContent.setOnLongClickListener(null); + } else { + tvContent.setOnLongClickListener(v -> { + if (onLongClickListener != null) { + onLongClickListener.onLongClick(v, chatRoomMessage.getFromAccount(), nickName); + } + return true; + }); + } tvContent.setText(text.build()); } diff --git a/app/src/main/java/com/yizhuan/erban/avroom/widget/OnMsgLongClickListener.java b/app/src/main/java/com/yizhuan/erban/avroom/widget/OnMsgLongClickListener.java new file mode 100644 index 000000000..73809b480 --- /dev/null +++ b/app/src/main/java/com/yizhuan/erban/avroom/widget/OnMsgLongClickListener.java @@ -0,0 +1,7 @@ +package com.yizhuan.erban.avroom.widget; + +import android.view.View; + +public interface OnMsgLongClickListener { + void onLongClick(View v,String account,String name); +} diff --git a/app/src/main/java/com/yizhuan/erban/avroom/widget/ViewItem.java b/app/src/main/java/com/yizhuan/erban/avroom/widget/ViewItem.java index b4a70d282..4107b9419 100644 --- a/app/src/main/java/com/yizhuan/erban/avroom/widget/ViewItem.java +++ b/app/src/main/java/com/yizhuan/erban/avroom/widget/ViewItem.java @@ -60,6 +60,11 @@ public class ViewItem { */ public boolean isFindTa = false; + /** + * @Ta + */ + public boolean isAt = false; + public String mText; public int resourceID; public int imgRes; diff --git a/app/src/main/java/com/yizhuan/erban/ui/widget/UserInfoDialog.java b/app/src/main/java/com/yizhuan/erban/ui/widget/UserInfoDialog.java index e793179e5..20a084d20 100644 --- a/app/src/main/java/com/yizhuan/erban/ui/widget/UserInfoDialog.java +++ b/app/src/main/java/com/yizhuan/erban/ui/widget/UserInfoDialog.java @@ -64,6 +64,7 @@ import com.yizhuan.xchat_android_core.room.bean.RoomInfo; import com.yizhuan.xchat_android_core.room.bean.RoomResult; import com.yizhuan.xchat_android_core.room.dragonball.DragonBallModel; import com.yizhuan.xchat_android_core.room.event.DatingSelectUserEvent; +import com.yizhuan.xchat_android_core.room.event.RoomAtEvent; import com.yizhuan.xchat_android_core.room.face.FaceReceiveInfo; import com.yizhuan.xchat_android_core.room.giftvalue.GiftValueModel; import com.yizhuan.xchat_android_core.room.giftvalue.bean.RoomGiftValue; @@ -369,7 +370,21 @@ public class UserInfoDialog extends AppCompatDialog implements View.OnClickListe if (!isMySelf) { findHimView = buttonItem; } - + } else if (buttonItem.isAt) { + //@他处理 + if (!isMySelf) { + item.setOnClickListener(v -> { + if (userInfo != null) { + dismiss(); + EventBus.getDefault().post( + new RoomAtEvent(String.valueOf(userInfo.getUid()), userInfo.getNick()) + ); + } else { + SingleToastUtil.showToast("数据加载中,请稍后..."); + } + }); + flexbox.addView(item); + } } else { item.setOnClickListener(v -> { buttonItem.mClickListener.onClick(); diff --git a/app/src/main/res/drawable-xhdpi/icon_dialog_ait.png b/app/src/main/res/drawable-xhdpi/icon_dialog_ait.png new file mode 100644 index 0000000000000000000000000000000000000000..59970a85907fbacf4a8aa4bf76b59cfe1fb1a319 GIT binary patch literal 2415 zcmV-#36S=QP)Px;DM>^@RCr$PoPBJSR~^Sc=e8@|2DG+-Wk43T!Ll*HDTuVlf&n*KvO(Nr(~+31 zLtSrKFuueY6=O6;4Vi112{L1rWo!c3ShhOH5_F@tBKQIoOz9ADu(DFH1*WBxd(7|l zKE2O9eV+UFoO|06p1+#jbAB)1=l6Dg=bT4Ts7GtHHo`0&VxHE_1a1aq0F@fXDHtcB zXgH_f9B>+F2ilb4u!^$pscH_QlrDtGDxXZ&MRY|!tk8;OXg&o@3dpY$%`T;QBU;3c zjSG~3mzT#nFzdArooeQ;P>3}emIGJiMRK^PpeY(<)5IEHU$0cuCLe3Stly=JPnGfo zG~ZGKZc?yELt9AkWWzfvVAkx@6H5Ac8K}vI$#9R=5V=^wy_@E#u1sag z7#N8s(I{^gI^$%jNV;*c%oSp3rg0}DVB$gcEns>&0Y>=mM^%W$nShfPnEJQ$L|w%0 zVNb=j5SNsGiA4>I)u~h@Qv&n7zw46IXAw(TU`wtMLT69qcou*EHr3}RPfB3I5#2C~ zvQJi+E7;gjt$Z`9FEH^sC8ru7D+z~lu;#wT8nxX^1W#bT9MMyX;UG{poN^a{cTcpK z*-w95y=(IF1g0*cw<@@=0D=ua3q@1oLUngqV8Ri7C-8b9B)(}ZTw4s+j~&YG*m>ye zg^u3*OQJO^HrA*eZca%S6YHh4a426z+_+*`Fac(i!42b~v^c%e-520U5A1#)-Z`Is zd@duT`0G5*tgW9@mz?=Yz|=MC2b5wElyNu=8DbCFh2MFYVUGh0Jw&%7eg! zTl8npG}#2@i#Ni@Ji5FB#NJLg)b0QF#mZ)v!^|>o8h`GDUmvk4E$AqBZ(O8e7$ksc z)-Rw~Ws8*;C<4f~f5QIm?6?R>%csDi>yqbL2S@W_V~u)X5STUlbXiFsCxO!JMD`x- z1&S!K{TQ4J(2<>64iC*pc1z1{)!SD>)uwr>CuTAA5&f`+XKa9S&s118Et!%{;U&d? z>6T=0e)Ly+X=Q<3{LCW$sS4x~U8%Uo)WW$q%6QOzPk& z0sTSQs*69CUFzk=YPC|`{~KNO;i*VxD{$}jtFyqJQAEif9`J^HX%*Z#%|BZ?%KqS^ zP(EgWMsGiSeeb~Ern^3|H<+8cr0jYBIF+jYZ9P{P@wcGXBK}`{OEQ(s|L_j9e%Z>D zL0r)7mWR&3FWLr1O)iBeZcohEaTMN^C~4tQm-vVZNAx2Q>-GnFOl74Q+aSwOLU8Ab7&{a$%Dhq zG;J1i*<>t-s0pO$n&u0!2~6zpQaGXmpHNB%jA>En%-&4JeoBAkX1KLt07@?_&Gkjg zyn+DZRv;54%=qHBq;O|KFINi$j15;Z6*m=0XHljCCcU4x4sB1k!E;x{LBMe4I8z={j(M=e4SK zXAv{?`UO+3>}9%Trtv4BOTA`oNnoZ|cQEt<&aJT1elYtuqMVzKX-$@^-9ap!C4rSi zq-hnV3zz{_q!2fd7~(7%9m(YX&f?K&lz(VU@^V5zdFqh0R)c9^wbt4WX6+%I+}T8| zV(qO%K`9=q9`*JmLjd`#DEp} zS=iehiSC|5?`qe^-IgPP1MxtkN`$l3+7v;*dwX*G!7HnXb+{yBWn-@63M{1Y@r(sW5<{8Ctz4?=dHoAn~FWWMwm9oAu zH{4>tX%hF_-7({(`PQgi4TT~E4|+-V-wpd<_JmY?m!%{po>lS+@d8#5L1gQsy(c>t z%tR(KO?E-A0WJb^!LM6B;HBXm h;ILA(75d{{{|C+a&3=vhuR8z$002ovPDHLkV1i;hrOE&R literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 979e321e2..45ea17761 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -600,5 +600,6 @@ #66333333 #4DFFCE4E #c6c6e9 + #FD85C9 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7b3fd4a66..79e43cc34 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -941,4 +941,5 @@ 查看 解除后,包括陪伴时长、等级都会清除;确定解除关系吗? 撤销后,包括陪伴时长及等级都会回复,确定恢复关系吗? + 有%d人@你 diff --git a/core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/helper/AtProxy.java b/core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/helper/AtProxy.java new file mode 100644 index 000000000..47b0c0086 --- /dev/null +++ b/core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/helper/AtProxy.java @@ -0,0 +1,65 @@ +package com.yizhuan.xchat_android_core.helper; + +import android.widget.EditText; + +import com.netease.nim.uikit.business.ait.AitBlock; +import com.netease.nim.uikit.business.ait.AitManager; +import com.netease.nim.uikit.business.ait.AitTextChangeListener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class AtProxy implements AitTextChangeListener { + + private final AitManager aitManager; + private final EditText editText; + + public AtProxy(EditText editText) { + this.aitManager = new AitManager(editText.getContext(), null, false); + this.editText = editText; + init(); + } + + private void init() { + aitManager.setTextChangeListener(this); + editText.addTextChangedListener(aitManager); + } + + public void insertAitMember(String account, String name) { + aitManager.insertAitMember(account, name); + } + + @Override + public void onTextAdd(String content, int start, int length) { + editText.getEditableText().insert(start, content); + } + + @Override + public void onTextDelete(int start, int length) { + int end = start + length - 1; + editText.getEditableText().replace(start, end, ""); + } + + public void reset() { + aitManager.reset(); + } + + public Map getAtExtensionMap() { + Map map = new HashMap<>(); + if (aitManager.getAitBlocks().size() > 0) { + List uids = new ArrayList<>(); + List names = new ArrayList<>(); + for (String account : aitManager.getAitBlocks().keySet()) { + AitBlock block = aitManager.getAitBlocks().get(account); + uids.add(account); + names.add(block.text); + } + map.put("atUids",uids); + map.put("atNames",names); + } + return map; + } +} diff --git a/core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/manager/IMNetEaseManager.java b/core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/manager/IMNetEaseManager.java index 07f438e23..8ea6a2ad5 100644 --- a/core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/manager/IMNetEaseManager.java +++ b/core/src/diff_src_erban/java/com/yizhuan/xchat_android_core/manager/IMNetEaseManager.java @@ -7,6 +7,7 @@ import android.util.Log; import android.util.SparseArray; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -60,6 +61,7 @@ import com.yizhuan.xchat_android_core.family.bean.FamilyInfo; import com.yizhuan.xchat_android_core.family.event.FamilyMineEvent; import com.yizhuan.xchat_android_core.gift.GiftModel; import com.yizhuan.xchat_android_core.gift.bean.GiftInfo; +import com.yizhuan.xchat_android_core.helper.AtProxy; import com.yizhuan.xchat_android_core.im.custom.bean.ActivityTimerAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.AssistantAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.CarAttachment; @@ -1841,11 +1843,16 @@ public final class IMNetEaseManager { * * @param message - */ - public Single sendTextMsg(long roomId, String message) { + public Single sendTextMsg(long roomId, String message, @Nullable AtProxy atProxy) { if (TextUtils.isEmpty(message) || TextUtils.isEmpty(message.trim())) return Single.error(new ErrorThrowable("message == null !!!")); ChatRoomMessage chatRoomMessage = ChatRoomMessageBuilder.createChatRoomTextMessage( String.valueOf(roomId), message); + + if (atProxy != null) { + chatRoomMessage.setLocalExtension(atProxy.getAtExtensionMap()); + atProxy.reset(); + } NIMAntiSpamOption antiSpamOption = new NIMAntiSpamOption(); antiSpamOption.antiSpamConfigId = XChatConstants.CHAT_ROOM_ANTI_SPAM_CONFIG_ID; chatRoomMessage.setNIMAntiSpamOption(antiSpamOption); diff --git a/core/src/main/java/com/yizhuan/xchat_android_core/DemoCache.java b/core/src/main/java/com/yizhuan/xchat_android_core/DemoCache.java index 823f27099..209a752d4 100644 --- a/core/src/main/java/com/yizhuan/xchat_android_core/DemoCache.java +++ b/core/src/main/java/com/yizhuan/xchat_android_core/DemoCache.java @@ -58,6 +58,8 @@ public class DemoCache { private static final String KEY_FILTRATE_TYPE = "FilTrateType"; private static final String KEY_RED_PACKAGE = "RedPackage"; public static final String KEY_VIP_RED_POINT = "key_vip_red_point"; + private static final String KEY_AT_MSG_UUID = "AtMsgUuid"; + /** * 保存网页域名 */ @@ -123,6 +125,27 @@ public class DemoCache { SettingsPref.instance().putString(KEY_RED_PACKAGE, new Gson().toJson(map)); } + public static Map readAtMsgUuid() { + String string = SettingsPref.instance().getString(KEY_AT_MSG_UUID, null); + if (TextUtils.isEmpty(string)) return null; + return new Gson().fromJson(string, + new TypeToken>() { + }.getType()); + } + + //云信聊天室云端历史消息最长保存10天,这里保存30天的应该够用了 + public static void saveAtMsgUuid(String id) { + Map map = readAtMsgUuid(); + if (map == null) map = new HashMap<>(); + for (Iterator> it = map.entrySet().iterator(); it.hasNext(); ) { + if (CurrentTimeUtils.getCurrentTime() - it.next().getValue() > 60 * 60 * 24 * 30 * 1000L) { + it.remove(); + } + } + map.put(id, CurrentTimeUtils.getCurrentTime()); + SettingsPref.instance().putString(KEY_AT_MSG_UUID, new Gson().toJson(map)); + } + public static void saveBoolean(String key, boolean value) { SettingsPref.instance(BasicConfig.INSTANCE.getAppContext()).putBoolean(key, value); diff --git a/core/src/main/java/com/yizhuan/xchat_android_core/room/event/RoomAtEvent.java b/core/src/main/java/com/yizhuan/xchat_android_core/room/event/RoomAtEvent.java new file mode 100644 index 000000000..551d16d36 --- /dev/null +++ b/core/src/main/java/com/yizhuan/xchat_android_core/room/event/RoomAtEvent.java @@ -0,0 +1,11 @@ +package com.yizhuan.xchat_android_core.room.event; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class RoomAtEvent { + private String account; + private String name; +} diff --git a/core/src/main/java/com/yizhuan/xchat_android_core/user/bean/UserInfo.java b/core/src/main/java/com/yizhuan/xchat_android_core/user/bean/UserInfo.java index 758feef85..28630b66e 100644 --- a/core/src/main/java/com/yizhuan/xchat_android_core/user/bean/UserInfo.java +++ b/core/src/main/java/com/yizhuan/xchat_android_core/user/bean/UserInfo.java @@ -50,6 +50,8 @@ public class UserInfo implements Serializable { public static String VIP_ICON = "vipIcon"; public static String BUBBLE_URL_ANDROID = "androidBubbleUrl"; public static String BUBBLE_URL_IOS = "iosBubbleUrl"; + public static String AT_UIDS = "atUids"; + public static String AT_NAMES = "atNames"; /** * PK的时候队伍ID * GroupType_default = 0,//默认 diff --git a/core/src/main/java/com/yizhuan/xchat_android_core/utils/ExtensionUtil.java b/core/src/main/java/com/yizhuan/xchat_android_core/utils/ExtensionUtil.java index bb86ded32..a15b45fb8 100644 --- a/core/src/main/java/com/yizhuan/xchat_android_core/utils/ExtensionUtil.java +++ b/core/src/main/java/com/yizhuan/xchat_android_core/utils/ExtensionUtil.java @@ -12,6 +12,7 @@ import com.yizhuan.xchat_android_core.im.custom.bean.FaceAttachment; import com.yizhuan.xchat_android_core.im.custom.bean.RoomTipAttachment; import java.util.HashMap; +import java.util.List; import java.util.Map; public class ExtensionUtil { @@ -45,7 +46,36 @@ public class ExtensionUtil { return o == null ? null : (Map) o; } - public static String getAccount(ChatRoomMessage chatRoomMessage) throws NullPointerException{ + /** + * 获取房间内的ext字段 + * + * @param chatRoomMessage 聊天室内的信息 + * @param key + * @return ext + */ + public static List getListExtension(ChatRoomMessage chatRoomMessage, String key) { + Object o = null; + // 本地的ext字段 + if (chatRoomMessage.getLocalExtension() != null && chatRoomMessage.getLocalExtension().get(key) != null) { + o = chatRoomMessage.getLocalExtension().get(key); + } + // 别人发送过来的ext字段 + if (o == null && + chatRoomMessage.getRemoteExtension() != null && + chatRoomMessage.getRemoteExtension().get(key) != null) { + o = chatRoomMessage.getRemoteExtension().get(key); + } + // 默认的云信发送过来的ext字段 + if (o == null && + chatRoomMessage.getChatRoomMessageExtension() != null && + chatRoomMessage.getChatRoomMessageExtension().getSenderExtension() != null && + chatRoomMessage.getChatRoomMessageExtension().getSenderExtension().get(key) != null) { + o = chatRoomMessage.getChatRoomMessageExtension().getSenderExtension().get(key); + } + return (o instanceof List) ? (List) o : null; + } + + public static String getAccount(ChatRoomMessage chatRoomMessage) throws NullPointerException { String account; if (chatRoomMessage.getMsgType() == MsgTypeEnum.tip) { account = chatRoomMessage.getFromAccount(); @@ -70,6 +100,7 @@ public class ExtensionUtil { /** * 获取聊天室成员的拓展字段 + * * @param chatRoomMember - * @return - 可能为null */ @@ -82,7 +113,7 @@ public class ExtensionUtil { Object tmp = ext.get(chatRoomMember.getAccount()); try { //noinspection unchecked - return (Map) tmp; + return (Map) tmp; } catch (Exception ex) { ex.printStackTrace(); } @@ -91,6 +122,7 @@ public class ExtensionUtil { } private static final String KEY_IS_WELCOME = "is_welcome"; + /** * 判断聊天室消息本地字段 是否已经欢迎过了 */ diff --git a/nim_uikit/src/com/netease/nim/uikit/business/ait/AitContactsModel.java b/nim_uikit/src/com/netease/nim/uikit/business/ait/AitContactsModel.java index 25550a735..c1cf9c937 100644 --- a/nim_uikit/src/com/netease/nim/uikit/business/ait/AitContactsModel.java +++ b/nim_uikit/src/com/netease/nim/uikit/business/ait/AitContactsModel.java @@ -20,13 +20,17 @@ import java.util.Map; public class AitContactsModel { // 已@ 的成员 - private Map aitBlocks = new HashMap<>(); + private final Map aitBlocks = new HashMap<>(); // 清除所有的@块 public void reset() { aitBlocks.clear(); } + public Map getAitBlocks() { + return aitBlocks; + } + public void addAitMember(String account, String name, int type, int start) { AitBlock aitBlock = aitBlocks.get(account); if (aitBlock == null) { diff --git a/nim_uikit/src/com/netease/nim/uikit/business/ait/AitManager.java b/nim_uikit/src/com/netease/nim/uikit/business/ait/AitManager.java index 5f1b87f95..9bf7df8a1 100644 --- a/nim_uikit/src/com/netease/nim/uikit/business/ait/AitManager.java +++ b/nim_uikit/src/com/netease/nim/uikit/business/ait/AitManager.java @@ -7,6 +7,8 @@ import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; +import androidx.annotation.NonNull; + import com.netease.nim.uikit.business.ait.event.AitContactActionEvent; import com.netease.nim.uikit.business.ait.selector.AitContactSelectorActivity; import com.netease.nim.uikit.business.uinfo.UserInfoHelper; @@ -16,6 +18,7 @@ import com.netease.nimlib.sdk.team.model.TeamMember; import org.greenrobot.eventbus.EventBus; import java.util.List; +import java.util.Map; /** * Created by hzchenkang on 2017/7/10. @@ -52,6 +55,11 @@ public class AitManager implements TextWatcher { return aitContactsModel.getAitTeamMember(); } + @NonNull + public Map getAitBlocks() { + return aitContactsModel.getAitBlocks(); + } + public String getAitRobot() { return aitContactsModel.getFirstAitRobot(); }