feat:完善游戏房公屏展示与消息发送

This commit is contained in:
max
2024-05-29 15:26:04 +08:00
parent c72af689e5
commit 65ef4810e3
17 changed files with 453 additions and 72 deletions

View File

@@ -565,13 +565,12 @@ public class BaseRoomPresenter<V extends IBaseRoomView> extends BaseMvpPresenter
@SuppressLint("CheckResult")
public void sendPublicChatTextMessage(String message) {
if (TextUtils.isEmpty(message)) return;
String sessionId = InitialModel.get().getPublicChatSessionId();
if (sessionId == null) {
ChatRoomClient client = ChatRoomClientManager.INSTANCE.getPublicChatClient();
if (client == null) {
SingleToastUtil.showToast(R.string.public_chat_not_found);
return;
}
ChatRoomClient client = ChatRoomClientManager.INSTANCE.getClient(sessionId);
ChatRoomMessage textMessage = ChatRoomMessageBuilder.createChatRoomTextMessage(sessionId, message);
ChatRoomMessage textMessage = ChatRoomMessageBuilder.createChatRoomTextMessage(client.getSessionId(), message);
client.sendMessage(textMessage).compose(bindToLifecycle()).subscribe(new BiConsumer<Object, Throwable>() {
@Override
public void accept(Object o, Throwable throwable) throws Exception {

View File

@@ -388,9 +388,6 @@ public class PublicChatMessageView extends FrameLayout {
}
return;
}
if (mMessageAdapter.getItemCount() > 0) {
messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1);
}
}
public void release() {

View File

@@ -50,10 +50,8 @@ class PublicChatRoomMessageWidget : FrameLayoutRoomWidget {
override fun onStart(roomView: RoomView) {
super.onStart(roomView)
val sessionId = InitialModel.get().publicChatSessionId
if (sessionId != null) {
chatRoomClient = ChatRoomClientManager.getClient(sessionId);
} else {
chatRoomClient = ChatRoomClientManager.getPublicChatClient()
if (chatRoomClient == null) {
SingleToastUtil.showToast(R.string.public_chat_not_found)
}
chatRoomClient?.let {

View File

@@ -2,52 +2,76 @@ package com.chwl.app.game.core
import com.chwl.app.public_chat.core.ChatRoomClient
import com.chwl.app.public_chat.core.ChatRoomClientManager
import com.chwl.core.support.listener.ListenerOwner
import com.chwl.core.support.listener.ListenerStore
import com.chwl.core.support.listener.SafeListenerOwner
import com.chwl.core.support.room.RoomAbility
import com.chwl.core.support.room.RoomContext
import com.netease.nimlib.sdk.StatusCode
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.netease.nimlib.sdk.msg.model.QueryDirectionEnum
import io.reactivex.Single
import kotlinx.coroutines.flow.MutableStateFlow
import java.lang.IllegalStateException
class GameIMEngineAbility : RoomAbility() {
class GameIMEngineAbility(private val listenerOwner: ListenerOwner<GameIMEngineAbility.Listener> = SafeListenerOwner()) :
RoomAbility(), ListenerStore<GameIMEngineAbility.Listener> by listenerOwner {
private var client: ChatRoomClient? = null
private var chatRoomClient: ChatRoomClient? = null
val stateFlow = MutableStateFlow<StatusCode>(StatusCode.INVALID)
fun enterRoom(sessionId: String) {
client = ChatRoomClientManager.getClient(sessionId)
client?.let {
addDisposable(it.enterChatRoom().subscribe({
}, {
}))
if (chatRoomClient != null && chatRoomClient?.sessionId != sessionId) {
chatRoomClient?.onCleared()
}
initClient(sessionId)
}
private fun initClient(sessionId: String) {
chatRoomClient = ChatRoomClientManager.getClient(sessionId)
chatRoomClient?.let {
safeLaunch {
it.stateFlow.collect {
this@GameIMEngineAbility.stateFlow.emit(it)
}
}
addDisposable(it.messageObservable.subscribe { list ->
listenerOwner.postEvent { it.onReceiveMessage(list) }
})
enterChatRoom(it)
}
}
private fun enterChatRoom(client: ChatRoomClient) {
addDisposable(client.enterChatRoom().subscribe({
}, {
}))
}
fun sendMessage(message: ChatRoomMessage) {
client?.let {
addDisposable(it.sendMessage(message).subscribe({
}, {
}))
chatRoomClient?.let {
addDisposable(it.sendMessage(message).subscribe({}, {}))
}
}
private fun requestHistory(chatRoomClient: ChatRoomClient) {
val typeEnums = arrayOf(MsgTypeEnum.text)
addDisposable(
chatRoomClient.requestRemoteMessageType(
0,
50,
QueryDirectionEnum.QUERY_OLD,
typeEnums
).subscribe({
}, {
it.printStackTrace()
})
)
fun buildTextMessage(text: String): ChatRoomMessage? {
val client = chatRoomClient ?: return null
return ChatRoomMessageBuilder.createChatRoomTextMessage(client.sessionId, text)
}
fun sendMessageRx(message: ChatRoomMessage): Single<Any> {
val client = chatRoomClient ?: return Single.error(IllegalStateException("client is NULL"))
return client.sendMessage(message)
}
override fun onStop(context: RoomContext) {
super.onStop(context)
listenerOwner.removeAllListener()
chatRoomClient?.onCleared()
}
interface Listener {
fun onStateChange()
fun onReceiveMessage(messages: List<ChatRoomMessage>)
}
}

View File

@@ -4,12 +4,23 @@ import com.chwl.core.support.listener.ListenerOwner
import com.chwl.core.support.listener.ListenerStore
import com.chwl.core.support.listener.SafeListenerOwner
import com.chwl.core.support.room.RoomAbility
import com.chwl.core.support.room.RoomContext
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum
import io.reactivex.Single
import java.lang.IllegalStateException
class GameMessageAbility(private val listenerOwner: ListenerOwner<GameMessageAbility.Listener> = SafeListenerOwner()) :
RoomAbility(), ListenerStore<GameMessageAbility.Listener> by listenerOwner {
RoomAbility(), ListenerStore<GameMessageAbility.Listener> by listenerOwner,
GameIMEngineAbility.Listener {
private val dataList = ArrayList<Any>()
private val imEngineAbility
get() =
roomContext?.findAbility<GameIMEngineAbility>(GameIMEngineAbility::class.java.simpleName)
fun getMessageList(): List<Any> {
return dataList
}
@@ -21,6 +32,44 @@ class GameMessageAbility(private val listenerOwner: ListenerOwner<GameMessageAbi
}
}
fun sendTextMessage(text: String): Single<Any> {
imEngineAbility?.let {
val textMessage = it.buildTextMessage(text)
if (textMessage == null) {
return Single.error(IllegalStateException("message is NULL"))
} else {
return it.sendMessageRx(textMessage).map {
addMessage(textMessage)
}
}
}
return Single.error(IllegalStateException("engine is NULL"))
}
override fun onStart(context: RoomContext) {
super.onStart(context)
val imEngineAbility =
context.findAbility<GameIMEngineAbility>(GameIMEngineAbility::class.java.simpleName)
imEngineAbility?.addListener(this)
}
override fun onStop(context: RoomContext) {
super.onStop(context)
listenerOwner.removeAllListener()
}
override fun onReceiveMessage(messages: List<ChatRoomMessage>) {
messages.forEach {
onReceiveMessage(it)
}
}
private fun onReceiveMessage(message: ChatRoomMessage) {
if (message.msgType == MsgTypeEnum.text) {
addMessage(message)
}
}
interface Listener {
fun onAddMessage(message: Any)

View File

@@ -3,7 +3,9 @@ package com.chwl.app.game.ui.game
import androidx.lifecycle.MutableLiveData
import com.chwl.app.base.BaseViewModel
import com.chwl.app.game.core.GameContext
import com.chwl.core.support.room.RoomContext
import com.chwl.app.game.core.GameIMEngineAbility
import com.chwl.app.public_chat.core.ChatRoomClientManager
import com.chwl.core.initial.InitialModel
class GameViewModel : BaseViewModel() {
@@ -11,6 +13,14 @@ class GameViewModel : BaseViewModel() {
fun init(intent: GameIntent) {
val gameContext = GameContext(intent.roomId)
gameContext.performStart()
gameContextLiveData.value = gameContext
gameContext.findAbility<GameIMEngineAbility>(GameIMEngineAbility::class.java.simpleName)?.enterRoom(
InitialModel.get().publicChatSessionId)
}
override fun onCleared() {
super.onCleared()
gameContextLiveData.value?.performStop()
}
}

View File

@@ -2,6 +2,7 @@ package com.chwl.app.game.ui.game.input
import android.app.Dialog
import android.os.Bundle
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -11,12 +12,15 @@ import androidx.lifecycle.repeatOnLifecycle
import com.chwl.app.R
import com.chwl.app.common.widget.dialog.DialogManager
import com.chwl.app.databinding.GameMessageInputDialogBinding
import com.chwl.app.game.core.GameContext
import com.chwl.app.game.core.GameMessageAbility
import com.chwl.core.support.room.RoomContext
import com.chwl.library.utils.SingleToastUtil
import com.chwl.library.utils.keyboard.KeyboardUtil
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.coroutines.launch
class GameMessageInputDialog :
class GameMessageInputDialog(private var onSend: ((GameMessageInputDialog, String) -> Unit)?) :
BottomSheetDialogFragment() {
private var binding: GameMessageInputDialogBinding? = null
@@ -34,9 +38,21 @@ class GameMessageInputDialog :
binding?.inputEdit?.let {
KeyboardUtil.showKeyboardInDialog(this.dialog, it)
}
binding?.inputSend?.setOnClickListener {
SingleToastUtil.showToast("SEND")
binding?.inputEdit?.setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
send()
return@setOnKeyListener true
}
false
}
binding?.inputSend?.setOnClickListener {
send()
}
}
private fun send() {
val text = binding?.inputEdit?.text?.toString()?.trim()
onSend?.invoke(this, text ?: "")
}
private fun initObserver() {
@@ -71,4 +87,9 @@ class GameMessageInputDialog :
this.setCanceledOnTouchOutside(true)
}
}
override fun onDestroy() {
super.onDestroy()
onSend = null
}
}

View File

@@ -1,13 +1,17 @@
package com.chwl.app.game.ui.game.widgets.bottom
import android.content.Context
import android.text.TextUtils
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.databinding.DataBindingUtil
import com.chwl.app.R
import com.chwl.app.databinding.GameBottomWidgetBinding
import com.chwl.app.game.core.GameMessageAbility
import com.chwl.app.game.ui.game.input.GameMessageInputDialog
import com.chwl.core.support.room.FrameLayoutRoomWidget
import com.chwl.library.utils.ResUtil
import com.chwl.library.utils.SingleToastUtil
class GameBottomWidget : FrameLayoutRoomWidget {
@@ -36,8 +40,35 @@ class GameBottomWidget : FrameLayoutRoomWidget {
init {
binding.tvInput.setOnClickListener {
roomView?.let {
GameMessageInputDialog().show(it.getViewFragmentManager(), "MESSAGE_INPUT")
roomContext?.let { context ->
GameMessageInputDialog { dialog, text ->
sendMessage(dialog, text)
}.show(
it.getViewFragmentManager(),
"MESSAGE_INPUT"
)
}
}
}
}
private fun sendMessage(dialog: GameMessageInputDialog, message: String) {
if (TextUtils.isEmpty(message)) {
SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_08))
return
}
val messageAbility =
roomContext?.findAbility<GameMessageAbility>(GameMessageAbility::class.java.simpleName)
if (messageAbility == null) {
dialog.dismissAllowingStateLoss()
SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_015))
return
}
addDisposable(messageAbility.sendTextMessage(message).subscribe({
dialog.dismissAllowingStateLoss()
}, {
dialog.dismissAllowingStateLoss()
SingleToastUtil.showToast(it.message)
}))
}
}

View File

@@ -1,13 +1,54 @@
package com.chwl.app.game.ui.game.widgets.message
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.chwl.app.R
import com.chwl.app.common.widget.CustomImageSpan
import com.chwl.app.ui.utils.ImageLoadUtils
import com.chwl.app.ui.widget.TextSpannableBuilder
import com.chwl.core.auth.AuthModel
import com.chwl.core.level.UserLevelResourceType
import com.chwl.core.manager.AvRoomDataManager
import com.chwl.core.noble.NobleUtil
import com.chwl.core.user.bean.UserInfo
import com.chwl.library.common.util.Utils
import com.chwl.library.utils.ResUtil
import com.chwl.library.utils.SizeUtils
import com.example.lib_utils.AppUtils
import com.example.lib_utils.UiUtils.isRtl
import com.example.lib_utils.ktx.getColorById
import com.netease.nim.uikit.business.session.emoji.MoonUtil
import com.netease.nim.uikit.common.util.sys.ScreenUtil
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum
class GameMessageAdapter(val dataList: MutableList<Any>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>(), View.OnClickListener {
private val itemPaddingHorizontal = Utils.dip2px(AppUtils.getApp(), 11f)
private val itemPaddingVertical = Utils.dip2px(AppUtils.getApp(), 6f)
private val expLevelHeight = Utils.dip2px(AppUtils.getApp(), 18f)
private val badgeWidth = Utils.dip2px(AppUtils.getApp(), 15f)
private val badgeHeight = Utils.dip2px(AppUtils.getApp(), 15f)
private val greyColor = ContextCompat.getColor(AppUtils.getApp(), R.color.white_transparent_50)
private val imageSpanFactory = object : Function1<Drawable, ImageSpan> {
override fun invoke(p1: Drawable): ImageSpan {
return CustomImageSpan(p1)
}
}
class GameMessageAdapter<T>(val dataList: MutableList<T>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameMessageNormalViewHolder {
return GameMessageNormalViewHolder(
LayoutInflater.from(parent.context)
@@ -16,10 +57,151 @@ class GameMessageAdapter<T>(val dataList: MutableList<T>) :
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val message = getItem(position)
val item = getItem(position)
val viewHolder = holder as GameMessageNormalViewHolder
viewHolder.textView.let {
it.setLineSpacing(0f, 1f)
it.setTextColor(Color.WHITE)
it.textSize = 12f
it.setOnClickListener(this)
it.setOnLongClickListener(null)
it.tag = item
it.gravity = Gravity.START or Gravity.CENTER_VERTICAL
if (isRtl(it.context)) {
it.textDirection = View.TEXT_DIRECTION_RTL
}
resetItemBackground(it)
}
if (item is ChatRoomMessage) {
if (item.msgType == MsgTypeEnum.text) {
convertText(viewHolder, item)
}
}
}
fun getItem(position: Int): T? {
private fun convertText(holder: GameMessageNormalViewHolder, message: ChatRoomMessage) {
val textView = holder.textView
val text = TextSpannableBuilder(textView)
addUserTag(message, text, textView)
val nickName =
if (message.fromAccount != null && message.fromAccount == AuthModel.get().currentUid.toString() + "") {
ResUtil.getString(R.string.avroom_widget_messageview_0116)
} else {
NobleUtil.getNamePlate(UserInfo.NICK, message)
}
text.append(nickName, ForegroundColorSpan(greyColor))
text.append(
": " + message.content,
ForegroundColorSpan(textView.context.getColorById(R.color.white))
)
MoonUtil.replaceEmoticons(
textView.context,
text.builder.toString(),
text.builder,
imageSpanFactory
)
textView.text = text.build()
loadItemBackgroundVip(message, textView)
}
private fun addUserTag(
chatRoomMessage: ChatRoomMessage,
builder: TextSpannableBuilder,
textView: TextView
) {
val extension = chatRoomMessage.chatRoomMessageExtension
val userLevel = NobleUtil.getLevel(UserLevelResourceType.EXPER_URL, chatRoomMessage)
val isOfficial = NobleUtil.getIsOfficial(UserInfo.IS_OFFICIAL, chatRoomMessage)
val vipIcon = NobleUtil.getResource(UserInfo.VIP_ICON, chatRoomMessage)
builder.append(vipIcon, expLevelHeight)
.append(
if (isOfficial) ResourcesCompat.getDrawable(
textView.resources,
R.mipmap.ic_user_official_13dp, null
) else null,
badgeWidth, badgeHeight
)
.append(getNewUserDrawable(textView.context, chatRoomMessage), badgeWidth, badgeHeight)
.append(
if (AvRoomDataManager.get()
.isSuperAdmin(chatRoomMessage.fromAccount)
) ResourcesCompat.getDrawable(
textView.resources,
R.drawable.ic_room_super_admin, null
) else null,
SizeUtils.dp2px(textView.context, 23f), expLevelHeight
)
// 官方主播認證
val tvOfficialMask =
NobleUtil.getLevel(UserInfo.OAC_NAME, chatRoomMessage).trim { it <= ' ' }
val ivOfficialMask = NobleUtil.getLevel(UserInfo.OAC_ICON, chatRoomMessage)
if (!TextUtils.isEmpty(tvOfficialMask) && !TextUtils.isEmpty(ivOfficialMask) && extension != null) { // extension != null 表示自己
builder.appendBgAndContent(ivOfficialMask, tvOfficialMask)
} else if (!TextUtils.isEmpty(ivOfficialMask)) {
builder.append(ivOfficialMask, SizeUtils.dp2px(textView.context, 62f), expLevelHeight)
}
//等級
builder.append(userLevel, expLevelHeight)
//銘牌
val tvNamePlate =
NobleUtil.getNamePlate(UserInfo.NAMEPLATE_WORD, chatRoomMessage).trim { it <= ' ' }
val ivNamePlate = NobleUtil.getNamePlate(UserInfo.NAMEPLATE_PIC, chatRoomMessage)
if (!TextUtils.isEmpty(tvNamePlate) && !TextUtils.isEmpty(ivNamePlate)) { // extension != null 表示自己
builder.appendBgAndContent(ivNamePlate, tvNamePlate)
} else if (!TextUtils.isEmpty(ivNamePlate)) {
builder.append(ivNamePlate, expLevelHeight)
}
}
private fun getNewUserDrawable(context: Context, chatRoomMessage: ChatRoomMessage): Drawable? {
val newUser = NobleUtil.getIsNewUser(UserInfo.IS_NEW_USER, chatRoomMessage)
val isHelloUser =
NobleUtil.getIsNewUser(UserInfo.IS_FROM_SAY_HELLO_CHANNEL, chatRoomMessage)
return if (newUser) {
ResourcesCompat.getDrawable(
context.resources,
if (isHelloUser) R.drawable.ic_new_user_hello else R.drawable.ic_new_user,
null
)
} else null
}
private fun resetItemBackground(textView: TextView) {
textView.text = ""
textView.setBackgroundResource(R.drawable.shape_room_message_bg)
textView.setPadding(
itemPaddingHorizontal,
itemPaddingVertical,
itemPaddingHorizontal,
itemPaddingVertical
)
}
private fun loadItemBackgroundVip(chatRoomMessage: ChatRoomMessage?, view: View) {
val androidBubbleUrl = NobleUtil.getResource(UserInfo.BUBBLE_URL_ANDROID, chatRoomMessage)
if (TextUtils.isEmpty(androidBubbleUrl)) return
view.setPadding(
itemPaddingHorizontal,
ScreenUtil.dip2px(10f),
itemPaddingHorizontal,
ScreenUtil.dip2px(10f)
)
ImageLoadUtils.loadNinePatchBg(view, androidBubbleUrl)
}
fun setDataList(list: List<Any>) {
dataList.clear()
dataList.addAll(list)
notifyDataSetChanged()
}
fun addData(item: Any) {
dataList.add(item)
notifyItemInserted(dataList.size)
}
fun getItem(position: Int): Any? {
return dataList.get(position)
}
@@ -27,8 +209,7 @@ class GameMessageAdapter<T>(val dataList: MutableList<T>) :
return dataList.size
}
protected open fun convert(holder: GameMessageNormalViewHolder, item: T){
override fun onClick(v: View) {
}
}

View File

@@ -7,10 +7,6 @@ import com.chwl.app.R
class GameMessageNormalViewHolder(val itemView: View) : RecyclerView.ViewHolder(itemView) {
var textView: TextView? = null
init {
textView = itemView.findViewById(R.id.tv_content)
}
var textView: TextView = itemView.findViewById(R.id.tv_content)
}

View File

@@ -6,16 +6,19 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chwl.app.R
import com.chwl.app.game.core.GameMessageAbility
import com.chwl.app.ui.widget.DividerItemDecoration
import com.chwl.app.ui.widget.MyItemAnimator
import com.chwl.app.ui.widget.RecyclerViewNoViewpagerScroll
import com.chwl.core.support.room.FrameLayoutRoomWidget
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import com.chwl.core.support.room.RoomContext
import com.chwl.core.support.room.RoomView
class GameMessageWidget : FrameLayoutRoomWidget {
class GameMessageWidget : FrameLayoutRoomWidget, GameMessageAbility.Listener {
private val recyclerView = RecyclerViewNoViewpagerScroll(context)
private val adapter = GameMessageAdapter<ChatRoomMessage>(ArrayList())
private val adapter = GameMessageAdapter(ArrayList())
private var isAtBottom = true
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
@@ -34,6 +37,7 @@ class GameMessageWidget : FrameLayoutRoomWidget {
init {
initListView()
initEvent()
}
private fun initListView() {
@@ -63,4 +67,55 @@ class GameMessageWidget : FrameLayoutRoomWidget {
}
recyclerView.adapter = adapter
}
private fun initEvent() {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
val lastPosition = layoutManager.findLastVisibleItemPosition()
if (lastPosition == RecyclerView.NO_POSITION) {
isAtBottom = true
} else isAtBottom = lastPosition == adapter.itemCount - 1
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy < 0) {
isAtBottom = false
}
}
})
}
override fun onInitialize(roomView: RoomView, roomContext: RoomContext) {
super.onInitialize(roomView, roomContext)
val messageAbility =
roomContext.findAbility<GameMessageAbility>(GameMessageAbility::class.java.simpleName)
messageAbility?.getMessageList()?.let {
adapter.setDataList(it)
}
messageAbility?.addListener(this)
}
override fun onAddMessage(message: Any) {
adapter.addData(message)
tryScrollToBottom()
}
override fun onReplaceMessageList(list: List<Any>) {
adapter.setDataList(list)
tryScrollToBottom()
}
private fun tryScrollToBottom() {
logD("tryScrollToBottom isAtBottom:$isAtBottom")
if (isAtBottom) {
if (adapter.itemCount > 0) {
recyclerView.smoothScrollToPosition(adapter.itemCount - 1)
}
}
}
}

View File

@@ -103,10 +103,13 @@
<com.chwl.app.game.ui.game.widgets.message.GameMessageWidget
android:id="@+id/message_widget"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="@dimen/dp_100"
app:layout_constraintBottom_toTopOf="@id/bottom_widget"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.277"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_percent="0.75" />
<com.chwl.app.game.ui.game.widgets.bottom.GameBottomWidget
android:id="@+id/bottom_widget"

View File

@@ -15,6 +15,8 @@
android:layout_weight="1"
android:background="@android:color/white"
android:hint="@string/room_say_here"
android:imeOptions="actionSend"
android:inputType="text"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="0dp"

View File

@@ -47,16 +47,20 @@ open class ChatRoomClient(val sessionId: String) : ICleared, ILog {
.observeOn(AndroidSchedulers.mainThread())
val stateFlow = MutableStateFlow<StatusCode>(StatusCode.INVALID)
var messageFilter: ChatRoomMessageFilter? = null
private val receiveMessageObserver = Observer<List<ChatRoomMessage>> {
logD("receiveMessageObserver size:${it.size}")
val list = it.filter { item ->
item.sessionId == sessionId && !ChatRoomClientManager.publicChatRoomReceiveMessageFilter.filter(
item
)
item.sessionId == sessionId && (messageFilter?.filter(item) ?: true)
}
messagePublishSubject.onNext(list)
}
private val onlineStatusObserver = Observer<ChatRoomStatusChangeData> {
if (it.roomId != sessionId) {
return@Observer
}
if (it.status == StatusCode.LOGINED) {
isLogin = true
} else {

View File

@@ -13,7 +13,7 @@ object ChatRoomClientManager {
val publicChatRoomReceiveMessageFilter: ChatRoomMessageFilter = object : ChatRoomMessageFilter {
override fun filter(message: ChatRoomMessage): Boolean {
if (message.msgType == MsgTypeEnum.image || message.msgType == MsgTypeEnum.text) {
return false
return true
}
if (message.msgType == MsgTypeEnum.custom) {
val attachment: CustomAttachment =
@@ -22,19 +22,24 @@ object ChatRoomClientManager {
CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED -> {
when (attachment.second) {
CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED_SUB -> {
return false
return true
}
}
}
}
}
return true
return false
}
}
fun getPublicChatClient(): ChatRoomClient? {
val sessionId = InitialModel.get().publicChatSessionId
return getClient(sessionId)
if (sessionId.isNullOrEmpty()) {
return null
}
return getClient(sessionId).apply {
this.messageFilter = publicChatRoomReceiveMessageFilter
}
}
fun getClient(sessionId: String): ChatRoomClient {

View File

@@ -20,6 +20,7 @@ class PublicChatRoomViewModel : BaseViewModel() {
fun init(sessionId: String) {
val client = ChatRoomClientManager.getClient(sessionId)
client.messageFilter = ChatRoomClientManager.publicChatRoomReceiveMessageFilter
chatRoomClient = client
registerReceiveMessage(client)
}

View File

@@ -8,6 +8,7 @@ import androidx.lifecycle.Observer
import com.chwl.core.utils.extension.toast
import com.chwl.library.net.rxnet.exception.ExceptionHandle
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
@@ -110,6 +111,10 @@ abstract class FrameLayoutRoomWidget : FrameLayout, RoomWidget {
return disposable
}
protected fun addDisposable(disposable: Disposable) {
getCompositeDisposable().add(disposable)
}
protected fun safeLaunch(
onError: suspend(e: Throwable) -> Unit = {
if (it.message != "Job was cancelled") {