feat:完善游戏房公屏展示与消息发送
This commit is contained in:
@@ -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 {
|
||||
|
@@ -388,9 +388,6 @@ public class PublicChatMessageView extends FrameLayout {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mMessageAdapter.getItemCount() > 0) {
|
||||
messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void release() {
|
||||
|
@@ -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 {
|
||||
|
@@ -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>)
|
||||
}
|
||||
}
|
@@ -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)
|
||||
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}))
|
||||
}
|
||||
}
|
@@ -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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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)
|
||||
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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"
|
||||
|
@@ -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"
|
||||
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
@@ -20,6 +20,7 @@ class PublicChatRoomViewModel : BaseViewModel() {
|
||||
|
||||
fun init(sessionId: String) {
|
||||
val client = ChatRoomClientManager.getClient(sessionId)
|
||||
client.messageFilter = ChatRoomClientManager.publicChatRoomReceiveMessageFilter
|
||||
chatRoomClient = client
|
||||
registerReceiveMessage(client)
|
||||
}
|
||||
|
@@ -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") {
|
||||
|
Reference in New Issue
Block a user