瀏覽代碼

房间顶层复用问题,内置一些错误码

DoggyZhang 21 小時之前
父節點
當前提交
64ef1bd1e5
共有 30 個文件被更改,包括 284 次插入340 次删除
  1. 0 45
      app/src/main/java/com/adealink/weparty/commonui/BaseActivity.kt
  2. 0 41
      app/src/main/java/com/adealink/weparty/commonui/tip/TipUtil.kt
  3. 7 0
      app/src/main/java/com/adealink/weparty/module/room/chat/data/Message.kt
  4. 8 0
      module/call/src/main/java/com/tencent/qcloud/tuikit/tuicallkit/TUICallKitImpl.kt
  5. 2 0
      module/call/src/main/java/com/tencent/qcloud/tuikit/tuicallkit/manager/feature/CallingBellFeature.kt
  6. 13 3
      module/profile/src/main/java/com/adealink/weparty/profile/comp/ProfileRoomStatusComp.kt
  7. 2 16
      module/room/src/main/java/com/adealink/weparty/room/chat/adapter/SendGiftMessageViewBinder.kt
  8. 0 6
      module/room/src/main/java/com/adealink/weparty/room/chatroom/ChatRoomFragment.kt
  9. 13 18
      module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/DispatchCenterRoomInfoFragment.kt
  10. 14 25
      module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/DispatchRoomBottomOperateFragment.kt
  11. 16 20
      module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/DispatchRoomEventViewModel.kt
  12. 44 1
      module/room/src/main/java/com/adealink/weparty/room/data/RoomError.kt
  13. 3 1
      module/room/src/main/java/com/adealink/weparty/room/gift/RoomGiftPanelDialog.kt
  14. 1 2
      module/room/src/main/java/com/adealink/weparty/room/interceptor/EnterRoomUriInterceptor.kt
  15. 34 38
      module/room/src/main/java/com/adealink/weparty/room/micseat/BaseSeatsTemplate.kt
  16. 10 16
      module/room/src/main/java/com/adealink/weparty/room/micseat/MicSeatFragment.kt
  17. 1 1
      module/room/src/main/java/com/adealink/weparty/room/micseat/decor/IMicIndexDecorApi.kt
  18. 2 5
      module/room/src/main/java/com/adealink/weparty/room/micseat/decor/NameDecorView.kt
  19. 8 5
      module/room/src/main/java/com/adealink/weparty/room/micseat/defaults/BaseDefaultSeatView.kt
  20. 1 1
      module/room/src/main/java/com/adealink/weparty/room/minimize/view/MinimizedRoomFloatView.kt
  21. 4 4
      module/room/src/main/java/com/adealink/weparty/room/sdk/controller/ISeatController.kt
  22. 2 1
      module/room/src/main/java/com/adealink/weparty/room/sdk/controller/impl/JoinController.kt
  23. 58 81
      module/room/src/main/java/com/adealink/weparty/room/sdk/controller/impl/SeatController.kt
  24. 1 1
      module/room/src/main/java/com/adealink/weparty/room/setting/RoomSettingDialog.kt
  25. 4 4
      module/room/src/main/res/layout/dialog_room_invite_mic.xml
  26. 4 4
      module/room/src/main/res/layout/fragment_room_apply_mic_list.xml
  27. 2 1
      module/room/src/main/res/layout/layout_minimized_room_float_view.xml
  28. 10 0
      module/room/src/main/res/values-in/strings.xml
  29. 10 0
      module/room/src/main/res/values-zh/strings.xml
  30. 10 0
      module/room/src/main/res/values/strings.xml

+ 0 - 45
app/src/main/java/com/adealink/weparty/commonui/BaseActivity.kt

@@ -9,21 +9,16 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.activity.enableEdgeToEdge
 import androidx.annotation.ColorRes
-import androidx.annotation.DrawableRes
-import androidx.annotation.StringRes
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.view.WindowCompat
 import androidx.core.view.isNotEmpty
 import androidx.viewpager2.widget.ViewPager2
 import com.adealink.frame.aab.util.getCompatColor
-import com.adealink.frame.aab.util.getCompatDrawable
-import com.adealink.frame.aab.util.getCompatString
 import com.adealink.frame.aab.util.installSplitCompat
 import com.adealink.frame.apm.apmService
 import com.adealink.frame.locale.language.languageManager
 import com.adealink.frame.router.Router
 import com.adealink.frame.router.manager.deeplinkRouterManager
-import com.adealink.frame.util.isActivityInValid
 import com.adealink.frame.util.istNavigationBarGestureMode
 import com.adealink.frame.util.paddingBottomSystemWindowInsets
 import com.adealink.weparty.BuildConfig
@@ -33,14 +28,12 @@ import com.adealink.weparty.module.profile.ProfileModule
 import com.google.firebase.crashlytics.ktx.crashlytics
 import com.google.firebase.crashlytics.setCustomKeys
 import com.google.firebase.ktx.Firebase
-import com.qmuiteam.qmui.widget.dialog.QMUITipDialog
 import com.qmuiteam.qmui.widget.util.QMUIStatusBarHelper
 import me.jessyan.autosize.AutoSizeCompat
 
 open class BaseActivity : AppCompatActivity() {
 
     private var loadingDialog: LoadingDialog? = null
-    private var tipDialog: QMUITipDialog? = null
     private var istNavigationBarGestureMode = false
 
     protected open val isEdge2EdgeEnable = true
@@ -206,43 +199,6 @@ open class BaseActivity : AppCompatActivity() {
         loadingDialog?.dismiss()
     }
 
-    fun showTipDialog(
-        @DrawableRes drawableId: Int,
-        @StringRes tipWordId: Int,
-        duration: Long = 1500,
-    ) {
-        dismissTipDialog()
-        if (isActivityInValid(this)) {
-            return
-        }
-
-        tipDialog = QMUITipDialog.Builder(this)
-            .setIconType(QMUITipDialog.Builder.ICON_TYPE_CUSTOM)
-            .setCustomIconDrawable(getCompatDrawable(drawableId))
-            .setTipWord(getCompatString(tipWordId))
-            .setDismissDelayMillis(duration)
-            .create()
-        tipDialog?.show()
-    }
-
-    fun showTipDialog(tipWord: String, duration: Long = 1500) {
-        dismissTipDialog()
-        if (isActivityInValid(this)) {
-            return
-        }
-
-        tipDialog = QMUITipDialog.Builder(this)
-            .setIconType(QMUITipDialog.Builder.ICON_TYPE_NOTHING)
-            .setTipWord(tipWord)
-            .setDismissDelayMillis(duration)
-            .create()
-        tipDialog?.show()
-    }
-
-    private fun dismissTipDialog() {
-        tipDialog?.dismiss()
-    }
-
     fun isLoadingShowing(): Boolean {
         return loadingDialog?.isShowing() == true
     }
@@ -250,7 +206,6 @@ open class BaseActivity : AppCompatActivity() {
     override fun onDestroy() {
         super.onDestroy()
         dismissLoading()
-        dismissTipDialog()
     }
 
     override fun onSaveInstanceState(outState: Bundle) {

+ 0 - 41
app/src/main/java/com/adealink/weparty/commonui/tip/TipUtil.kt

@@ -1,41 +0,0 @@
-package com.adealink.weparty.commonui.tip
-
-import android.app.Activity
-import com.adealink.frame.aab.util.getCompatString
-import com.adealink.frame.base.Rlt
-import com.adealink.weparty.R
-import com.adealink.weparty.commonui.BaseActivity
-
-fun showFailedTip(activity: Activity?, rlt: Rlt<*>) {
-    val baseActivity = activity as? BaseActivity
-    if (rlt is Rlt.Failed) {
-        var tip = getCompatString(R.string.common_failed)
-        if (rlt.error.msg.isNotEmpty()) {
-            tip = rlt.error.msg
-        }
-        baseActivity?.showTipDialog(tip)
-    }
-}
-
-fun showCenterTip(activity: Activity?, tip: String, duration: Long = 1500) {
-    val baseActivity = activity as? BaseActivity
-    baseActivity?.showTipDialog(tip, duration)
-}
-
-fun showSuccessTip(activity: Activity?, rlt: Rlt<*>) {
-    val baseActivity = activity as? BaseActivity
-    if (rlt is Rlt.Success) {
-        baseActivity?.showTipDialog(R.drawable.commonui_success_white_tick_ic, R.string.common_success)
-    }
-}
-
-fun showTip(activity: Activity?, rlt: Rlt<*>) {
-    when (rlt) {
-        is Rlt.Success -> {
-            showSuccessTip(activity, rlt)
-        }
-        is Rlt.Failed -> {
-            showFailedTip(activity, rlt)
-        }
-    }
-}

+ 7 - 0
app/src/main/java/com/adealink/weparty/module/room/chat/data/Message.kt

@@ -64,6 +64,13 @@ sealed class Message(open val barrage: Barrage) : ILiveMessage, BaseListItemData
     override fun index(): Long {
         return index
     }
+
+    override fun areContentsTheSame(newItem: Any): Boolean {
+        return newItem is Message
+                && barrage.sequence == newItem.barrage.sequence
+                && barrage.timestampInSecond == newItem.barrage.timestampInSecond
+                && barrage.sender == newItem.barrage.sender
+    }
 }
 
 data class EnterRoomMessage(override val barrage: Barrage) : Message(barrage)

+ 8 - 0
module/call/src/main/java/com/tencent/qcloud/tuikit/tuicallkit/TUICallKitImpl.kt

@@ -17,6 +17,7 @@ import com.adealink.weparty.call.util.ScreenWakeupHelper
 import com.adealink.weparty.commonui.toast.util.showToast
 import com.adealink.weparty.module.call.Call
 import com.adealink.weparty.module.im.IM
+import com.adealink.weparty.module.room.RoomModule
 import com.tencent.cloud.tuikit.engine.call.TUICallDefine
 import com.tencent.cloud.tuikit.engine.call.TUICallEngine
 import com.tencent.cloud.tuikit.engine.call.TUICallObserver
@@ -70,6 +71,13 @@ class TUICallKitImpl private constructor(context: Context) : TUICallKit() {
                 return
             }
             Log.i(TAG_CALL_FLOW, "onCallReceived($mediaType), callId:$callId")
+
+            if (!RoomModule.getJoinedRoomId().isNullOrEmpty()) {
+                //用户在房,在线忙
+                CallStore.shared.reject(null)
+                return
+            }
+
             callId?.let {
                 KeyMetrics.countUV(KeyMetrics.EventId.RECEIVED, callId)
             }

+ 2 - 0
module/call/src/main/java/com/tencent/qcloud/tuikit/tuicallkit/manager/feature/CallingBellFeature.kt

@@ -11,6 +11,7 @@ import android.os.HandlerThread
 import android.text.TextUtils
 import androidx.core.content.ContextCompat
 import com.adealink.frame.log.Log
+import com.adealink.weparty.call.constant.TAG_CALL_KIT
 import com.adealink.weparty.call.util.PermissionRequest
 import com.tencent.cloud.tuikit.engine.call.TUICallEngine
 import com.tencent.liteav.audio.TXAudioEffectManager.AudioMusicParam
@@ -49,6 +50,7 @@ class CallingBellFeature(context: Context) {
     private fun registerObserver() {
         scope.launch {
             CallStore.shared.observerState.selfInfo.collect { selfInfo ->
+                Log.i(TAG_CALL_KIT, "CallingBellFeature id=${selfInfo.id} status=${selfInfo.status}")
                 if (selfInfo.status != CallParticipantStatus.Waiting) {
                     stopMusic()
                     return@collect

+ 13 - 3
module/profile/src/main/java/com/adealink/weparty/profile/comp/ProfileRoomStatusComp.kt

@@ -5,12 +5,13 @@ import android.view.View
 import android.view.ViewOutlineProvider
 import androidx.lifecycle.LifecycleOwner
 import com.adealink.frame.mvvm.viewmodel.viewModels
+import com.adealink.frame.router.Router
 import com.adealink.frame.util.onClick
 import com.adealink.weparty.commonui.BaseActivity
 import com.adealink.weparty.commonui.ext.dp
 import com.adealink.weparty.commonui.ext.gone
 import com.adealink.weparty.commonui.ext.show
-import com.adealink.weparty.module.room.RoomModule
+import com.adealink.weparty.module.room.Room
 import com.adealink.weparty.module.room.data.RoomInfo
 import com.adealink.weparty.module.room.data.SpeakingRippleConfig
 import com.adealink.weparty.profile.databinding.LayoutUserProfileHeaderBinding
@@ -27,13 +28,14 @@ class ProfileRoomStatusComp(
 
     private val roomViewModel by viewModels<ProfileRoomViewModel>()
 
+    private var roomInfo: RoomInfo? = null
+
     override fun initView() {
         initBlur()
         initRipple()
         binding.root.gone()
         binding.root.onClick {
-            val act = (activity as? BaseActivity) ?: return@onClick
-            RoomModule.createRoom(act)
+            goRoom()
         }
     }
 
@@ -79,6 +81,7 @@ class ProfileRoomStatusComp(
     }
 
     private fun updateRoomInfo(roomInfo: RoomInfo?) {
+        this.roomInfo = roomInfo
         if (roomInfo == null || roomInfo.roomId.isNullOrEmpty()) {
             binding.vRipple.stopRipple()
             binding.root.gone()
@@ -94,5 +97,12 @@ class ProfileRoomStatusComp(
         roomViewModel.getUserRoomStatus(userUid)
     }
 
+    private fun goRoom() {
+        val act = (activity as? BaseActivity) ?: return
+        val roomInfo = roomInfo ?: return
+        Router.build(act, Room.Room.PATH)
+            .putExtra(Room.Room.EXTRA_ENTER_ROOM_ID, roomInfo.roomId)
+            .start()
+    }
 
 }

+ 2 - 16
module/room/src/main/java/com/adealink/weparty/room/chat/adapter/SendGiftMessageViewBinder.kt

@@ -2,26 +2,20 @@ package com.adealink.weparty.room.chat.adapter
 
 import android.text.SpannableStringBuilder
 import android.text.method.LinkMovementMethod
-import android.text.style.ClickableSpan
-import android.text.style.ForegroundColorSpan
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
-import com.adealink.frame.aab.util.getCompatColor
 import com.adealink.frame.aab.util.getCompatString
 import com.adealink.frame.ext.findAndSetSpan
-import com.adealink.frame.router.Router
 import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
 import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
 import com.adealink.weparty.commonui.widget.ColorClickSpan
 import com.adealink.weparty.module.gift.GiftModule
 import com.adealink.weparty.module.room.chat.data.SendGiftMessage
-import com.adealink.weparty.module.webview.Web
 import com.adealink.weparty.room.R
 import com.adealink.weparty.room.chat.listener.IMessageOperaListener
 import com.adealink.weparty.room.databinding.ItemMessageSendGiftBinding
-import com.adealink.weparty.url.UrlConfig
 import com.adealink.weparty.util.formatNumberStr
 import com.adealink.weparty.R as APP_R
 
@@ -55,11 +49,7 @@ class SendGiftMessageViewBinder(
             binding.tvMsg.movementMethod = LinkMovementMethod.getInstance()
             binding.tvMsg.text = SpannableStringBuilder(text).apply {
                 findAndSetSpan(
-                    ForegroundColorSpan(getCompatColor(APP_R.color.color_FF35F3F0)),
-                    senderName
-                )
-                findAndSetSpan(
-                    object : ClickableSpan() {
+                    object : ColorClickSpan(APP_R.color.color_FF35F3F0) {
                         override fun onClick(widget: View) {
                             sendGiftContent?.sender?.let { uid ->
                                 listener.onAvatarClick(uid)
@@ -69,11 +59,7 @@ class SendGiftMessageViewBinder(
                     senderName
                 )
                 findAndSetSpan(
-                    ForegroundColorSpan(getCompatColor(APP_R.color.color_FF35F3F0)),
-                    receiverName
-                )
-                findAndSetSpan(
-                    object : ClickableSpan() {
+                    object : ColorClickSpan(APP_R.color.color_FF35F3F0) {
                         override fun onClick(widget: View) {
                             sendGiftContent?.receiver?.let { uid ->
                                 listener.onAvatarClick(uid)

+ 0 - 6
module/room/src/main/java/com/adealink/weparty/room/chatroom/ChatRoomFragment.kt

@@ -8,7 +8,6 @@ import com.adealink.frame.ext.isUIValid
 import com.adealink.frame.ext.isViewBindingValid
 import com.adealink.frame.log.Log
 import com.adealink.frame.mvvm.view.viewBinding
-import com.adealink.weparty.commonui.BaseFragment
 import com.adealink.weparty.commonui.widget.floatview.view.ITouchDispatchEventListener
 import com.adealink.weparty.module.room.listener.IMicSeatListener
 import com.adealink.weparty.module.room.listener.IMicSeatViewListener
@@ -37,8 +36,6 @@ class ChatRoomFragment : BaseRoomFragment(R.layout.fragment_chat_room),
     private val eventViewModel by viewModels<ChatRoomEventViewModel>()
 
     private var currFragment: BaseChatRoomPageFragment? = null
-    private val fragmentList = arrayListOf<BaseFragment>()
-
 
     override fun initViews() {
         super.initViews()
@@ -61,9 +58,6 @@ class ChatRoomFragment : BaseRoomFragment(R.layout.fragment_chat_room),
             return
         }
         currFragment?.handleNewIntent(intent)
-        fragmentList.forEach {
-            it.onNewIntent(intent)
-        }
     }
 
     override fun onRoomMinimize(minimize: (Boolean) -> Unit) {

+ 13 - 18
module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/DispatchCenterRoomInfoFragment.kt

@@ -1,8 +1,9 @@
 package com.adealink.weparty.room.chatroom.page.dispatchcenter
 
 import android.annotation.SuppressLint
+import android.content.Intent
+import androidx.lifecycle.lifecycleScope
 import com.adealink.frame.mvvm.view.viewBinding
-import com.adealink.frame.util.onClick
 import com.adealink.weparty.commonui.BaseFragment
 import com.adealink.weparty.commonui.ext.gone
 import com.adealink.weparty.commonui.ext.show
@@ -11,30 +12,29 @@ import com.adealink.weparty.room.databinding.FragmentDispatchCenterRoomInfoBindi
 import com.adealink.weparty.room.sdk.service.roomService
 import io.trtc.tuikit.atomicxcore.api.live.LiveInfo
 import io.trtc.tuikit.atomicxcore.api.live.LiveListStore
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 
 class DispatchCenterRoomInfoFragment : BaseFragment(R.layout.fragment_dispatch_center_room_info) {
 
     private val binding by viewBinding(FragmentDispatchCenterRoomInfoBinding::bind)
 
-    private var subscribeStateJob: Job? = null
-
     override fun initViews() {
         updateRoomInfo(roomService.joinController.joinedRoomInfo)
     }
 
+    override fun onNewIntent(intent: Intent?) {
+        super.onNewIntent(intent)
+        updateRoomInfo(roomService.joinController.joinedRoomInfo)
+    }
+
     override fun observeViewModel() {
         super.observeViewModel()
-        subscribeStateJob = CoroutineScope(Dispatchers.Main).launch {
-            LiveListStore.shared().liveState.currentLive.collect { liveInfo ->
-                if (liveInfo.liveID == roomService.joinController.getJoinedRoomId()) {
-                    updateRoomInfo(liveInfo)
-                }
+        LiveListStore.shared().liveState.currentLive.onEach { liveInfo ->
+            if (liveInfo.liveID == roomService.joinController.getJoinedRoomId()) {
+                updateRoomInfo(liveInfo)
             }
-        }
+        }.launchIn(lifecycleScope)
     }
 
     @SuppressLint("SetTextI18n")
@@ -49,9 +49,4 @@ class DispatchCenterRoomInfoFragment : BaseFragment(R.layout.fragment_dispatch_c
         }
     }
 
-    override fun onDestroyView() {
-        super.onDestroyView()
-        subscribeStateJob?.cancel()
-    }
-
 }

+ 14 - 25
module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/DispatchRoomBottomOperateFragment.kt

@@ -35,10 +35,10 @@ import com.adealink.weparty.room.micseat.dispatcenter.MIC_HOST
 import com.adealink.weparty.room.sdk.service.roomService
 import com.adealink.weparty.room.setting.RoomSettingDialog
 import io.trtc.tuikit.atomicxcore.api.device.DeviceStatus
-import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.flow.onEach
 
 open class DispatchRoomBottomOperateFragment : BaseFragment(R.layout.fragment_dispatch_room_bottom_operate),
     IRoomOperateItemListener {
@@ -129,7 +129,6 @@ open class DispatchRoomBottomOperateFragment : BaseFragment(R.layout.fragment_di
         updateOperateBoxBy()
     }
 
-    private var observeJob: Job? = null
     override fun observeViewModel() {
         super.observeViewModel()
         dispatchEventViewModel.applyMicNumberLD.observe(viewLifecycleOwner) {
@@ -138,27 +137,17 @@ open class DispatchRoomBottomOperateFragment : BaseFragment(R.layout.fragment_di
         onRecordChangedLD.observeWithoutCache(viewLifecycleOwner) {
             updateApplyMic()
         }
-        observeJob = lifecycleScope.launch {
-            launch {
-                roomService.seatController.micSeatsFlow.map {
-                    it.values.find { it.userInfo.userID == ProfileModule.getMyUid() } != null
-                }.distinctUntilChanged().collect { isOnMic ->
-                    showMicIcon(isOnMic)
-                    showRoomSettingIcon()
-                    updateApplyMic(isOnMic = isOnMic)
-                }
-            }
-            launch {
-                roomService.deviceController.microphoneStatusFlow.collect { status ->
-                    updateMicIcon(status == DeviceStatus.OFF)
-                }
-            }
-        }
-    }
+        roomService.seatController.micSeatsFlow.map {
+            it.values.find { it.userInfo.userID == ProfileModule.getMyUid() } != null
+        }.distinctUntilChanged().onEach { isOnMic ->
+            showMicIcon(isOnMic)
+            showRoomSettingIcon()
+            updateApplyMic(isOnMic = isOnMic)
+        }.launchIn(lifecycleScope)
 
-    override fun onDestroyView() {
-        super.onDestroyView()
-        observeJob?.cancel()
+        roomService.deviceController.microphoneStatusFlow.onEach { status ->
+            updateMicIcon(status == DeviceStatus.OFF)
+        }.launchIn(lifecycleScope)
     }
 
     private fun updateOperateBoxBy() {
@@ -168,7 +157,7 @@ open class DispatchRoomBottomOperateFragment : BaseFragment(R.layout.fragment_di
                 addItem(micOperateItem)
             }
             addItem(giftOperateItem)
-            if (roomService.joinController.isOwner() || roomService.seatController.getMicIndex() == MIC_HOST) {
+            if (roomService.joinController.isOwner() || roomService.seatController.getMyMicIndex() == MIC_HOST) {
                 addItem(settingOperateItem)
             }
         }
@@ -249,7 +238,7 @@ open class DispatchRoomBottomOperateFragment : BaseFragment(R.layout.fragment_di
         )
     }
 
-    fun showRoomSettingIcon(show: Boolean = roomService.joinController.isOwner() || roomService.seatController.getMicIndex() == MIC_HOST) {
+    fun showRoomSettingIcon(show: Boolean = roomService.joinController.isOwner() || roomService.seatController.getMyMicIndex() == MIC_HOST) {
         if (show) {
             binding.operateBox.addItem(settingOperateItem)
         } else {

+ 16 - 20
module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/DispatchRoomEventViewModel.kt

@@ -17,9 +17,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.update
-import kotlinx.coroutines.launch
 
 class DispatchRoomEventViewModel : BaseViewModel() {
 
@@ -34,28 +35,23 @@ class DispatchRoomEventViewModel : BaseViewModel() {
     val clearPlaymateMicLD = MutableLiveData<Unit>()
 
     init {
-        viewModelScope.launch {
-            launch {
-                LiveListStore.shared().liveState.currentLive.collect { liveInfo ->
-                    if (liveInfo.liveID == roomService.joinController.getJoinedRoomId()) {
-                        onLiveInfoChanged(liveInfo)
-                    }
-                }
+        LiveListStore.shared().liveState.currentLive.onEach { liveInfo ->
+            if (liveInfo.liveID == roomService.joinController.getJoinedRoomId()) {
+                onLiveInfoChanged(liveInfo)
             }
-            launch {
-                roomService.messageController.notificationsFlow.map { notifications ->
-                    notifications.mapNotNull {
-                        if (it.content is SendGiftNotificationContent) {
-                            it
-                        } else {
-                            null
-                        }
-                    }
-                }.distinctUntilChanged().collect { notifications ->
-                    notifyMicApplyClear(notifications)
+        }.launchIn(viewModelScope)
+
+        roomService.messageController.notificationsFlow.map { notifications ->
+            notifications.mapNotNull {
+                if (it.content is SendGiftNotificationContent) {
+                    it
+                } else {
+                    null
                 }
             }
-        }
+        }.distinctUntilChanged().onEach { notifications ->
+            notifyMicApplyClear(notifications)
+        }.launchIn(viewModelScope)
     }
 
     private fun onLiveInfoChanged(liveInfo: LiveInfo) {

+ 44 - 1
module/room/src/main/java/com/adealink/weparty/room/data/RoomError.kt

@@ -13,4 +13,47 @@ data class SeatAudioLockError(override val msg: String = getCompatString(R.strin
 data class ApplyMicOnlyHostError(
     override var serverCode: Int = APPLY_MIC_ONLY_HOST_ERROR,
     override val msg: String = getCompatString(R.string.room_request_host_mic_fail_for_no_host_permission)
-) : IError()
+) : IError()
+
+
+/**
+ * 腾讯 RTC Live错误码
+ * https://trtc.io/zh/document/60027?product=live&menulabel=core%20sdk&platform=ios#19824d9a-21d7-4656-9594-694e2eeb481a
+ */
+//const val TRTC_ROOM_ERROR_100001 = 100001 //服务器内部错误,请重试
+//const val TRTC_ROOM_ERROR_100002 = 100002 //参数非法,请根据错误描述检查请求是否正确
+//const val TRTC_ROOM_ERROR_100003 = 100003 //房间ID 已被使用,请选择别的房间ID
+const val TRTC_ROOM_ERROR_100004 = 100004 //房间不存在,或者曾经存在过,但是目前已经被解散。
+const val TRTC_ROOM_ERROR_100005 = 100005 //非房间成员
+const val TRTC_ROOM_ERROR_100006 = 100006 //操作权限不足
+
+//const val TRTC_ROOM_ERROR_100007 = 100007 //无付费信息,需在控制台购买套餐包(需要特殊上报)
+const val TRTC_ROOM_ERROR_100008 = 100008 //房间成员已满
+const val TRTC_ROOM_ERROR_100009 = 100009 //标签数量超上限
+
+//const val TRTC_ROOM_ERROR_100010 = 100010 //房间 ID 已被使用,并且操作者为房主,可以直接使用
+//const val TRTC_ROOM_ERROR_100011 = 100011 //房间 ID 已被 Chat 占用,可以换一个房间 ID 使用,或者先通过 Chat 接口解散该群
+//const val TRTC_ROOM_ERROR_100012 = 100012 //频率超过限制,例如创建房间频率超限,同一房间 ID, 1秒内只能创建一次
+//const val TRTC_ROOM_ERROR_100013 = 100013 //超过付费上限,例如麦位数,pk场次房间数量等超过付费限制
+//const val TRTC_ROOM_ERROR_100015 = 100015 //无效的房间类型
+const val TRTC_ROOM_ERROR_100016 = 100016 //该成员已经被封禁
+const val TRTC_ROOM_ERROR_100017 = 100017 //该成员已经被禁言
+const val TRTC_ROOM_ERROR_100018 = 100018 //当前房间需要密码才能进入
+const val TRTC_ROOM_ERROR_100019 = 100019 //进房密码错误
+const val TRTC_ROOM_ERROR_100020 = 100029 //管理员数量超过上限
+
+fun getError(code: Int, desc: String): IError {
+    return when (code) {
+        TRTC_ROOM_ERROR_100004 -> IError(msg = getCompatString(R.string.room_trtc_error_100004), serverCode = code)
+        TRTC_ROOM_ERROR_100005 -> IError(msg = getCompatString(R.string.room_trtc_error_100005), serverCode = code)
+        TRTC_ROOM_ERROR_100006 -> IError(msg = getCompatString(R.string.room_trtc_error_100006), serverCode = code)
+        TRTC_ROOM_ERROR_100008 -> IError(msg = getCompatString(R.string.room_trtc_error_100008), serverCode = code)
+        TRTC_ROOM_ERROR_100009 -> IError(msg = getCompatString(R.string.room_trtc_error_100009), serverCode = code)
+        TRTC_ROOM_ERROR_100016 -> IError(msg = getCompatString(R.string.room_trtc_error_100016), serverCode = code)
+        TRTC_ROOM_ERROR_100017 -> IError(msg = getCompatString(R.string.room_trtc_error_100017), serverCode = code)
+        TRTC_ROOM_ERROR_100018 -> IError(msg = getCompatString(R.string.room_trtc_error_100018), serverCode = code)
+        TRTC_ROOM_ERROR_100019 -> IError(msg = getCompatString(R.string.room_trtc_error_100019), serverCode = code)
+        TRTC_ROOM_ERROR_100020 -> IError(msg = getCompatString(R.string.room_trtc_error_100020), serverCode = code)
+        else -> IError(msg = desc, serverCode = code)
+    }
+}

+ 3 - 1
module/room/src/main/java/com/adealink/weparty/room/gift/RoomGiftPanelDialog.kt

@@ -256,6 +256,8 @@ class RoomGiftPanelDialog : BottomDialogFragment(R.layout.dialog_room_gift_panel
 
     private fun goDiamondExchangePage() {
         val act = activity ?: return
-        Router.build(act, Wallet.Wallet.PATH).start()
+        Router.build(act, Wallet.Recharge.PATH)
+            .putExtra(Wallet.Common.EXTRA_CURRENCY, Currency.DIAMOND.type)
+            .start()
     }
 }

+ 1 - 2
module/room/src/main/java/com/adealink/weparty/room/interceptor/EnterRoomUriInterceptor.kt

@@ -14,7 +14,6 @@ import com.adealink.frame.router.request.UriRequest
 import com.adealink.frame.util.AppUtil
 import com.adealink.frame.util.isActivityDestroy
 import com.adealink.weparty.App
-import com.adealink.weparty.commonui.tip.showFailedTip
 import com.adealink.weparty.commonui.toast.util.showToast
 import com.adealink.weparty.commonui.widget.ProgressDialog
 import com.adealink.weparty.media.MediaType
@@ -185,7 +184,7 @@ class EnterRoomUriInterceptor : UriInterceptor {
                     TAG_ROOM_ENTER_ROOM,
                     "EnterRoomUriInterceptor, join room fail(${result.error.serverCode}), abort()"
                 )
-                showFailedTip(activity, result)
+                showToast(result)
                 chain.abort()
             }
         }

+ 34 - 38
module/room/src/main/java/com/adealink/weparty/room/micseat/BaseSeatsTemplate.kt

@@ -19,7 +19,8 @@ import com.adealink.weparty.room.micseat.defaults.BaseDefaultSeatView
 import com.adealink.weparty.room.sdk.service.roomService
 import com.adealink.weparty.room.viewmodel.RoomViewModelFactory
 import io.trtc.tuikit.atomicxcore.api.live.SeatInfo
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 
 /**
  * 麦位模板要解决的问题?
@@ -95,50 +96,45 @@ abstract class BaseSeatsTemplate<SV : BaseDefaultSeatView, VM : BaseSeatsTemplat
     @CallSuper
     override fun observeViewModel() {
         //不要转成lambda, 注意kotlin SAM 优化,不注意就会踩坑!(https://www.jianshu.com/p/acba3986c4a2)
-        lifecycleScope.launch {
-            launch {
-                roomService.seatController.micSeatsFlow.collect {
-                    logRoomTime("BaseSeatsTemplate, micSeatsChange")
-                    //上麦列表
-                    val onMicMap = mutableMapOf<Int, SeatInfo>()
-                    val offMicList = mutableListOf<Int>()
-                    micSeatViews.onEach { seatViewEntry ->
-                        val micIndex = seatViewEntry.key
-                        val seatView = seatViewEntry.value
-                        val micSeatInfo = it[micIndex] ?: SeatInfo(micIndex, false)
+        roomService.seatController.micSeatsFlow.onEach {
+            logRoomTime("BaseSeatsTemplate, micSeatsChange")
+            //上麦列表
+            val onMicMap = mutableMapOf<Int, SeatInfo>()
+            val offMicList = mutableListOf<Int>()
+            micSeatViews.onEach { seatViewEntry ->
+                val micIndex = seatViewEntry.key
+                val seatView = seatViewEntry.value
+                val micSeatInfo = it[micIndex] ?: SeatInfo(micIndex, false)
 //                        if (micIndex == MicIndex.SUPER_MIC.index) {
 //                            openSuperMic(it.containsKey(micIndex), micSeatInfo?.isMicDeluxeOpen() ?: false)
 //                        }
-                        seatView.handleMicSeatInfo(
-                            micSeatInfo,
-                            { onMicInfo ->
-                                //有人上麦
-                                onMicMap[micIndex] = onMicInfo
-                            },
-                            {
-                                //下麦
-                                offMicList.add(micIndex)
-                            }
-                        )
+                seatView.handleMicSeatInfo(
+                    micSeatInfo,
+                    { onMicInfo ->
+                        //有人上麦
+                        onMicMap[micIndex] = onMicInfo
+                    },
+                    {
+                        //下麦
+                        offMicList.add(micIndex)
                     }
+                )
+            }
 
-                    if (onMicMap.isNotEmpty()) {
-                        onUserOnMic(onMicMap)
-                    }
-                    if (offMicList.isNotEmpty()) {
-                        onUserOffMic(offMicList)
-                    }
-                }
+            if (onMicMap.isNotEmpty()) {
+                onUserOnMic(onMicMap)
             }
-            launch {
-                roomService.seatController.speakingUsersFlow.collect { speakingMap ->
-                    micSeatViews.onEach { seatViewEntry ->
-                        val uid = seatViewEntry.value.micSeatInfo?.userInfo?.userID ?: return@collect
-                        seatViewEntry.value.showSpeaking(speakingMap[uid] ?: false)
-                    }
-                }
+            if (offMicList.isNotEmpty()) {
+                onUserOffMic(offMicList)
             }
-        }
+        }.launchIn(lifecycleScope)
+
+        roomService.seatController.speakingUsersFlow.onEach { speakingMap ->
+            micSeatViews.onEach { seatViewEntry ->
+                val uid = seatViewEntry.value.micSeatInfo?.userInfo?.userID ?: return@onEach
+                seatViewEntry.value.showSpeaking(speakingMap[uid] ?: false)
+            }
+        }.launchIn(lifecycleScope)
     }
 
     @CallSuper

+ 10 - 16
module/room/src/main/java/com/adealink/weparty/room/micseat/MicSeatFragment.kt

@@ -27,11 +27,6 @@ class MicSeatFragment : BaseFragment(R.layout.fragment_mic_seat) {
         switchMicSeatTemplate()
     }
 
-    override fun loadData() {
-        super.loadData()
-
-    }
-
     private fun switchMicSeatTemplate() {
         switchToDispatchCenter()
     }
@@ -66,20 +61,19 @@ class MicSeatFragment : BaseFragment(R.layout.fragment_mic_seat) {
     override fun onNewIntent(intent: Intent?) {
         super.onNewIntent(intent)
         val currentTemplate = currentSeatsTemplate
-        loadData()
         switchMicSeatTemplate()
-        if (currentTemplate == currentSeatsTemplate) {
-            //没有更换麦位模版,重置并重新加载当前麦位
-            reloadCurrentSeatsTemplate()
-        }
+//        if (currentTemplate == currentSeatsTemplate) {
+//            //没有更换麦位模版,重置并重新加载当前麦位
+//            reloadCurrentSeatsTemplate()
+//        }
     }
 
-    private fun reloadCurrentSeatsTemplate() {
-        if (currentSeatsTemplate?.isViewCreated() == true) {
-            currentSeatsTemplate?.resetAllMicSeatViews()
-            currentSeatsTemplate?.loadData()
-        }
-    }
+//    private fun reloadCurrentSeatsTemplate() {
+//        if (currentSeatsTemplate?.isViewCreated() == true) {
+//            currentSeatsTemplate?.resetAllMicSeatViews()
+//            currentSeatsTemplate?.loadData()
+//        }
+//    }
 
     companion object {
         private const val TAG = "MicSeatFragment"

+ 1 - 1
module/room/src/main/java/com/adealink/weparty/room/micseat/decor/IMicIndexDecorApi.kt

@@ -4,6 +4,6 @@ import com.adealink.weparty.module.room.data.MicIndex
 
 interface IMicIndexDecorApi : IDecorApi {
 
-    fun showMicIndex(micIndex: MicIndex?)
+    fun showMicIndex(micIndex: MicIndex)
 
 }

+ 2 - 5
module/room/src/main/java/com/adealink/weparty/room/micseat/decor/NameDecorView.kt

@@ -1,11 +1,8 @@
 package com.adealink.weparty.room.micseat.decor
 
 import android.content.Context
-import android.text.TextUtils
 import android.util.TypedValue
-import android.view.Gravity
 import android.view.ViewGroup
-import androidx.appcompat.widget.AppCompatTextView
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.widget.TextViewCompat
 import com.adealink.frame.aab.util.getCompatColor
@@ -75,10 +72,10 @@ class NameDecorView(
         }
     }
 
-    override fun showMicIndex(micIndex: MicIndex?) {
+    override fun showMicIndex(micIndex: MicIndex) {
         view {
             it.setNameColor(getCompatColor(APP_R.color.color_99FFFFFF))
-            it.setName(micIndex?.micName?.invoke())
+            it.setName(micIndex.micName.invoke())
         }
     }
 }

+ 8 - 5
module/room/src/main/java/com/adealink/weparty/room/micseat/defaults/BaseDefaultSeatView.kt

@@ -132,6 +132,7 @@ abstract class BaseDefaultSeatView @JvmOverloads constructor(
      */
     @CallSuper
     override fun onMemberOffMicSeat(oldSeatInfo: SeatInfo?, offSeatInfo: SeatInfo?) {
+        Log.d(TAG_ROOM_SEAT, "onMemberOffMicSeat(index:${micIndex.index})")
         //原来就是空麦位,就不刷新这个麦位状态了
 //        if (((oldSeatInfo == null || oldSeatInfo.isSeatEmpty()) && (offSeatInfo == null || offSeatInfo.isSeatEmpty()))) {
 //            //只更新基础麦位基础信息
@@ -152,9 +153,10 @@ abstract class BaseDefaultSeatView @JvmOverloads constructor(
     @CallSuper
     override fun resetMicSeat() {
         super.resetMicSeat()
+        Log.d(TAG_ROOM_SEAT, "resetMicSeat(index:${micIndex.index})")
         this.micSeatInfo = null
         showAvatarFrame(false)
-        showMicIndex(null)
+        showMicIndex(micIndex)
         showLock(false)
         showSpeaking(false)
     }
@@ -164,7 +166,8 @@ abstract class BaseDefaultSeatView @JvmOverloads constructor(
      */
     @CallSuper
     override fun onMemberOnMicSeat(oldSeatInfo: SeatInfo?, onSeatInfo: SeatInfo) {
-        showAvatar("")
+        Log.d(TAG_ROOM_SEAT, "onMemberOnMicSeat(index:${micIndex.index}), $onSeatInfo")
+        showAvatar(onSeatInfo.userInfo.avatarURL)
         showAvatarFrame(true)
         showMemberInfo(onSeatInfo)
     }
@@ -185,8 +188,8 @@ abstract class BaseDefaultSeatView @JvmOverloads constructor(
             if (this.micSeatInfo?.micUid() == uid) {
                 if (it == null) {
                     memberInfoGetFailed = true
-                    showAvatar("")
-                    showName("", "")
+                    showAvatar(seatInfo.userInfo.avatarURL)
+                    showName(seatInfo.userInfo.userName, seatInfo.userInfo.userID)
                 } else {
                     memberInfoGetFailed = false
                     showAvatar(it.avatar ?: "")
@@ -227,7 +230,7 @@ abstract class BaseDefaultSeatView @JvmOverloads constructor(
         }
     }
 
-    override fun showMicIndex(micIndex: MicIndex?) {
+    override fun showMicIndex(micIndex: MicIndex) {
         getDecorApi(IMicIndexDecorApi::class.java)?.onEach {
             it.showMicIndex(micIndex)
         }

+ 1 - 1
module/room/src/main/java/com/adealink/weparty/room/minimize/view/MinimizedRoomFloatView.kt

@@ -51,7 +51,7 @@ class MinimizedRoomFloatView(floatData: MinimizedRoomFloatData) : BaseDragFloatV
     }
 
     override fun getLayoutParamX(): Int {
-        return DisplayUtil.getScreenWidth() - getLayoutParamWidth() - 20.dp()
+        return DisplayUtil.getScreenWidth() - getLayoutParamWidth()
     }
 
     override fun getLayoutParamY(): Int {

+ 4 - 4
module/room/src/main/java/com/adealink/weparty/room/sdk/controller/ISeatController.kt

@@ -12,12 +12,14 @@ interface ISeatController<L : ISeatListener> : IController<L> {
 
     var selfMicSeatInfo: StateFlow<SeatInfo?>
 
-    val micSeatsFlow: StateFlow<MutableMap<Int, SeatInfo>>
+    val micSeatsFlow: StateFlow<Map<Int, SeatInfo>>
 
-    val speakingUsersFlow: StateFlow<MutableMap<String, Boolean>>
+    val speakingUsersFlow: StateFlow<Map<String, Boolean>>
 
     fun getMySeatInfo(): SeatInfo?
 
+    fun getMyMicIndex(): Int?
+
     fun handleMicSeatsInfo(
         roomId: String,
         micSeatsInfo: List<SeatInfo>,
@@ -26,8 +28,6 @@ interface ISeatController<L : ISeatListener> : IController<L> {
 
     fun isOnMic(uid: String): Boolean
 
-    fun getMicIndex(): Int?
-
     fun getMicSeatIndex(uid: String): Int?
 
     fun micOn(micInex: Int,onSuccess: (() -> Unit)? = null, onFail: ((error: IError) -> Unit)? = null)

+ 2 - 1
module/room/src/main/java/com/adealink/weparty/room/sdk/controller/impl/JoinController.kt

@@ -19,6 +19,7 @@ import com.adealink.weparty.room.constant.TAG_ROOM_ENTER_ROOM
 import com.adealink.weparty.room.constant.enterRoomJoinReqTime
 import com.adealink.weparty.room.constant.enterRoomJoinResTime
 import com.adealink.weparty.room.constant.logRoomTime
+import com.adealink.weparty.room.data.getError
 import com.adealink.weparty.room.datasource.local.RoomLocalService
 import com.adealink.weparty.room.sdk.context.IRoomContext
 import com.adealink.weparty.room.sdk.controller.BaseController
@@ -216,7 +217,7 @@ open class JoinController(override val ctx: IRoomContext, serialHandler: Handler
                     enterRoomJoinResTime = SystemClock.elapsedRealtime()
                     if (coroutine.isActive) {
                         coroutine.resume(
-                            Rlt.Failed(IError(msg = desc, serverCode = code, data = req.roomId))
+                            Rlt.Failed(getError(code, desc))
                         )
                     }
                 }

+ 58 - 81
module/room/src/main/java/com/adealink/weparty/room/sdk/controller/impl/SeatController.kt

@@ -25,8 +25,6 @@ import com.adealink.weparty.room.sdk.listener.IDeviceListener
 import com.adealink.weparty.room.sdk.listener.ISeatListener
 import com.adealink.weparty.room.sdk.service.roomService
 import io.trtc.tuikit.atomicxcore.api.CompletionHandler
-import io.trtc.tuikit.atomicxcore.api.device.DeviceStatus
-import io.trtc.tuikit.atomicxcore.api.device.DeviceStore
 import io.trtc.tuikit.atomicxcore.api.live.DeviceControlPolicy
 import io.trtc.tuikit.atomicxcore.api.live.LiveSeatStore
 import io.trtc.tuikit.atomicxcore.api.live.SeatInfo
@@ -35,6 +33,8 @@ import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 
@@ -49,21 +49,19 @@ class SeatController(override val ctx: IRoomContext, serialHandler: Handler) :
 
     private var liveSeatRoomId: String? = null
     private var liveSeatStore: LiveSeatStore? = null
-    private var liveSeatListJob: Job? = null
 
-    private val _micSeatsFlow = MutableStateFlow<MutableMap<Int, SeatInfo>>(hashMapOf())
-    override val micSeatsFlow: StateFlow<MutableMap<Int, SeatInfo>> = _micSeatsFlow.asStateFlow()
-    private var uid2MicSeat: MutableMap<String, SeatInfo> = hashMapOf() //<用户UID, 麦位>
+    private val _micSeatsFlow = MutableStateFlow<Map<Int, SeatInfo>>(emptyMap())
+    override val micSeatsFlow: StateFlow<Map<Int, SeatInfo>> = _micSeatsFlow.asStateFlow()
 
-    private val _speakingUsersFlow = MutableStateFlow<MutableMap<String, Boolean>>(hashMapOf())
-    override val speakingUsersFlow: StateFlow<MutableMap<String, Boolean>> = _speakingUsersFlow.asStateFlow()
+    private val _speakingUsersFlow = MutableStateFlow<Map<String, Boolean>>(hashMapOf())
+    override val speakingUsersFlow: StateFlow<Map<String, Boolean>> = _speakingUsersFlow.asStateFlow()
 
     override fun getMySeatInfo(): SeatInfo? {
-        return uid2MicSeat[ctx.appSupplier.selfUid]
+        return _micSeatsFlow.value.values.find { it.userInfo.userID == ctx.appSupplier.selfUid }
     }
 
-    override fun getMicIndex(): Int? {
-        return uid2MicSeat[ctx.appSupplier.selfUid]?.index
+    override fun getMyMicIndex(): Int? {
+        return _micSeatsFlow.value.values.find { it.userInfo.userID == ctx.appSupplier.selfUid }?.index
     }
 
     override fun onRoomIn(flowStateInfo: FlowStateInfo) {
@@ -78,8 +76,6 @@ class SeatController(override val ctx: IRoomContext, serialHandler: Handler) :
             TAG_ROOM_SEAT,
             "onRoomLeaved, ${flowStateInfo.roomId}, reason:${flowStateInfo.reason}"
         )
-        liveSeatListJob?.cancel()
-        uid2MicSeat.clear()
         _micSeatsFlow.update { hashMapOf() }
         _selfMicSeatInfo.update { null }
         _speakingUsersFlow.update { hashMapOf() }
@@ -89,27 +85,23 @@ class SeatController(override val ctx: IRoomContext, serialHandler: Handler) :
 
     private fun observeSeatList() {
         // 监听 seatList 变化,并更新您的麦位 UI
-        liveSeatListJob = launch {
-            launch {
-                liveSeatStore?.liveSeatState?.seatList?.collect { seatInfoList ->
-                    val roomId = liveSeatRoomId ?: return@collect
-                    Log.d(
-                        TAG_ROOM_SEAT,
-                        "Seat list updated(roomId:$roomId): ${
-                            seatInfoList.joinToString(separator = ",") {
-                                "(index:${it.index},uid:${it.userInfo.userID})"
-                            }
-                        }"
-                    )
-                    handleMicSeatsInfo(
-                        roomId,
-                        seatInfoList
-                    )
-                }
-            }
-            launch {
-                liveSeatStore?.liveSeatState?.speakingUsers?.collect { speakingUsers ->
-                    val roomId = liveSeatRoomId ?: return@collect
+        liveSeatStore?.liveSeatState?.seatList?.onEach { seatInfoList ->
+            val roomId = liveSeatRoomId ?: return@onEach
+            Log.d(
+                TAG_ROOM_SEAT,
+                "Seat list updated(roomId:$roomId): ${
+                    seatInfoList.joinToString(separator = ",") {
+                        "(index:${it.index},uid:${it.userInfo.userID})"
+                    }
+                }"
+            )
+            handleMicSeatsInfo(
+                roomId,
+                seatInfoList
+            )
+        }?.launchIn(this)
+        liveSeatStore?.liveSeatState?.speakingUsers?.onEach { speakingUsers ->
+            val roomId = liveSeatRoomId ?: return@onEach
 //                    Log.d(
 //                        TAG_ROOM_SEAT,
 //                        "Speaking updated(roomId:$roomId): ${
@@ -118,10 +110,8 @@ class SeatController(override val ctx: IRoomContext, serialHandler: Handler) :
 //                            }
 //                        }"
 //                    )
-                    handleMicSeatSpeaking(speakingUsers)
-                }
-            }
-        }
+            handleMicSeatSpeaking(speakingUsers)
+        }?.launchIn(this)
     }
 
     override fun observeMicSeatsInfo(scope: CoroutineScope, action: (roomId: String, micSeatsInfo: List<SeatInfo>) -> Unit): Job {
@@ -201,36 +191,23 @@ class SeatController(override val ctx: IRoomContext, serialHandler: Handler) :
             }
             _selfMicSeatInfo.update { newSelfMicSeatInfo }
             _micSeatsFlow.update { newMicSeats }
-            uid2MicSeat = newUidMicSeats
             if (newSelfMicSeatInfo != null) {
                 val remoteMute = !newSelfMicSeatInfo.userInfo.allowOpenMicrophone
-                val autoMuteMic = roomService.joinController.joinedRoomInfo?.isAutoMuteMic() ?: false
-                if (lastSelfMicSeatInfo == null || lastSelfMicSeatInfo.isSeatEmpty()) {
-                    Log.d(TAG_ROOM_SEAT, "SeatController, newSelfMicSeatInfo, remoteMute:$remoteMute, autoMuteMic:$autoMuteMic")
-                    //没在麦位
-                    if (remoteMute) {
-                        //房主or管理员关麦
-                        roomService.deviceController.closeLocalMicrophone()
-                    } else if (autoMuteMic) {
-                        //用户自己关麦
-                        roomService.deviceController.closeLocalMicrophone()
-                    } else {
-                        //麦位打开
-                        roomService.deviceController.openLocalMicrophone()
-                    }
+
+                // 提取出“是否应该被静音”的核心逻辑
+                val shouldMute = if (lastSelfMicSeatInfo == null || lastSelfMicSeatInfo.isSeatEmpty()) {
+                    roomService.joinController.joinedRoomInfo?.isAutoMuteMic() ?: false
                 } else {
-                    val userMute = roomService.deviceController.isLocalUserMute()
-                    Log.d(TAG_ROOM_SEAT, "SeatController, newSelfMicSeatInfo, remoteMute:$remoteMute, autoMuteMic:$autoMuteMic, userMute:$userMute")
-                    if (remoteMute) {
-                        //房主or管理员关麦
-                        roomService.deviceController.closeLocalMicrophone()
-                    } else if (userMute) {
-                        //用户自己关麦
-                        roomService.deviceController.closeLocalMicrophone()
-                    } else {
-                        //麦位打开
-                        roomService.deviceController.openLocalMicrophone()
-                    }
+                    roomService.deviceController.isLocalUserMute()
+                }
+
+                Log.d(TAG_ROOM_SEAT, "SeatController, remoteMute:$remoteMute, shouldMute:$shouldMute")
+
+                // 逻辑合并,极为清晰
+                if (remoteMute || shouldMute) {
+                    roomService.deviceController.closeLocalMicrophone()
+                } else {
+                    roomService.deviceController.openLocalMicrophone()
                 }
             }
 
@@ -251,11 +228,11 @@ class SeatController(override val ctx: IRoomContext, serialHandler: Handler) :
     }
 
     override fun isOnMic(uid: String): Boolean {
-        return uid2MicSeat.contains(uid)
+        return _micSeatsFlow.value.values.any { it.userInfo.userID == uid }
     }
 
     override fun getMicSeatIndex(uid: String): Int? {
-        return uid2MicSeat[uid]?.index
+        return _micSeatsFlow.value.values.find { it.userInfo.userID == uid }?.index
     }
 
     override fun micOn(micInex: Int, onSuccess: (() -> Unit)?, onFail: ((error: IError) -> Unit)?) {
@@ -350,20 +327,20 @@ class SeatController(override val ctx: IRoomContext, serialHandler: Handler) :
     }
 
     override suspend fun getMicSeatsInfo() {
-        val roomId = liveSeatRoomId ?: return
-        val seatInfoList = liveSeatStore?.liveSeatState?.seatList?.value ?: emptyList()
-        Log.d(
-            TAG_ROOM_SEAT,
-            "Seat list updated(roomId:$roomId): ${
-                seatInfoList.joinToString(separator = ",") {
-                    "(index:${it.index},uid:${it.userInfo.userID})"
-                }
-            }"
-        )
-        handleMicSeatsInfo(
-            roomId,
-            seatInfoList
-        )
+//        val roomId = liveSeatRoomId ?: return
+//        val seatInfoList = liveSeatStore?.liveSeatState?.seatList?.value ?: emptyList()
+//        Log.d(
+//            TAG_ROOM_SEAT,
+//            "Seat list updated(roomId:$roomId): ${
+//                seatInfoList.joinToString(separator = ",") {
+//                    "(index:${it.index},uid:${it.userInfo.userID})"
+//                }
+//            }"
+//        )
+//        handleMicSeatsInfo(
+//            roomId,
+//            seatInfoList
+//        )
     }
 
     /**

+ 1 - 1
module/room/src/main/java/com/adealink/weparty/room/setting/RoomSettingDialog.kt

@@ -22,7 +22,7 @@ class RoomSettingDialog : BottomDialogFragment(R.layout.dialog_room_setting) {
 
     override fun initViews() {
         super.initViews()
-        binding.btnSetting.show(roomService.joinController.isOwner() || roomService.seatController.getMicIndex() == MIC_HOST)
+        binding.btnSetting.show(roomService.joinController.isOwner() || roomService.seatController.getMyMicIndex() == MIC_HOST)
         binding.btnSetting.onClick {
             EditRoomDialog().show(childFragmentManager)
         }

+ 4 - 4
module/room/src/main/res/layout/dialog_room_invite_mic.xml

@@ -47,18 +47,18 @@
                 android:layout_height="match_parent"
                 android:gravity="start|center_vertical"
                 android:includeFontPadding="false"
-                android:maxWidth="120dp"
+                android:maxWidth="96dp"
                 android:singleLine="true"
                 android:text="@string/room_playmate_category_filter"
                 android:textColor="@color/white"
-                android:textSize="14sp"
+                android:textSize="12sp"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toTopOf="parent" />
 
             <androidx.appcompat.widget.AppCompatImageView
-                android:layout_width="13dp"
-                android:layout_height="13dp"
+                android:layout_width="12dp"
+                android:layout_height="12dp"
                 android:src="@drawable/common_go_white_ic"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintStart_toEndOf="@id/tv_filter"

+ 4 - 4
module/room/src/main/res/layout/fragment_room_apply_mic_list.xml

@@ -41,18 +41,18 @@
             android:layout_height="match_parent"
             android:gravity="start|center_vertical"
             android:includeFontPadding="false"
-            android:maxWidth="120dp"
+            android:maxWidth="96dp"
             android:singleLine="true"
             android:text="@string/room_playmate_category_filter"
             android:textColor="@color/white"
-            android:textSize="14sp"
+            android:textSize="12sp"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent" />
 
         <androidx.appcompat.widget.AppCompatImageView
-            android:layout_width="13dp"
-            android:layout_height="13dp"
+            android:layout_width="12dp"
+            android:layout_height="12dp"
             android:src="@drawable/common_go_white_ic"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toEndOf="@id/tv_filter"

+ 2 - 1
module/room/src/main/res/layout/layout_minimized_room_float_view.xml

@@ -13,6 +13,7 @@
         android:background="@drawable/room_mini_bg"
         android:padding="8dp"
         app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent">
 
         <com.adealink.weparty.commonui.imageview.AvatarView
@@ -32,7 +33,7 @@
         android:layout_height="23dp"
         android:padding="2dp"
         android:src="@drawable/common_clear_black_36_ic"
-        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toEndOf="@id/cl_bg"
         app:layout_constraintTop_toTopOf="parent" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 10 - 0
module/room/src/main/res/values-in/strings.xml

@@ -77,4 +77,14 @@
     <string name="room_send_gift_gift_no_select">Silakan pilih hadiah yang akan dikirim</string>
     <string name="room_send_gift_count_empty">Setidaknya ada satu hadiah untuk dikirim</string>
     <string name="room_send_gift_balance_not_enough">Berlian tidak cukup, ingin menambah?</string>
+    <string name="room_trtc_error_100004">Ruang tidak ada atau telah dibubarkan</string>
+    <string name="room_trtc_error_100005">Bukan anggota ruang</string>
+    <string name="room_trtc_error_100006">Izin ditolak</string>
+    <string name="room_trtc_error_100008">Ruang penuh</string>
+    <string name="room_trtc_error_100009">Batas tag terlampaui</string>
+    <string name="room_trtc_error_100016">Anggota ini telah diblokir</string>
+    <string name="room_trtc_error_100017">Anggota ini telah dibisukan</string>
+    <string name="room_trtc_error_100018">Kata sandi diperlukan untuk masuk</string>
+    <string name="room_trtc_error_100019">Kata sandi salah</string>
+    <string name="room_trtc_error_100020">Batas admin terlampaui</string>
 </resources>

+ 10 - 0
module/room/src/main/res/values-zh/strings.xml

@@ -77,4 +77,14 @@
     <string name="room_send_gift_gift_no_select">请选择要赠送的礼物</string>
     <string name="room_send_gift_count_empty">至少赠送一个礼物</string>
     <string name="room_send_gift_balance_not_enough">钻石不足,是否去充值?</string>
+    <string name="room_trtc_error_100004">房间不存在或已经被解散</string>
+    <string name="room_trtc_error_100005">非房间成员</string>
+    <string name="room_trtc_error_100006">操作权限不足</string>
+    <string name="room_trtc_error_100008">房间成员已满</string>
+    <string name="room_trtc_error_100009">标签数量超上限</string>
+    <string name="room_trtc_error_100016">该成员已经被封禁</string>
+    <string name="room_trtc_error_100017">该成员已经被禁言</string>
+    <string name="room_trtc_error_100018">当前房间需要密码才能进入</string>
+    <string name="room_trtc_error_100019">进房密码错误</string>
+    <string name="room_trtc_error_100020">管理员数量超过上限</string>
 </resources>

+ 10 - 0
module/room/src/main/res/values/strings.xml

@@ -78,4 +78,14 @@
     <string name="room_send_gift_gift_no_select">Please select the gift to send</string>
     <string name="room_send_gift_count_empty">At least one gift to send</string>
     <string name="room_send_gift_balance_not_enough"> Insufficient diamonds, wish to top up?</string>
+    <string name="room_trtc_error_100004">Room does not exist or is closed</string>
+    <string name="room_trtc_error_100005">Not a room member</string>
+    <string name="room_trtc_error_100006">Permission denied</string>
+    <string name="room_trtc_error_100008">Room is full</string>
+    <string name="room_trtc_error_100009">Tag limit exceeded</string>
+    <string name="room_trtc_error_100016">Member is banned</string>
+    <string name="room_trtc_error_100017">Member is muted</string>
+    <string name="room_trtc_error_100018">Password required to enter</string>
+    <string name="room_trtc_error_100019">Incorrect password</string>
+    <string name="room_trtc_error_100020">Admin limit exceeded</string>
 </resources>