From f121ef5ad1219edbee01e75c529d0908f34c8149 Mon Sep 17 00:00:00 2001 From: max Date: Fri, 10 May 2024 21:07:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=AE=8C=E6=88=90=E6=88=BF=E9=97=B4?= =?UTF-8?q?=E5=85=AC=E8=81=8A=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/avroom/fragment/BaseRoomFragment.kt | 142 ++++++++++++- .../avroom/presenter/BaseRoomPresenter.java | 27 ++- .../public_chat/PublicChatMessageView.java | 197 +++++++++++------- .../PublicChatRoomMessageWidget.kt | 81 +++++-- .../com/chwl/app/avroom/view/IBaseRoomView.kt | 2 + .../app/home/fragment/ContactsListFragment.kt | 5 +- .../drawable-xxhdpi/room_ic_headline_send.png | Bin 0 -> 36889 bytes .../main/res/drawable/shape_593722_7dp.xml | 5 + .../main/res/layout/fragment_av_room_game.xml | 25 ++- .../main/res/layout/fragment_contact_list.xml | 2 - .../main/res/layout/fragment_single_room.xml | 28 ++- .../layout/list_item_chatroom_msg_image.xml | 31 +++ .../res/layout/list_item_chatrrom_msg.xml | 2 +- .../room_public_chat_message_widget.xml | 29 +++ app/src/main/res/values-ar/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 4 + .../public_chat/core/ChatRoomClientManager.kt | 7 + .../ui/message/HeadlineViewModel.kt | 37 ++++ .../PublicChatRoomMessageListPanel.java | 1 - .../ui/message/PublicChatRoomViewModel.kt | 35 +--- .../ui/message/headline/HeadlineSendDialog.kt | 6 +- .../res/values-ar/strings.xml | 2 + .../res/values-zh-rTW/strings.xml | 3 + .../module_public_chat/res/values/strings.xml | 2 + .../support/room/FrameLayoutRoomWidget.kt | 36 ++++ .../public_chat_hall/model/PublicChatModel.kt | 1 - 28 files changed, 556 insertions(+), 160 deletions(-) create mode 100644 app/src/main/res/drawable-xxhdpi/room_ic_headline_send.png create mode 100644 app/src/main/res/drawable/shape_593722_7dp.xml create mode 100644 app/src/main/res/layout/list_item_chatroom_msg_image.xml create mode 100644 app/src/main/res/layout/room_public_chat_message_widget.xml create mode 100644 app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/HeadlineViewModel.kt diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt index 5babf9d87..9cb9b2279 100644 --- a/app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt +++ b/app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt @@ -11,6 +11,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.os.Bundle import android.text.TextUtils +import android.util.Log import android.view.KeyEvent import android.view.MotionEvent import android.view.View @@ -22,6 +23,8 @@ import android.widget.RelativeLayout import android.widget.TextView import androidx.annotation.CallSuper import androidx.core.content.ContextCompat +import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.withResumed @@ -53,13 +56,15 @@ import com.chwl.app.event.OpenRoomIntroEvent import com.chwl.app.friend.view.SelectFriendActivity import com.chwl.app.home.adapter.RoomActAdapter import com.chwl.app.music.widget.MusicPlayerView +import com.chwl.app.public_chat.ui.message.HeadlineViewModel import com.chwl.app.room_chat.activity.RoomMsgActivity -import com.chwl.app.ui.user.adapter.UserInfoIndicatorAdapter +import com.chwl.app.ui.pay.ChargeActivity import com.chwl.app.ui.widget.ButtonItem import com.chwl.app.ui.widget.GiftDialog import com.chwl.app.ui.widget.GiftDialog.OnGiftDialogBtnClickListener import com.chwl.app.ui.widget.GiftDialog.SenGiftCallback import com.chwl.app.ui.widget.UserInfoDialog +import com.chwl.app.ui.widget.dialog.CommonTipDialog import com.chwl.app.ui.widget.dynamicface.DynamicFaceDialog import com.chwl.app.ui.widget.magicindicator.MagicIndicator import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil @@ -68,6 +73,7 @@ import com.chwl.app.ui.widget.rollviewpager.RollPagerView import com.chwl.app.ui.widget.rollviewpager.Util import com.chwl.app.ui.widget.rollviewpager.hintview.ColorPointHintView import com.chwl.app.utils.KeyBoardUtils +import com.chwl.app.vip.dialog.SelectPayTypeDialog import com.chwl.core.Constants import com.chwl.core.XConstants import com.chwl.core.auth.AuthModel @@ -102,6 +108,7 @@ import com.chwl.core.support.room.RoomWidget import com.chwl.core.user.UserModel import com.chwl.core.user.bean.BaseInfo import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.net.BalanceNotEnoughExeption import com.chwl.core.utils.net.VipLevelNotEnoughException import com.chwl.library.common.util.LimitClickUtils import com.chwl.library.net.rxnet.utils.RxNetWorkUtils @@ -117,6 +124,7 @@ import com.tbruyelle.rxpermissions2.RxPermissions import com.trello.rxlifecycle3.android.FragmentEvent import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -135,12 +143,14 @@ open class BaseRoomFragment?> : View.OnClickListener, OnGiftDialogBtnClickListener, IBaseRoomView, OnMicroItemClickListener, RoomView { private var myUid: Long = 0 + protected lateinit var messagePager: ViewPager2 protected lateinit var messageView: MessageView protected var publicChatMessageWidget: PublicChatRoomMessageWidget? = null protected lateinit var bottomView: BottomView protected lateinit var inputLayout: RelativeLayout protected lateinit var inputEdit: EditText protected lateinit var inputSend: ImageView + protected lateinit var inputHeadlineSend: ImageView protected lateinit var microView: MicroView private var musicPlayerView: MusicPlayerView? = null private var mVsMusicPlayer: ViewStub? = null @@ -182,10 +192,11 @@ open class BaseRoomFragment?> : // 房间小组件 private var widgets: HashMap = HashMap() + private val headlineViewModel by activityViewModels() + @CallSuper override fun onFindViews() { initMessageView() -// messageView = mView.findViewById(R.id.message_view) bottomView = mView.findViewById(R.id.bottom_view) inputLayout = mView.findViewById(R.id.input_layout) inputEdit = mView.findViewById(R.id.input_edit) @@ -198,6 +209,7 @@ open class BaseRoomFragment?> : false } inputSend = mView.findViewById(R.id.input_send) + inputHeadlineSend = mView.findViewById(R.id.input_headline_send) microView = mView.findViewById(R.id.micro_view) mVsMusicPlayer = mView.findViewById(R.id.vs_music_player) messageView.setClickConsumer { @@ -218,12 +230,12 @@ open class BaseRoomFragment?> : } private fun initMessageView() { + messagePager = mView.findViewById(R.id.message_pager) messageView = MessageView(context) publicChatMessageWidget = PublicChatRoomMessageWidget(requireContext()) val tabList: MutableList = java.util.ArrayList(2) tabList.add(getString(R.string.room)) tabList.add(getString(R.string.public_chat_room)) - val messagePager = mView.findViewById(R.id.message_pager) val messageIndicator = mView.findViewById(R.id.message_indicator) messagePager.offscreenPageLimit = tabList.size messagePager.adapter = object : RecyclerView.Adapter() { @@ -290,6 +302,7 @@ open class BaseRoomFragment?> : override fun onSetListener() { bottomView.setMagicBtnEnable(true) inputSend.setOnClickListener(this) + inputHeadlineSend.setOnClickListener(this) inputLayout.setOnTouchListener { _: View?, _: MotionEvent? -> inputEdit.clearFocus() inputLayout.visibility = View.GONE @@ -353,6 +366,44 @@ open class BaseRoomFragment?> : //获取免费礼物详情 mvpPresenter?.queryFreeFlower() initRoomAlbum() + initHeadline() + } + + private fun initHeadline() { + headlineViewModel.loadingLiveData.observe(this) { + if (it) dialogManager?.showProgressDialog(context) + else dialogManager?.dismissDialog() + } + lifecycleScope.launch(Dispatchers.Main) { + headlineViewModel.sendHeadlineFlow.collect { + if (it.isSuccess) { + SingleToastUtil.showToast(R.string.sent_success) + inputEdit.setText("") + KeyBoardUtils.hideKeyBoard(activity, inputEdit) + } else { + if (it.code == BalanceNotEnoughExeption.code) { + showBalanceNotEnoughDialog() + } else { + SingleToastUtil.showToast(it.message) + } + } + } + } + headlineViewModel.getHeadlinePayMoneyIsNull() + } + + private fun showBalanceNotEnoughDialog() { + val tipDialog = CommonTipDialog(context) + tipDialog.setTipMsg(ResUtil.getString(R.string.insufficient_balance_recharge_tips)) + tipDialog.setOkText(getString(R.string.charge)) + tipDialog.setOnActionListener( + object : CommonTipDialog.OnActionListener { + override fun onOk() { + ChargeActivity.start(context) + } + } + ) + tipDialog.show() } @SuppressLint("CheckResult") @@ -724,6 +775,10 @@ open class BaseRoomFragment?> : messageView.clear() } + private fun isPublicMessageTab(): Boolean { + return messagePager.currentItem == 1 + } + @CallSuper override fun onClick(v: View) { if (mClickLimit.checkForTime(500)) return @@ -731,11 +786,54 @@ open class BaseRoomFragment?> : R.id.input_send -> { sendMsg() } + R.id.input_headline_send -> { + sendHeadline() + } } } private fun sendMsg() { - sendMsg(inputEdit.text.toString()) + val message = inputEdit.text.toString().trim() + if (isPublicMessageTab()) { + sendPublicChatMessage(message) + } else { + sendMsg(message) + } + } + + private fun sendHeadline() { + val message = inputEdit.text.toString().trim() + if (TextUtils.isEmpty(message)) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_08)) + return + } + if (message.length > 100) { + toast(R.string.headline_input_length_limit_tips) + return + } + val money = headlineViewModel.headlinePayMoneyLiveData.value + if (money != null) { + showHeadlinePayDialog(money, message) + } else { + SingleToastUtil.showToast(R.string.ui_setting_modifypwdactivity_01) + headlineViewModel.getHeadlinePayMoney() + } + } + + private fun showHeadlinePayDialog(money: Long, message: String) { + KeyBoardUtils.hideKeyBoard(activity, inputEdit) + SelectPayTypeDialog.newInstance( + money.toString(), + false, + money.toDouble() + ).apply { + setOnDiamondChargeClick { + headlineViewModel.sendHeadline(message) + } + setOnChargeClick { + ChargeActivity.start(context) + } + }.show(context) } @SuppressLint("CheckResult") @@ -758,6 +856,20 @@ open class BaseRoomFragment?> : inputEdit.setText("") } + private fun sendPublicChatMessage(message: String){ + if (!AuthModel.get().isImLogin) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_07)) + return + } + if (TextUtils.isEmpty(message)) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_08)) + return + } + mvpPresenter?.sendPublicChatTextMessage(message) + publicChatMessageWidget?.getMessageView()?.setNeedAutoScroll(true) // 發送後自動滾動公屏列表 + inputEdit.setText("") + } + /** * 軟鍵盤顯示與隱藏的監聽 */ @@ -1069,6 +1181,12 @@ open class BaseRoomFragment?> : KeyBoardUtils.hideKeyBoard(activity, inputEdit) } + override fun onSendPublicChatMsgSuccess(msg: ChatRoomMessage) { + publicChatMessageWidget?.getMessageView()?.addMessages(msg) + inputEdit.setText("") + KeyBoardUtils.hideKeyBoard(activity, inputEdit) + } + /** * 顯示資料卡片 */ @@ -1089,7 +1207,7 @@ open class BaseRoomFragment?> : return } if (AvRoomDataManager.get().isSelfGamePlaying) { - SingleToastUtil.showToast("遊戲中不可以換麥!") + SingleToastUtil.showToast(R.string.avroom_presenter_baseroompresenter_01) return } UserModel.get().cacheLoginUserInfo?.gameStatus = GameStatus.STATUS_NOT_JOIN @@ -1098,9 +1216,13 @@ open class BaseRoomFragment?> : if (result) { mvpPresenter?.upMicroPhone(micPosition, currentUid, b) } else { - toast("請給予麥克風權限後再試!") + toast(R.string.permission_mic_tips) } - }, { _: Throwable? -> toast("發生一些異常,請稍後重試!") }) + }, { error: Throwable? -> + error?.let { + toast(it.message) + } ?: toast(R.string.exception_try_again) + }) } /** @@ -1164,7 +1286,9 @@ open class BaseRoomFragment?> : } override fun onFollowFail(msg: String?) { - toast("關註失敗,請稍後重試") + msg?.let { + toast(msg) + } } override fun updateMicView() { @@ -1323,7 +1447,6 @@ open class BaseRoomFragment?> : } open fun initWidget() { - publicChatMessageWidget?.let { registerWidget(PublicChatRoomMessageWidget::class.java.simpleName, it) } @@ -1344,6 +1467,7 @@ open class BaseRoomFragment?> : * 打开公屏输入 */ fun openMessageInput(text: String?) { + inputHeadlineSend.isVisible = isPublicMessageTab() inputLayout.visibility = View.VISIBLE if (text != null) { inputEdit.setText(text) diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java index 294cec46f..f94cc825b 100644 --- a/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java +++ b/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java @@ -6,6 +6,9 @@ import android.util.Log; import androidx.annotation.Nullable; +import com.chwl.app.public_chat.core.ChatRoomClient; +import com.chwl.app.public_chat.core.ChatRoomClientManager; +import com.chwl.core.initial.InitialModel; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -26,7 +29,6 @@ import com.chwl.core.im.custom.bean.RoomInfoAttachment; import com.chwl.core.manager.AvRoomDataManager; import com.chwl.core.manager.IMNetEaseManager; import com.chwl.core.praise.PraiseModel; -import com.chwl.core.room.bean.RoomContributeDataInfo; import com.chwl.core.room.bean.RoomInfo; import com.chwl.core.room.exception.AntiSpamHitException; import com.chwl.core.room.game.GameStatus; @@ -34,7 +36,6 @@ import com.chwl.core.room.giftvalue.helper.GiftValueMrg; import com.chwl.core.room.model.AvRoomModel; import com.chwl.core.room.model.HomePartyModel; import com.chwl.core.room.model.RoomBaseModel; -import com.chwl.core.room.model.RoomContributeListModel; import com.chwl.core.room.queue.bean.MicMemberInfo; import com.chwl.core.super_admin.model.SuperAdminModel; import com.chwl.core.super_admin.util.SuperAdminUtil; @@ -52,7 +53,6 @@ import com.chwl.library.utils.SingleToastUtil; import java.util.Objects; import java.util.concurrent.TimeUnit; -import io.reactivex.Observable; import io.reactivex.Single; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.functions.BiConsumer; @@ -562,4 +562,25 @@ public class BaseRoomPresenter extends BaseMvpPresenter .subscribe(); } + @SuppressLint("CheckResult") + public void sendPublicChatTextMessage(String message) { + if (TextUtils.isEmpty(message)) return; + String sessionId = InitialModel.get().getPublicChatSessionId(); + if (sessionId == null) { + SingleToastUtil.showToast(R.string.public_chat_not_found); + return; + } + ChatRoomClient client = ChatRoomClientManager.INSTANCE.getClient(sessionId); + ChatRoomMessage textMessage = ChatRoomMessageBuilder.createChatRoomTextMessage(sessionId, message); + client.sendMessage(textMessage).compose(bindToLifecycle()).subscribe(new BiConsumer() { + @Override + public void accept(Object o, Throwable throwable) throws Exception { + if (throwable != null) { + SingleToastUtil.showToast(throwable.getMessage()); + } else { + getMvpView().onSendPublicChatMsgSuccess(textMessage); + } + } + }); + } } diff --git a/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatMessageView.java b/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatMessageView.java index ccb2b0ec3..7adc82b1a 100644 --- a/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatMessageView.java +++ b/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatMessageView.java @@ -2,6 +2,7 @@ package com.chwl.app.avroom.public_chat; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.Drawable; @@ -17,6 +18,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; @@ -34,12 +36,17 @@ import com.chwl.app.avroom.dialog.PKResultDialog; import com.chwl.app.avroom.widget.OnMsgLongClickListener; import com.chwl.app.avroom.widget.TemplateMessageAdapter; import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.photo.BigPhotoActivity; +import com.chwl.app.photo.PagerOption; +import com.chwl.app.public_chat.core.viewholder.ChatRoomMessageViewHolderThumbBase; import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; import com.chwl.app.ui.widget.DividerItemDecoration; import com.chwl.app.ui.widget.MyItemAnimator; import com.chwl.app.ui.widget.RecyclerViewNoViewpagerScroll; import com.chwl.app.ui.widget.TextSpannableBuilder; import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.utils.ObjectTypeHelper; import com.chwl.app.utils.RegexUtil; import com.chwl.core.DemoCache; import com.chwl.core.XConstants; @@ -48,8 +55,8 @@ import com.chwl.core.bean.attachmsg.RoomQueueMsgAttachment; import com.chwl.core.decoration.car.bean.CarInfo; import com.chwl.core.home.event.FollowRoomEvent; import com.chwl.core.home.model.CollectionRoomModel; -import com.chwl.core.im.custom.bean.AuctionAttachment; import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.HeadlineChangedAttachment; import com.chwl.core.im.custom.bean.MonsterHuntingResultAttachment; import com.chwl.core.im.custom.bean.MonsterStatusAttachment; import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment; @@ -62,6 +69,7 @@ import com.chwl.core.monsterhunting.bean.MonsterDataBean; import com.chwl.core.monsterhunting.bean.MonsterHuntingResult; import com.chwl.core.noble.NobleUtil; import com.chwl.core.praise.PraiseModel; +import com.chwl.core.public_chat_hall.bean.HeadlineBean; import com.chwl.core.room.bean.RoomInfo; import com.chwl.core.room.pk.attachment.RoomPkAttachment; import com.chwl.core.user.bean.UserInfo; @@ -73,12 +81,13 @@ import com.chwl.library.utils.ResUtil; import com.chwl.library.utils.SingleToastUtil; import com.chwl.library.utils.SizeUtils; import com.example.lib_utils.UiUtils; -import com.netease.nim.uikit.business.uinfo.UserInfoHelper; +import com.example.lib_utils.spannable.SpannableTextBuilder; +import com.netease.nim.uikit.common.util.media.ImageUtil; import com.netease.nim.uikit.common.util.sys.ScreenUtil; import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessageExtension; import com.netease.nimlib.sdk.chatroom.model.ChatRoomNotificationAttachment; -import com.netease.nimlib.sdk.msg.attachment.MsgAttachment; +import com.netease.nimlib.sdk.msg.attachment.ImageAttachment; import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; import com.netease.nimlib.sdk.msg.constant.NotificationType; @@ -103,10 +112,8 @@ import io.reactivex.functions.Consumer; public class PublicChatMessageView extends FrameLayout { private static final String TAG = "PublicChatMessageView"; - private final static int MAX_MESSAGE_SIZE = 2000;//公屏最多展示條數 + private final static int MAX_MESSAGE_SIZE = 100;//公屏最多展示條數 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; @@ -118,17 +125,11 @@ public class PublicChatMessageView extends FrameLayout { private int paddingHeight; private int whiteColor; private int greyColor; - private int roomTipNickColor; private int roomTipColor; - private int roomBlueColor; private int badgeWidth; private int badgeHeight; - private int sysIconHeight; - private int smallFace; - private int bigFace; - private int expLevelWidth; private int expLevelHeight; - private int giftLength; + private int defTextSize = 12; private volatile boolean needAutoScroll = true;//是否自動滾動到底部 private Consumer clickConsumer; private OnClick onClick; @@ -148,6 +149,7 @@ public class PublicChatMessageView extends FrameLayout { super(context, attr, i); init(context); } + public void setOnLongClickListener(OnMsgLongClickListener onLongClickListener) { this.onLongClickListener = onLongClickListener; } @@ -174,20 +176,13 @@ public class PublicChatMessageView extends FrameLayout { private void init(Context context) { whiteColor = ContextCompat.getColor(context, R.color.white); greyColor = ContextCompat.getColor(context, R.color.white_transparent_50); - roomTipNickColor = ContextCompat.getColor(context, R.color.color_FEE057); roomTipColor = ContextCompat.getColor(context, R.color.color_FEE057); - roomBlueColor = ContextCompat.getColor(context, R.color.color_00EAFF); paddingWidth = Utils.dip2px(context, 11); paddingHeight = Utils.dip2px(context, 6); badgeWidth = Utils.dip2px(context, 15); badgeHeight = Utils.dip2px(context, 15); - sysIconHeight = Utils.dip2px(context, 14); - smallFace = Utils.dip2px(context, 22); - bigFace = Utils.dip2px(context, 30); //經驗等級圖片後臺已經更換尺寸了,公屏同步下,尺寸是36:18 expLevelHeight = Utils.dip2px(context, 18); - expLevelWidth = expLevelHeight * 36 / 18;//expLevelHeight * 114 / 45 - giftLength = Utils.dip2px(context, 35); // 內容區域 layoutManger = new LinearLayoutManager(context, RecyclerView.VERTICAL, false); LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); @@ -238,7 +233,9 @@ public class PublicChatMessageView extends FrameLayout { tvBottomTip.setOnClickListener(v -> { tvBottomTip.setVisibility(GONE); needAutoScroll = true; - messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + if (mMessageAdapter.getItemCount() > 0) { + messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + } }); addView(tvBottomTip); @@ -332,7 +329,7 @@ public class PublicChatMessageView extends FrameLayout { /** * 添加公屏消息請使用 {@link AvRoomDataManager#addChatRoomMessage(ChatRoomMessage)} */ - private void addMessages(ChatRoomMessage msg) { + public void addMessages(ChatRoomMessage msg) { if (msg == null) return; chatRoomMessages.add(msg); //通知adapter 刷新 @@ -345,14 +342,14 @@ public class PublicChatMessageView extends FrameLayout { if (messages == null) return; chatRoomMessages.addAll(messages); //通知adapter 刷新 - mMessageAdapter.notifyItemInserted(mMessageAdapter.getItemCount() - 1); + mMessageAdapter.notifyDataSetChanged(); showTipsOrScrollToBottom(); for (ChatRoomMessage message : messages) { checkAtMe(message, true); } } - public void addHistoryMessages(List messages) { + public void addHistoryMessages(List messages) { chatRoomMessages.addAll(chatRoomMessages.size() > 0 ? 1 : 0, messages); mMessageAdapter.notifyDataSetChanged(); messageListView.scrollToPosition(mMessageAdapter.getItemCount() - 1); @@ -399,16 +396,20 @@ public class PublicChatMessageView extends FrameLayout { } } - private void showTipsOrScrollToBottom() { + public void showTipsOrScrollToBottom() { if (!needAutoScroll) { tvBottomTip.setVisibility(VISIBLE); //超過某值後自動滾動下去 if (mMessageAdapter.getItemCount() > BLOCK_MAX_MESSAGE_SIZE) { - messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + if (mMessageAdapter.getItemCount() > 0) { + messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + } } return; } - messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + if (mMessageAdapter.getItemCount() > 0) { + messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + } } public void release() { @@ -427,16 +428,11 @@ public class PublicChatMessageView extends FrameLayout { } } + public void setNeedAutoScroll(boolean needAutoScroll) { + this.needAutoScroll = needAutoScroll; + } + public interface OnClick { - /** - * 點擊關註 - * - * @param position - */ - void onFollowClick(int position); - - void onJoinMiniWorldClick(int position); - /** * 公屏查看公告 */ @@ -450,6 +446,8 @@ public class PublicChatMessageView extends FrameLayout { private Context mContext; private List data; + private int ITEM_TYPE_IMAGE = 1; + public MessageAdapter(Context mContext) { this.mContext = mContext; } @@ -461,13 +459,8 @@ public class PublicChatMessageView extends FrameLayout { @Override public int getItemViewType(int position) { ChatRoomMessage chatRoomMessage = data.get(position); - if (chatRoomMessage.getMsgType() == MsgTypeEnum.custom) { - MsgAttachment attachment = chatRoomMessage.getAttachment(); - if (attachment instanceof CustomAttachment) { - if (((CustomAttachment) attachment).getFirst() == CustomAttachment.CUSTOM_MSG_ROOM_ALBUM) { - return CustomAttachment.CUSTOM_MSG_ROOM_ALBUM; - } - } + if (chatRoomMessage.getMsgType() == MsgTypeEnum.image) { + return ITEM_TYPE_IMAGE; } return super.getItemViewType(position); @@ -475,13 +468,22 @@ public class PublicChatMessageView extends FrameLayout { @Override public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == ITEM_TYPE_IMAGE) { + return new MessageAdapter.MessageViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.list_item_chatroom_msg_image, parent, false)); + + } return new MessageViewHolder(LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item_chatrrom_msg, parent, false)); } @Override public void onBindViewHolder(MessageViewHolder holder, int position) { - convert(holder, data.get(position)); + if (getItemViewType(position) == ITEM_TYPE_IMAGE) { + convertImage(holder, data.get(position)); + } else { + convert(holder, data.get(position)); + } } @Override @@ -489,11 +491,57 @@ public class PublicChatMessageView extends FrameLayout { return data.size(); } + protected void convertImage(MessageViewHolder baseViewHolder, ChatRoomMessage chatRoomMessage) { + TextView tvContent = baseViewHolder.tvContent; + tvContent.setLineSpacing(0, 1); + tvContent.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); + tvContent.setOnClickListener(this); + tvContent.setTag(chatRoomMessage); + if (UiUtils.INSTANCE.isRtl(tvContent.getContext())) { + tvContent.setTextDirection(View.TEXT_DIRECTION_RTL); + } + try { + setVIPMessageBackground(chatRoomMessage, baseViewHolder.itemView); + ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + addCommonTag(chatRoomMessage, text, tvContent); + String nickName = extension == null ? ResUtil.getString(R.string.avroom_widget_messageview_0116) : RegexUtil.getPrintableString(extension.getSenderNick()); + text.append(nickName, new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + + ImageView imageView = baseViewHolder.itemView.findViewById(R.id.iv_image); + ImageAttachment msgAttachment = (ImageAttachment) chatRoomMessage.getAttachment(); + String path = msgAttachment.getThumbPath(); + if (TextUtils.isEmpty(path)) { + path = msgAttachment.getPath(); + } + if (TextUtils.isEmpty(path)) { + path = ""; + } + ImageLoadUtilsV2.loadImage(imageView, path); + int[] bounds = new int[]{msgAttachment.getWidth(), msgAttachment.getHeight()}; + ImageUtil.ImageSize imageSize = ImageUtil.getThumbnailDisplaySize(bounds[0], bounds[1], ChatRoomMessageViewHolderThumbBase.getImageMaxEdge(), ChatRoomMessageViewHolderThumbBase.getImageMinEdge()); + ViewGroup.LayoutParams maskParams = imageView.getLayoutParams(); + maskParams.width = imageSize.width; + maskParams.height = imageSize.height; + imageView.setLayoutParams(maskParams); + String finalPath = path; + imageView.setOnClickListener(v -> { + BigPhotoActivity.start((Activity) mContext, ObjectTypeHelper.pathToCustomItems(finalPath), + 0, new PagerOption()); + }); + + } catch (Exception e) { + e.printStackTrace(); + } + } + protected void convert(MessageViewHolder baseViewHolder, ChatRoomMessage chatRoomMessage) { if (chatRoomMessage == null) return; TextView tvContent = baseViewHolder.tvContent; tvContent.setLineSpacing(0, 1); tvContent.setTextColor(Color.WHITE); + tvContent.setTextSize(defTextSize); tvContent.setOnClickListener(this); tvContent.setOnLongClickListener(null); tvContent.setTag(chatRoomMessage); @@ -504,11 +552,10 @@ public class PublicChatMessageView extends FrameLayout { clearBackground(tvContent); try { if (chatRoomMessage.getMsgType() == MsgTypeEnum.tip) { - String contentText = chatRoomMessage.getContent(); // 房間通告 - tvContent.setTextColor(ContextCompat.getColor(mContext, R.color.color_92F9E8)); - tvContent.setText(chatRoomMessage.getContent()); - tvContent.setBackgroundResource(R.drawable.shape_room_message_tip_bg); + tvContent.setTextColor(ContextCompat.getColor(mContext, R.color.color_92F9E8)); + tvContent.setText(chatRoomMessage.getContent()); + tvContent.setBackgroundResource(R.drawable.shape_room_message_tip_bg); } else if (chatRoomMessage.getMsgType() == MsgTypeEnum.text) { setMsgText(chatRoomMessage, tvContent); setVIPMessageBackground(chatRoomMessage, tvContent); @@ -520,8 +567,10 @@ public class PublicChatMessageView extends FrameLayout { CustomAttachment attachment = (CustomAttachment) chatRoomMessage.getAttachment(); int first = attachment.getFirst(); int second = attachment.getSecond(); - if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_AUCTION) { - setMsgAuction(chatRoomMessage, tvContent, attachment); + if (first == CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED) { + if (second == CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED_SUB) { + setHeadlineMsg(chatRoomMessage, tvContent, attachment); + } } else { tvContent.setTextColor(Color.WHITE); tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); @@ -543,6 +592,12 @@ public class PublicChatMessageView extends FrameLayout { textView.setPadding(paddingWidth, paddingHeight, paddingWidth, paddingHeight); } + private void setNullBackground(TextView textView) { + // 清除聊天氣泡 + textView.setBackground(null); + textView.setPadding(0, 0, 0, 0); + } + public void setVIPMessageBackground(ChatRoomMessage chatRoomMessage, View view) { String androidBubbleUrl = NobleUtil.getResource(UserInfo.BUBBLE_URL_ANDROID, chatRoomMessage); if (TextUtils.isEmpty(androidBubbleUrl)) return; @@ -630,34 +685,24 @@ public class PublicChatMessageView extends FrameLayout { } } - /** - * 暫時已拋棄 - * - * @param chatRoomMessage - - * @param tvContent - - * @param attachment - - */ - private void setMsgAuction(ChatRoomMessage chatRoomMessage, TextView tvContent, CustomAttachment attachment) { - String senderNick = chatRoomMessage.getChatRoomMessageExtension().getSenderNick(); - senderNick = senderNick == null ? "" : senderNick; - AuctionAttachment auctionAttachment = (AuctionAttachment) attachment; - TextSpannableBuilder builder = new TextSpannableBuilder(tvContent); - if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_TYPE_AUCTION_START) { - builder.append(ResUtil.getString(R.string.avroom_widget_messageview_0117), new ForegroundColorSpan(roomTipNickColor)); - } else if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_TYPE_AUCTION_FINISH) { - if (auctionAttachment.getAuctionInfo().getCurMaxUid() > 0) { - senderNick = UserInfoHelper.getUserDisplayName(auctionAttachment.getAuctionInfo().getCurMaxUid() + ""); - String voiceActorNick = UserInfoHelper.getUserDisplayName(auctionAttachment.getAuctionInfo().getAuctUid() + ""); - builder.append(senderNick, new ForegroundColorSpan(roomTipNickColor)) - .append(ResUtil.getString(R.string.avroom_widget_messageview_0118) + auctionAttachment.getAuctionInfo().getRivals().get(0).getAuctMoney() + ResUtil.getString(R.string.avroom_widget_messageview_0119)) - .append(voiceActorNick, new ForegroundColorSpan(roomTipNickColor)); - } else - builder.append(ResUtil.getString(R.string.avroom_widget_messageview_0120), new ForegroundColorSpan(roomTipNickColor)); - } else { - builder.append(senderNick, new ForegroundColorSpan(roomTipNickColor)) - .append(ResUtil.getString(R.string.avroom_widget_messageview_0121) + auctionAttachment.getAuctionInfo().getRivals().get(0).getAuctMoney() + ResUtil.getString(R.string.avroom_widget_messageview_027)); + private void setHeadlineMsg(ChatRoomMessage chatRoomMessage, TextView tvContent, CustomAttachment attachment) { + HeadlineChangedAttachment headlineAttachment = (HeadlineChangedAttachment) attachment; + SpannableTextBuilder builder = new SpannableTextBuilder(tvContent); + if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED_SUB) { + HeadlineBean data = headlineAttachment.getHeadlineData(); + String nick = null; + if (data != null) { + nick = data.getNick(); + } + if (nick == null) { + nick = ""; + } + builder.appendText(String.format(ResUtil.getString(R.string.headline_message_format), nick), null, null, null, null, null, null); + builder.setTextStyle(nick, ContextCompat.getColor(getContext(), R.color.color_DE3446), null, null, null, null, null); } tvContent.setText(builder.build()); + tvContent.setTextSize(9); + setNullBackground(tvContent); } /** diff --git a/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatRoomMessageWidget.kt b/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatRoomMessageWidget.kt index 16046472c..435c747d0 100644 --- a/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatRoomMessageWidget.kt +++ b/app/src/main/java/com/chwl/app/avroom/public_chat/PublicChatRoomMessageWidget.kt @@ -2,11 +2,18 @@ package com.chwl.app.avroom.public_chat import android.content.Context import android.util.AttributeSet -import android.view.ViewGroup +import android.view.LayoutInflater +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil import com.chwl.app.R +import com.chwl.app.databinding.RoomPublicChatMessageWidgetBinding import com.chwl.app.public_chat.core.ChatRoomClient import com.chwl.app.public_chat.core.ChatRoomClientManager +import com.chwl.core.im.custom.bean.CustomAttachment +import com.chwl.core.im.custom.bean.HeadlineChangedAttachment import com.chwl.core.initial.InitialModel +import com.chwl.core.public_chat_hall.bean.HeadlineBean +import com.chwl.core.public_chat_hall.model.PublicChatModel import com.chwl.core.support.room.FrameLayoutRoomWidget import com.chwl.core.support.room.RoomView import com.chwl.library.utils.SingleToastUtil @@ -14,11 +21,15 @@ import com.netease.nim.uikit.api.model.NimException import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum import com.netease.nimlib.sdk.msg.model.QueryDirectionEnum -import java.util.Collections class PublicChatRoomMessageWidget : FrameLayoutRoomWidget { - private var messageListView: PublicChatMessageView = PublicChatMessageView(context) + private val binding: RoomPublicChatMessageWidgetBinding = + DataBindingUtil.inflate( + LayoutInflater.from( + context + ), R.layout.room_public_chat_message_widget, this, true + ) private var chatRoomClient: ChatRoomClient? = null @@ -37,13 +48,6 @@ class PublicChatRoomMessageWidget : FrameLayoutRoomWidget { defStyleRes: Int ) : super(context, attrs, defStyleAttr, defStyleRes) - init { - addView( - messageListView, - LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) - ) - } - override fun onStart(roomView: RoomView) { super.onStart(roomView) val sessionId = InitialModel.get().publicChatSessionId @@ -55,10 +59,26 @@ class PublicChatRoomMessageWidget : FrameLayoutRoomWidget { chatRoomClient?.let { initChatRoom(it) } + requestCurrentHeadline() } - private fun onReceiveMessage(list: List) { - messageListView.addMessages(list) + private fun onReceiveMessage(message: ChatRoomMessage) { + if (!filterMessageForMessageList(message)) { + binding.messageView.addMessages(message) + } + if (message.msgType == MsgTypeEnum.custom) { + val attachment: CustomAttachment = (message.attachment as? CustomAttachment) ?: return + when (attachment.first) { + CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED -> { + when (attachment.second) { + CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED_SUB -> { + val data = (attachment as? HeadlineChangedAttachment) ?: return + updateHeadline(data.headlineData) + } + } + } + } + } } private fun initChatRoom(chatRoomClient: ChatRoomClient) { @@ -75,7 +95,9 @@ class PublicChatRoomMessageWidget : FrameLayoutRoomWidget { ) getCompositeDisposable().add(chatRoomClient.messageObservable.subscribe { - onReceiveMessage(it) + it.forEach { message -> + onReceiveMessage(message) + } }) } @@ -88,13 +110,44 @@ class PublicChatRoomMessageWidget : FrameLayoutRoomWidget { QueryDirectionEnum.QUERY_OLD, typeEnums ).subscribe({ - messageListView.addHistoryMessages(it.reversed()) + binding.messageView.addHistoryMessages(it.reversed()) }, { it.printStackTrace() }) ) } + private fun requestCurrentHeadline() { + safeLaunch { + val data = PublicChatModel.getCurrentHeadline() + updateHeadline(data) + } + } + + private fun updateHeadline(data: HeadlineBean?) { + val content = data?.content + if (content.isNullOrEmpty()) { + binding.tvHeadlineContent.isVisible = false + } else { + binding.tvHeadlineContent.text = content + binding.tvHeadlineContent.isVisible = true + } + } + + private fun filterMessageForMessageList(message: ChatRoomMessage): Boolean { + if (message.msgType == MsgTypeEnum.notification) { + return true + } + if (message.attachment is HeadlineChangedAttachment) { + if ((message.attachment as HeadlineChangedAttachment).headlineData == null) { + return true + } + } + return false + } + + fun getMessageView() = binding.messageView + override fun onStop() { super.onStop() chatRoomClient = null diff --git a/app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt b/app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt index a7c50aa15..ca3bd783e 100644 --- a/app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt +++ b/app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt @@ -3,6 +3,7 @@ package com.chwl.app.avroom.view import com.chwl.core.bean.RoomMicInfo import com.chwl.core.room.bean.RoomContributeUserInfo import com.chwl.library.base.IMvpBaseView +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage /** * @@ -32,6 +33,7 @@ interface IBaseRoomView : IMvpBaseView { fun chatRoomReConnectView() fun showToast(msg: String?) fun onSendMsgSuccess(msg: String?) + fun onSendPublicChatMsgSuccess(msg: ChatRoomMessage) /** * 上麦请求 diff --git a/app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt index 6c6bfbc7b..3078240ce 100644 --- a/app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt +++ b/app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt @@ -5,7 +5,6 @@ import android.view.MotionEvent import android.widget.LinearLayout import android.widget.TextView import androidx.core.view.GestureDetectorCompat -import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.RecyclerView @@ -166,7 +165,6 @@ class ContactsListFragment : BaseViewBindingFragment publicChatAdapter.setNewData(newList) switchPublicChatMessageScrollState(true) } - binding.layoutPublicChat.isVisible = (publicChatAdapter.getRealItemCount() > 0) } } @@ -190,6 +188,9 @@ class ContactsListFragment : BaseViewBindingFragment } private fun switchPublicChatMessageScrollState(showOrHide: Boolean) { + if (_binding == null) { + return + } if (showOrHide && publicChatAdapter.getRealItemCount() > 0) { autoScrollTask.start() } else { diff --git a/app/src/main/res/drawable-xxhdpi/room_ic_headline_send.png b/app/src/main/res/drawable-xxhdpi/room_ic_headline_send.png new file mode 100644 index 0000000000000000000000000000000000000000..de39b8a5d300dbd49a670823cbd1ad8f68ef94f4 GIT binary patch literal 36889 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/shape_593722_7dp.xml b/app/src/main/res/drawable/shape_593722_7dp.xml new file mode 100644 index 000000000..caf2d96e1 --- /dev/null +++ b/app/src/main/res/drawable/shape_593722_7dp.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_av_room_game.xml b/app/src/main/res/layout/fragment_av_room_game.xml index fe9c7e581..57bdcca26 100644 --- a/app/src/main/res/layout/fragment_av_room_game.xml +++ b/app/src/main/res/layout/fragment_av_room_game.xml @@ -117,8 +117,9 @@ @@ -132,18 +133,6 @@ android:layout_marginEnd="90dp" android:layout_marginBottom="@dimen/dp_10" /> - - - - - - - - - - - - + + + diff --git a/app/src/main/res/layout/fragment_contact_list.xml b/app/src/main/res/layout/fragment_contact_list.xml index 4d4a9571e..ab64ee62b 100644 --- a/app/src/main/res/layout/fragment_contact_list.xml +++ b/app/src/main/res/layout/fragment_contact_list.xml @@ -14,8 +14,6 @@ app:layout_constraintTop_toTopOf="parent" /> - + + + app:layout_constraintTop_toBottomOf="@id/message_indicator" /> + + diff --git a/app/src/main/res/layout/list_item_chatroom_msg_image.xml b/app/src/main/res/layout/list_item_chatroom_msg_image.xml new file mode 100644 index 000000000..5581ea101 --- /dev/null +++ b/app/src/main/res/layout/list_item_chatroom_msg_image.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_chatrrom_msg.xml b/app/src/main/res/layout/list_item_chatrrom_msg.xml index 537573f39..648b52b69 100644 --- a/app/src/main/res/layout/list_item_chatrrom_msg.xml +++ b/app/src/main/res/layout/list_item_chatrrom_msg.xml @@ -13,7 +13,7 @@ android:background="@drawable/shape_room_message_bg" android:gravity="start|center_vertical" android:textColor="@android:color/white" - android:textSize="12sp" + android:textSize="12dp" tools:text="@string/layout_list_item_chatrrom_msg_01" tools:textColor="#000" /> diff --git a/app/src/main/res/layout/room_public_chat_message_widget.xml b/app/src/main/res/layout/room_public_chat_message_widget.xml new file mode 100644 index 000000000..82daa60fd --- /dev/null +++ b/app/src/main/res/layout/room_public_chat_message_widget.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 5d4f0a793..4735c5d06 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -5261,4 +5261,6 @@ {0} محظوظ للغاية! تم فتح {3} بقيمة {2} من العملات الذهبية في {1} {0} محظوظ للغاية! تم فتح {4}X{3} بقيمة {2} من العملات الذهبية في {1} أنت لم تصل إلى المستوى الـ VIP المطلوب لإرسال %1$s. المستوى الـ VIP المطلوب: %2$s + حدثت بعض الاستثناءات، يرجى المحاولة مرة أخرى لاحقًا! + يرجى السماح بإذن الميكروفون والمحاولة مرة أخرى \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 5f8d0cd6c..c68f72c8f 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -5203,4 +5203,5 @@ 尚未達到贈送%1$s所需VIP等級,所需VIP等級:%2$s {0}運氣爆表!在{1}中開出了價值{2}金币的{3} {0}運氣爆表!在{1}中開出了價值{2}金币的{3}X{4} + 發生一些異常,請稍後重試! \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 20baa1c05..b17c759be 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5240,6 +5240,9 @@ {0} Amazing Luck! Opened a {1} worth {2} Coins in {3} {0} Amazing Luck! Opened a {1} worth {2} Coins in {3} X{4} + + Some exceptions occurred, please try again later! + Please allow microphone permission and try again diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8adf11760..bda923dad 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -610,4 +610,8 @@ @dimen/dp_6 + diff --git a/app/src/module_public_chat/java/com/chwl/app/public_chat/core/ChatRoomClientManager.kt b/app/src/module_public_chat/java/com/chwl/app/public_chat/core/ChatRoomClientManager.kt index 19dabdb5d..37f0d8650 100644 --- a/app/src/module_public_chat/java/com/chwl/app/public_chat/core/ChatRoomClientManager.kt +++ b/app/src/module_public_chat/java/com/chwl/app/public_chat/core/ChatRoomClientManager.kt @@ -1,9 +1,16 @@ package com.chwl.app.public_chat.core +import com.chwl.core.initial.InitialModel + object ChatRoomClientManager { private val clients = HashMap() + fun getPublicChatClient(): ChatRoomClient? { + val sessionId = InitialModel.get().publicChatSessionId + return getClient(sessionId) + } + fun getClient(sessionId: String): ChatRoomClient { var finalClient = clients[sessionId] if (finalClient?.sessionId == sessionId) { diff --git a/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/HeadlineViewModel.kt b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/HeadlineViewModel.kt new file mode 100644 index 000000000..49e985be3 --- /dev/null +++ b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/HeadlineViewModel.kt @@ -0,0 +1,37 @@ +package com.chwl.app.public_chat.ui.message + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.BeanResult +import com.chwl.core.public_chat_hall.model.PublicChatModel +import kotlinx.coroutines.flow.MutableSharedFlow + +class HeadlineViewModel : BaseViewModel() { + + val sendHeadlineFlow = MutableSharedFlow>() + + val headlinePayMoneyLiveData = MutableLiveData() + + fun sendHeadline(message: String) { + safeLaunch(needLoading = true, onError = { + sendHeadlineFlow.emit(BeanResult.failed(it)) + }) { + PublicChatModel.sendHeadline(message) + sendHeadlineFlow.emit(BeanResult.success(true)) + } + } + + fun getHeadlinePayMoneyIsNull() { + if (headlinePayMoneyLiveData.value == null) { + getHeadlinePayMoney() + } + } + + fun getHeadlinePayMoney() { + safeLaunch(needLoading = false, onError = { + }) { + val value = PublicChatModel.getHeadlinePayMoney() + headlinePayMoneyLiveData.postValue(value) + } + } +} \ No newline at end of file diff --git a/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomMessageListPanel.java b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomMessageListPanel.java index e35401693..69bcce7f9 100644 --- a/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomMessageListPanel.java +++ b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomMessageListPanel.java @@ -260,7 +260,6 @@ public class PublicChatRoomMessageListPanel { } public void onIncomingMessage(List messages) { - Log.d("MAAAX", "onIncomingMessage messages.size:" + messages.size()); boolean needScrollToBottom = isLastMessageVisible(); boolean needRefresh = false; List addedListItems = new ArrayList<>(messages.size()); diff --git a/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomViewModel.kt b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomViewModel.kt index 85f6f196a..54fce414e 100644 --- a/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomViewModel.kt +++ b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/PublicChatRoomViewModel.kt @@ -1,17 +1,16 @@ package com.chwl.app.public_chat.ui.message +import android.annotation.SuppressLint import androidx.lifecycle.MutableLiveData import com.chwl.app.base.BaseViewModel import com.chwl.app.public_chat.core.ChatRoomClient import com.chwl.app.public_chat.core.ChatRoomClientManager -import com.chwl.core.bean.response.BeanResult import com.chwl.core.im.custom.bean.CustomAttachment import com.chwl.core.im.custom.bean.HeadlineChangedAttachment import com.chwl.core.public_chat_hall.bean.HeadlineBean import com.chwl.core.public_chat_hall.model.PublicChatModel import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum -import kotlinx.coroutines.flow.MutableSharedFlow class PublicChatRoomViewModel : BaseViewModel() { @@ -19,20 +18,17 @@ class PublicChatRoomViewModel : BaseViewModel() { val headlineLiveData = MutableLiveData() - val sendHeadlineFlow = MutableSharedFlow>() - - val headlinePayMoneyLiveData = MutableLiveData() - fun init(sessionId: String) { val client = ChatRoomClientManager.getClient(sessionId) chatRoomClient = client registerReceiveMessage(client) } + @SuppressLint("CheckResult") fun sendMessage(message: ChatRoomMessage) { - chatRoomClient?.sendMessage(message)?.doOnError { - it.printStackTrace() - }?.subscribe({}, {}) + chatRoomClient?.sendMessage(message)?.subscribe({}, {})?.let { + addDisposable(it) + } } fun getCurrentHeadline() { @@ -47,23 +43,6 @@ class PublicChatRoomViewModel : BaseViewModel() { headlineLiveData.postValue(headline) } - fun sendHeadline(message: String) { - safeLaunch(needLoading = true, onError = { - sendHeadlineFlow.emit(BeanResult.failed(it)) - }) { - PublicChatModel.sendHeadline(message) - sendHeadlineFlow.emit(BeanResult.success(true)) - } - } - - fun getHeadlinePayMoney() { - safeLaunch(needLoading = false, onError = { - }) { - val value = PublicChatModel.getHeadlinePayMoney() - headlinePayMoneyLiveData.postValue(value) - } - } - private fun registerReceiveMessage(chatRoomClient: ChatRoomClient) { addDisposable(chatRoomClient.messageObservable.subscribe { it.forEach { @@ -87,8 +66,4 @@ class PublicChatRoomViewModel : BaseViewModel() { } } } - - override fun onCleared() { - super.onCleared() - } } \ No newline at end of file diff --git a/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/headline/HeadlineSendDialog.kt b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/headline/HeadlineSendDialog.kt index df8f12bcc..3d8da8548 100644 --- a/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/headline/HeadlineSendDialog.kt +++ b/app/src/module_public_chat/java/com/chwl/app/public_chat/ui/message/headline/HeadlineSendDialog.kt @@ -2,12 +2,14 @@ package com.chwl.app.public_chat.ui.message.headline import android.view.Gravity import android.view.WindowManager +import android.widget.Toast import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import com.chwl.app.R import com.chwl.app.base.BaseDialog import com.chwl.app.common.widget.dialog.DialogManager import com.chwl.app.databinding.HeadlineSendDialogBinding +import com.chwl.app.public_chat.ui.message.HeadlineViewModel import com.chwl.app.public_chat.ui.message.PublicChatRoomViewModel import com.chwl.app.ui.pay.ChargeActivity import com.chwl.app.ui.widget.dialog.CommonTipDialog @@ -20,7 +22,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class HeadlineSendDialog : BaseDialog() { - private val viewModel by activityViewModels() + private val viewModel by activityViewModels() override var width = WindowManager.LayoutParams.MATCH_PARENT override var height = WindowManager.LayoutParams.WRAP_CONTENT @@ -31,7 +33,7 @@ class HeadlineSendDialog : BaseDialog() { lifecycleScope.launch(Dispatchers.Main) { viewModel.sendHeadlineFlow.collect { if (it.isSuccess) { - SingleToastUtil.showToast("success") + SingleToastUtil.showToast(R.string.sent_success) dismissAllowingStateLoss() } else { if (it.code == BalanceNotEnoughExeption.code) { diff --git a/app/src/module_public_chat/res/values-ar/strings.xml b/app/src/module_public_chat/res/values-ar/strings.xml index f28f6ccfb..5104c7511 100644 --- a/app/src/module_public_chat/res/values-ar/strings.xml +++ b/app/src/module_public_chat/res/values-ar/strings.xml @@ -7,4 +7,6 @@ ~عزيزي%s، هيا تصدر العناوين رصيد العملات الذهبية غير كافي ،هل تريد إعادة الشحن علي الفور؟ الرجاء إدخال المحتوي الذي تريد أن تتصدر عناوينهّ~ (يقتصر على 100 كلمة) + 頭條字數請勿超過100字~ + 發送成功 \ No newline at end of file diff --git a/app/src/module_public_chat/res/values-zh-rTW/strings.xml b/app/src/module_public_chat/res/values-zh-rTW/strings.xml index 062b0602a..4ee913319 100644 --- a/app/src/module_public_chat/res/values-zh-rTW/strings.xml +++ b/app/src/module_public_chat/res/values-zh-rTW/strings.xml @@ -8,4 +8,7 @@ 尊貴的%s,上頭條啦~ 金幣餘額不足,是否立即儲值? 請輸入想上頭條的內容呀~(僅限100字) + 頭條字數請勿超過100字~ + 請給予麥克風權限後再試 + 發送成功 \ No newline at end of file diff --git a/app/src/module_public_chat/res/values/strings.xml b/app/src/module_public_chat/res/values/strings.xml index 4d1e8f353..1f95ffdee 100644 --- a/app/src/module_public_chat/res/values/strings.xml +++ b/app/src/module_public_chat/res/values/strings.xml @@ -7,4 +7,6 @@ Honorable %s sent a broadcast~ The coin is insufficient,Would you like to recharge? Please enter the content you want to broadcast~(100 characters) + 頭條字數請勿超過100字~ + 發送成功 \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/support/room/FrameLayoutRoomWidget.kt b/core/src/main/java/com/chwl/core/support/room/FrameLayoutRoomWidget.kt index aab09575c..60ad42f6a 100644 --- a/core/src/main/java/com/chwl/core/support/room/FrameLayoutRoomWidget.kt +++ b/core/src/main/java/com/chwl/core/support/room/FrameLayoutRoomWidget.kt @@ -5,7 +5,15 @@ import android.util.AttributeSet import android.widget.FrameLayout import androidx.annotation.CallSuper import androidx.lifecycle.Observer +import androidx.lifecycle.viewModelScope +import com.chwl.core.utils.extension.toast +import com.chwl.library.net.rxnet.exception.ExceptionHandle import io.reactivex.disposables.CompositeDisposable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import java.lang.Exception /** * Created by Max on 2023/10/30 18:20 @@ -14,6 +22,7 @@ import io.reactivex.disposables.CompositeDisposable **/ abstract class FrameLayoutRoomWidget : FrameLayout, RoomWidget { + protected val widgetScope = MainScope() protected var roomView: RoomView? = null // 当前房间UID @@ -77,6 +86,11 @@ abstract class FrameLayoutRoomWidget : FrameLayout, RoomWidget { open fun onUnbindContext() { compositeDisposable?.dispose() compositeDisposable = null + try { + widgetScope.cancel() + } catch (e: Exception) { + e.printStackTrace() + } } /** @@ -92,4 +106,26 @@ abstract class FrameLayoutRoomWidget : FrameLayout, RoomWidget { } return disposable } + + protected fun safeLaunch( + onError: suspend(e: Throwable) -> Unit = { + if (it.message != "Job was cancelled") { + val message = ExceptionHandle.handleException(it) + message.toast() + } + }, + onComplete: (() -> Unit)? = null, + block: suspend CoroutineScope.() -> Unit + ) { + widgetScope.launch { + try { + block() + } catch (e: Throwable) { + e.printStackTrace() + onError(e) + } finally { + onComplete?.invoke() + } + } + } } \ No newline at end of file diff --git a/core/src/model_public_chat_hall/java/com/chwl/core/public_chat_hall/model/PublicChatModel.kt b/core/src/model_public_chat_hall/java/com/chwl/core/public_chat_hall/model/PublicChatModel.kt index bf4021674..701a80e5b 100644 --- a/core/src/model_public_chat_hall/java/com/chwl/core/public_chat_hall/model/PublicChatModel.kt +++ b/core/src/model_public_chat_hall/java/com/chwl/core/public_chat_hall/model/PublicChatModel.kt @@ -5,7 +5,6 @@ import com.chwl.core.bean.response.ServiceResult import com.chwl.core.public_chat_hall.bean.HeadlineBean import com.chwl.core.public_chat_hall.bean.PublicChatMessageBean import com.chwl.core.utils.net.launchRequest -import com.chwl.core.vip.bean.VipPageInfo import com.chwl.library.net.rxnet.RxNet import retrofit2.http.Field import retrofit2.http.FormUrlEncoded