DoggyZhang hai 2 semanas
pai
achega
f19bbf485d
Modificáronse 31 ficheiros con 840 adicións e 103 borrados
  1. 0 6
      app/src/main/java/com/adealink/weparty/module/room/data/RoomAttrData.kt
  2. 1 1
      app/src/main/java/com/adealink/weparty/module/room/data/RoomData.kt
  3. 5 7
      app/src/main/java/com/adealink/weparty/module/room/data/RoomFlowData.kt
  4. 1 0
      app/src/main/res/values/strings.xml
  5. 10 1
      module/playmate/src/main/java/com/adealink/weparty/playmate/data/PlaymateData.kt
  6. 8 0
      module/playmate/src/main/java/com/adealink/weparty/playmate/datasource/remote/PlaymateHttpService.kt
  7. 43 2
      module/playmate/src/main/java/com/adealink/weparty/playmate/list/comp/PlaymateDispatchRoomComp.kt
  8. 70 0
      module/playmate/src/main/java/com/adealink/weparty/playmate/list/viewmodel/PlaymateRoomViewModel.kt
  9. 1 1
      module/profile/src/main/java/com/adealink/weparty/profile/search/adapter/SearchRoomItemViewBinder.kt
  10. 4 12
      module/profile/src/main/java/com/adealink/weparty/profile/search/data/SearchData.kt
  11. 1 0
      module/room/src/main/java/com/adealink/weparty/room/chat/viewmodel/ChatMessageViewModel.kt
  12. 2 0
      module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/seat/Constants.kt
  13. 24 0
      module/room/src/main/java/com/adealink/weparty/room/data/RoomData.kt
  14. 8 0
      module/room/src/main/java/com/adealink/weparty/room/datasource/remote/RoomHttpService.kt
  15. 112 11
      module/room/src/main/java/com/adealink/weparty/room/invite/InviteMicDialog.kt
  16. 46 0
      module/room/src/main/java/com/adealink/weparty/room/invite/adapter/RoomMemberViewBinder.kt
  17. 12 0
      module/room/src/main/java/com/adealink/weparty/room/invite/data/ApplyMicItemData.kt
  18. 114 0
      module/room/src/main/java/com/adealink/weparty/room/invite/viewmodel/InviteViewModel.kt
  19. 101 0
      module/room/src/main/java/com/adealink/weparty/room/member/RoomPlaymateFilterDialog.kt
  20. 28 0
      module/room/src/main/java/com/adealink/weparty/room/member/adapter/RoomPlaymateAllCategoryItemBinder.kt
  21. 26 0
      module/room/src/main/java/com/adealink/weparty/room/member/adapter/RoomPlaymateCategoryItemBinder.kt
  22. 11 1
      module/room/src/main/java/com/adealink/weparty/room/member/data/MemberData.kt
  23. 7 6
      module/room/src/main/java/com/adealink/weparty/room/member/viewmodel/RoomMemberViewModel.kt
  24. 19 0
      module/room/src/main/java/com/adealink/weparty/room/member/viewmodel/RoomPlaymateSkillViewModel.kt
  25. 12 9
      module/room/src/main/java/com/adealink/weparty/room/micseat/BaseSeatsTemplate.kt
  26. 10 10
      module/room/src/main/java/com/adealink/weparty/room/micseat/dispatcenter/DispatchCenterSeatsTemplate.kt
  27. 12 0
      module/room/src/main/java/com/adealink/weparty/room/micseat/dispatcenter/DispatchMicIndex.kt
  28. 0 5
      module/room/src/main/java/com/adealink/weparty/room/sdk/listener/IMemberListener.kt
  29. 3 2
      module/room/src/main/res/layout/dialog_room_apply_mic_host_playmate_page.xml
  30. 60 29
      module/room/src/main/res/layout/dialog_room_invite_mic.xml
  31. 89 0
      module/room/src/main/res/layout/layout_room_member_list_item.xml

+ 0 - 6
app/src/main/java/com/adealink/weparty/module/room/data/RoomAttrData.kt

@@ -1,10 +1,4 @@
 package com.adealink.weparty.module.room.data
 
-import com.adealink.weparty.commonui.recycleview.diffutil.BaseListItemData
-
-
-interface RoomData : BaseListItemData {
-
-}
 
 

+ 1 - 1
app/src/main/java/com/adealink/weparty/module/room/data/RoomData.kt

@@ -2,4 +2,4 @@ package com.adealink.weparty.module.room.data
 
 import com.adealink.frame.mvvm.livedata.ExtMutableLiveData
 
-val createRoomPermissionLD = ExtMutableLiveData<Boolean>()
+val createRoomPermissionLD = ExtMutableLiveData<Boolean>()

+ 5 - 7
app/src/main/java/com/adealink/weparty/module/room/data/RoomFlowData.kt

@@ -1,8 +1,8 @@
 package com.adealink.weparty.module.room.data
 
 import android.os.Parcelable
+import com.adealink.weparty.module.profile.data.UserInfo
 import com.google.gson.annotations.GsonNullable
-import com.google.gson.annotations.Must
 import com.google.gson.annotations.SerializedName
 import kotlinx.parcelize.Parcelize
 
@@ -22,14 +22,12 @@ data class MyRoomInfo(
 
 @Parcelize
 data class RoomInfo(
-    @Must
     @SerializedName("roomId") val roomId: String,
-) : Parcelable, RoomData {
+    @SerializedName("roomTitle") val roomTitle: String,
+    @SerializedName("roomCover") val roomCover: String,
+    @SerializedName("user") val owner: UserInfo,
+) : Parcelable {
 
-    override fun areItemsTheSame(newItem: Any): Boolean {
-        val newData = newItem as? RoomInfo ?: return false
-        return roomId == newData.roomId
-    }
 }
 
 infix fun RoomInfo.contentsTheSame(other: RoomInfo): Boolean =

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -7,6 +7,7 @@
     <string name="common_follow">Follow</string>
     <string name="common_unfollow">Following</string>
     <string name="common_invite">Invite</string>
+    <string name="common_invited">Invited</string>
     <string name="common_lock">Lock</string>
     <string name="common_un_lock">Unlock</string>
     <string name="common_mute">Mute</string>

+ 10 - 1
module/playmate/src/main/java/com/adealink/weparty/playmate/data/PlaymateData.kt

@@ -3,6 +3,7 @@ package com.adealink.weparty.playmate.data
 import com.adealink.weparty.module.playmate.data.SayWelcomeData
 import com.adealink.weparty.module.playmate.data.SkillSettingData
 import com.adealink.weparty.module.playmate.data.UserPlaymateCategoryData
+import com.adealink.weparty.module.room.data.RoomInfo
 import com.adealink.weparty.util.TimeHour
 import com.adealink.weparty.util.WeekDay
 import com.google.gson.annotations.GsonNullable
@@ -152,4 +153,12 @@ data class PlaymateUserPushQuotaRes(
     fun isQuotaAvailable(): Boolean {
         return userQuotaCount > 0 && playmateQuotaCount > 0
     }
-}
+}
+
+data class IsRoomAvailableRes(
+    @SerializedName("result") val available: Boolean,
+)
+
+data class AvailableRoomRes(
+    @SerializedName("room") val room: RoomInfo,
+)

+ 8 - 0
module/playmate/src/main/java/com/adealink/weparty/playmate/datasource/remote/PlaymateHttpService.kt

@@ -7,10 +7,12 @@ import com.adealink.weparty.module.playmate.data.PlaymateDetailData
 import com.adealink.weparty.playmate.comment.data.PlaymateCommentReq
 import com.adealink.weparty.playmate.comment.data.PlaymateCommentRes
 import com.adealink.weparty.playmate.data.AddWelcomeReq
+import com.adealink.weparty.playmate.data.AvailableRoomRes
 import com.adealink.weparty.playmate.data.BusinessTimeData
 import com.adealink.weparty.playmate.data.DeleteWelcomeReq
 import com.adealink.weparty.playmate.data.EnableAutoWelcomeReq
 import com.adealink.weparty.playmate.data.GetSkillSwitchReq
+import com.adealink.weparty.playmate.data.IsRoomAvailableRes
 import com.adealink.weparty.playmate.data.PlaymateCategoryConditionRes
 import com.adealink.weparty.playmate.data.PlaymateCategoryRes
 import com.adealink.weparty.playmate.data.PlaymateDetailReq
@@ -108,4 +110,10 @@ interface PlaymateHttpService {
     @POST("playmate/push/chat/quota")
     suspend fun getUserPushChatQuota(@Body req: PlaymateUserPushQuotaReq): Rlt<Res<PlaymateUserPushQuotaRes>>
 
+    @POST("live/room/alive")
+    suspend fun isRoomAvailable(): Rlt<Res<IsRoomAvailableRes>>
+
+    @POST("live/room/random")
+    suspend fun getAvailableRoom(): Rlt<Res<AvailableRoomRes>>
+
 }

+ 43 - 2
module/playmate/src/main/java/com/adealink/weparty/playmate/list/comp/PlaymateDispatchRoomComp.kt

@@ -1,18 +1,59 @@
 package com.adealink.weparty.playmate.list.comp
 
 import androidx.lifecycle.LifecycleOwner
+import com.adealink.frame.base.Rlt
+import com.adealink.frame.mvvm.viewmodel.activityViewModels
+import com.adealink.frame.router.Router
+import com.adealink.frame.util.onClick
 import com.adealink.weparty.commonui.BaseViewComponent
 import com.adealink.weparty.commonui.ext.show
+import com.adealink.weparty.commonui.toast.util.showToast
+import com.adealink.weparty.module.room.Room
 import com.adealink.weparty.playmate.databinding.LayoutPlaymateDispatchRoomBinding
+import com.adealink.weparty.playmate.list.viewmodel.PlaymateRoomViewModel
 
 class PlaymateDispatchRoomComp(
     lifecycleOwner: LifecycleOwner,
     val binding: LayoutPlaymateDispatchRoomBinding,
 ) : BaseViewComponent(lifecycleOwner) {
 
+    private val roomViewModel by activityViewModels<PlaymateRoomViewModel>()
+
     override fun initViews() {
         super.initViews()
-        // TODO: zhangfei
-        binding.root.show()
+        binding.root.onClick {
+            goRoom()
+        }
+    }
+
+    override fun observeViewModel() {
+        super.observeViewModel()
+        roomViewModel.roomAvailableLD.observe(viewLifecycleOwner) {
+            binding.root.show(it)
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        roomViewModel.checkRoomAvailable()
+    }
+
+    private fun goRoom() {
+        showLoading()
+        roomViewModel.getAvailableRoomId().observe(viewLifecycleOwner) { rlt ->
+            dismissLoading()
+            when (rlt) {
+                is Rlt.Failed -> {
+                    showToast(rlt)
+                }
+
+                is Rlt.Success -> {
+                    val act = activity ?: return@observe
+                    Router.build(act, Room.Room.PATH)
+                        .putExtra(Room.Room.EXTRA_ENTER_ROOM_ID, rlt.data.roomId)
+                        .start()
+                }
+            }
+        }
     }
 }

+ 70 - 0
module/playmate/src/main/java/com/adealink/weparty/playmate/list/viewmodel/PlaymateRoomViewModel.kt

@@ -0,0 +1,70 @@
+package com.adealink.weparty.playmate.list.viewmodel
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.adealink.frame.base.CommonDataNullError
+import com.adealink.frame.base.Rlt
+import com.adealink.frame.mvvm.livedata.OnceMutableLiveData
+import com.adealink.frame.mvvm.viewmodel.BaseViewModel
+import com.adealink.weparty.App
+import com.adealink.weparty.module.room.data.RoomInfo
+import com.adealink.weparty.playmate.datasource.remote.PlaymateHttpService
+import kotlinx.coroutines.launch
+
+class PlaymateRoomViewModel : BaseViewModel() {
+
+    private val playmateHttpService by lazy {
+        App.instance.networkService.getHttpService(PlaymateHttpService::class.java)
+    }
+
+
+    val roomAvailableLD = MutableLiveData<Boolean>()
+
+    private var lastCheckRoomAvailableTs = 0L
+    private var isChecking = false
+    fun checkRoomAvailable() {
+        viewModelScope.launch {
+            if (isChecking || System.currentTimeMillis() - lastCheckRoomAvailableTs < 60_000) {
+                return@launch
+            }
+            isChecking = true
+            val rlt = playmateHttpService.isRoomAvailable()
+            isChecking = false
+            lastCheckRoomAvailableTs = System.currentTimeMillis()
+            when (rlt) {
+                is Rlt.Failed -> {
+                    //Ntd.
+                }
+
+                is Rlt.Success -> {
+                    roomAvailableLD.send(rlt.data.data?.available ?: false)
+                }
+            }
+        }
+    }
+
+    fun getAvailableRoomId(): LiveData<Rlt<RoomInfo>> {
+        val liveData = OnceMutableLiveData<Rlt<RoomInfo>>()
+        viewModelScope.launch {
+            val rlt = playmateHttpService.getAvailableRoom()
+            when (rlt) {
+                is Rlt.Failed -> {
+                    liveData.send(rlt)
+                    return@launch
+                }
+
+                is Rlt.Success -> {
+                    val roomInfo = rlt.data.data?.room
+                    if (roomInfo == null) {
+                        liveData.send(Rlt.Failed(CommonDataNullError()))
+                        return@launch
+                    }
+                    liveData.send(Rlt.Success(roomInfo))
+                    return@launch
+                }
+            }
+        }
+        return liveData
+    }
+
+}

+ 1 - 1
module/profile/src/main/java/com/adealink/weparty/profile/search/adapter/SearchRoomItemViewBinder.kt

@@ -24,7 +24,7 @@ class SearchRoomItemViewBinder(val listener: OnRoomResultClickListener) :
         holder.binding.tvRoomId.text = "ID ${item.data.roomId}"
 
         holder.binding.tvRoomName.text = item.data.roomTitle
-        holder.binding.tvOwnerName.text = item.data.user.nickName
+        holder.binding.tvOwnerName.text = item.data.owner.nickName
     }
 
     override fun onCreateViewHolder(

+ 4 - 12
module/profile/src/main/java/com/adealink/weparty/profile/search/data/SearchData.kt

@@ -2,8 +2,7 @@ package com.adealink.weparty.profile.search.data
 
 import com.adealink.frame.network.data.PageReq
 import com.adealink.weparty.commonui.recycleview.diffutil.BaseListItemData
-import com.adealink.weparty.module.profile.data.UserInfo
-import com.adealink.weparty.profile.search.adapter.SearchRoomItemViewBinder
+import com.adealink.weparty.module.room.data.RoomInfo
 import com.google.gson.annotations.GsonNullable
 import com.google.gson.annotations.SerializedName
 
@@ -16,7 +15,7 @@ data class SearchAllRes(
     @GsonNullable
     @SerializedName("playmate") val playmate: List<SearchUserData>?,
     @GsonNullable
-    @SerializedName("rooms") val rooms: List<SearchRoomData>?,
+    @SerializedName("rooms") val rooms: List<RoomInfo>?,
 )
 
 
@@ -38,7 +37,7 @@ data class SearchRoomReq(
 )
 
 data class SearchRoomRes(
-    @SerializedName("list") val list: List<SearchRoomData>,
+    @SerializedName("list") val list: List<RoomInfo>,
     @GsonNullable
     @SerializedName("next") val next: String?
 )
@@ -85,7 +84,7 @@ data class SearchUserResultItemData(
 }
 
 data class SearchRoomResultItemData(
-    val data: SearchRoomData
+    val data: RoomInfo
 ) : BaseListItemData {
     override fun areContentsTheSame(newItem: Any): Boolean {
         val new = newItem as? SearchRoomResultItemData ?: return false
@@ -105,10 +104,3 @@ data class SearchHistoryItemData(
 }
 
 
-data class SearchRoomData(
-    @SerializedName("roomId") val roomId: String,
-    @SerializedName("roomTitle") val roomTitle: String,
-    @SerializedName("roomCover") val roomCover: String,
-    @SerializedName("user") val user: UserInfo,
-)
-

+ 1 - 0
module/room/src/main/java/com/adealink/weparty/room/chat/viewmodel/ChatMessageViewModel.kt

@@ -23,6 +23,7 @@ class ChatMessageViewModel : BaseViewModel(), IChatMessageViewModel, IMessageLis
             roomService.messageController.messagesFlow.collect {
                 onBarrageListChanged(it)
             }
+            roomService.messageController
         }
     }
 

+ 2 - 0
module/room/src/main/java/com/adealink/weparty/room/chatroom/page/dispatchcenter/seat/Constants.kt

@@ -0,0 +1,2 @@
+package com.adealink.weparty.room.chatroom.page.dispatchcenter.seat
+

+ 24 - 0
module/room/src/main/java/com/adealink/weparty/room/data/RoomData.kt

@@ -1,6 +1,7 @@
 package com.adealink.weparty.room.data
 
 import com.adealink.frame.network.data.PageReq
+import com.adealink.weparty.module.profile.data.UserInfo
 import com.adealink.weparty.room.applymic.data.ApplyMicData
 import com.google.gson.annotations.GsonNullable
 import com.google.gson.annotations.SerializedName
@@ -63,4 +64,27 @@ data class UpdateRoomInfoReq(
     @SerializedName("roomTitle") val roomTitle: String,
     @SerializedName("roomCover") val roomCover: String,
     @SerializedName("forbidAudio") val forbidAudio: Boolean,
+)
+
+data class InviteMicReq(
+    @SerializedName("roomId") val roomId: String,
+    @SerializedName("userId") val userId: String,
+    @SerializedName("micIndex") val micIndex: Int,
+)
+
+data class GetRoomMemberReq(
+    @SerializedName("roomId") val roomId: String,
+    @SerializedName("page") val page: PageReq,
+
+    //过滤陪玩师
+    @GsonNullable
+    @SerializedName("playmete") val filterPlaymate: Boolean? = null,
+    @GsonNullable
+    @SerializedName("skillCategories") val skillCategories: List<String>? = null,
+)
+
+data class GetRoomMemberRes(
+    @SerializedName("list") val list: List<UserInfo>,
+    @GsonNullable
+    @SerializedName("next") val next: String?,
 )

+ 8 - 0
module/room/src/main/java/com/adealink/weparty/room/datasource/remote/RoomHttpService.kt

@@ -10,6 +10,9 @@ import com.adealink.weparty.room.data.CheckCreateRoomPermissionRes
 import com.adealink.weparty.room.data.ClearApplyMicListReq
 import com.adealink.weparty.room.data.CreateRoomReq
 import com.adealink.weparty.room.data.CreateRoomRes
+import com.adealink.weparty.room.data.GetRoomMemberReq
+import com.adealink.weparty.room.data.GetRoomMemberRes
+import com.adealink.weparty.room.data.InviteMicReq
 import com.adealink.weparty.room.data.UpdateRoomInfoReq
 import retrofit2.http.Body
 import retrofit2.http.Core
@@ -43,4 +46,9 @@ interface RoomHttpService {
     @POST("live/room/update")
     suspend fun updateRoomInfo(@Body req: UpdateRoomInfoReq): Rlt<Res<Any>>
 
+    @POST("live/mic/invite/send")
+    suspend fun inviteOnMic(@Body req: InviteMicReq): Rlt<Res<Any>>
+
+    @POST("live/viewer/list")
+    suspend fun getRoomMembers(@Body req: GetRoomMemberReq): Rlt<Res<GetRoomMemberRes>>
 }

+ 112 - 11
module/room/src/main/java/com/adealink/weparty/room/invite/InviteMicDialog.kt

@@ -1,42 +1,143 @@
 package com.adealink.weparty.room.invite
 
+import androidx.fragment.app.viewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.adealink.frame.aab.util.getCompatColor
+import com.adealink.frame.base.Rlt
+import com.adealink.frame.base.fastLazy
 import com.adealink.frame.mvvm.view.viewBinding
+import com.adealink.frame.util.onClick
+import com.adealink.weparty.commonui.ext.gone
+import com.adealink.weparty.commonui.ext.show
+import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
+import com.adealink.weparty.commonui.toast.util.showFailedToast
 import com.adealink.weparty.commonui.widget.BottomDialogFragment
+import com.adealink.weparty.module.profile.data.UserPlaymateSkill
 import com.adealink.weparty.room.R
 import com.adealink.weparty.room.databinding.DialogRoomInviteMicBinding
+import com.adealink.weparty.room.invite.adapter.RoomMemberViewBinder
+import com.adealink.weparty.room.invite.data.RoomMemberItemData
+import com.adealink.weparty.room.invite.viewmodel.InviteViewModel
+import com.adealink.weparty.room.member.RoomPlaymateFilterDialog
 import com.scwang.smart.refresh.layout.api.RefreshLayout
 import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener
+import com.adealink.weparty.R as APP_R
 
 class InviteMicDialog : BottomDialogFragment(R.layout.dialog_room_invite_mic) {
 
     private val binding by viewBinding(DialogRoomInviteMicBinding::bind)
 
+    private val listAdapter by fastLazy { MultiTypeListAdapter<RoomMemberItemData>() }
+
+    private val inviteViewModel by viewModels<InviteViewModel>()
+    private var enableFilter = false
+
+    private var filterPlaymateCategory: List<String>? = null
+
+    private var inviteMicIndex: Int? = null
+    fun enableFilter(filter: Boolean) {
+        this.enableFilter = filter
+    }
+
+    fun inviteMicIndex(index: Int) {
+        this.inviteMicIndex = index
+    }
+
     override fun initViews() {
         super.initViews()
 
+        binding.btnFilter.show(enableFilter)
+        binding.btnFilter.onClick {
+            showFilter()
+        }
+
         binding.vRefresh.setEnableRefresh(true)
         binding.vRefresh.setEnableLoadMore(true)
         binding.vRefresh.setEnableAutoLoadMore(true)
         binding.vRefresh.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener {
             override fun onRefresh(refreshLayout: RefreshLayout) {
+                loadData()
+            }
 
+            override fun onLoadMore(refreshLayout: RefreshLayout) {
+                inviteViewModel.loadMore()
             }
+        })
 
+        listAdapter.register(RoomMemberViewBinder { item, position ->
+            invite(item, position)
+        })
+        binding.rvList.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
+        binding.rvList.adapter = listAdapter
 
-            override fun onLoadMore(refreshLayout: RefreshLayout) {
+        binding.vErrorView.setTitleColor(getCompatColor(APP_R.color.white))
+        binding.vErrorView.setSubTitleColor(getCompatColor(APP_R.color.white))
+    }
 
+    override fun observeViewModel() {
+        super.observeViewModel()
+        inviteViewModel.memberListRltLD.observe(viewLifecycleOwner) { rlt ->
+            binding.vRefresh.finishRefresh()
+            binding.vRefresh.finishLoadMore()
+            binding.vRefresh.setEnableLoadMore(inviteViewModel.hasMoreData())
+            showFailedToast(rlt)
+        }
+        inviteViewModel.memberListResultLD.observe(viewLifecycleOwner) {
+            if (it.isNullOrEmpty()) {
+                binding.rvList.gone()
+                binding.vErrorView.show(
+                    errorEmptyResId = APP_R.drawable.common_follow_list_empty_ic,
+                    title = APP_R.string.commonui_list_empty
+                )
+            } else {
+                listAdapter.submitList(it)
+                binding.rvList.show()
+                binding.vErrorView.gone()
             }
-        })
+        }
+    }
+
+    override fun loadData() {
+        super.loadData()
+        inviteViewModel.pullMemberList(filterPlaymateCategory)
+    }
+
+    private fun invite(item: RoomMemberItemData, position: Int) {
+        inviteViewModel.invite(item.data.uid, inviteMicIndex).observe(viewLifecycleOwner) { rlt ->
+            when (rlt) {
+                is Rlt.Failed -> {
+                    showFailedToast(rlt)
+                }
+
+                is Rlt.Success -> {
+                    item.invited = true
+                    listAdapter.notifyItemChanged(position)
+                }
+            }
+        }
+    }
+
+    private fun showFilter() {
+        RoomPlaymateFilterDialog().apply {
+            setListener(object : RoomPlaymateFilterDialog.OnCategorySelectListener {
+                override fun onSelect(skill: UserPlaymateSkill) {
+                    notifyMemberListRefresh(skill.id)
+                }
+
+                override fun onSelectAll() {
+                    notifyMemberListRefresh(null)
+                }
+            })
+            setCurrentSelect(filterPlaymateCategory?.firstOrNull())
+        }.show(childFragmentManager)
+    }
 
-//        listAdapter.register(VisitorItemViewBinder(this))
-//        binding.rvVisitor.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
-//        binding.rvVisitor.adapter = listAdapter
-//        binding.rvVisitor.addItemDecoration(
-//            VerticalSpaceItemDecoration(
-//                0,
-//                firstSpaceHeight = 6.dp()
-//            )
-//        )
+    private fun notifyMemberListRefresh(category: String?) {
+        this.filterPlaymateCategory = category?.let {
+            listOf(it)
+        }
+        binding.vRefresh.autoRefresh()
     }
 
 }

+ 46 - 0
module/room/src/main/java/com/adealink/weparty/room/invite/adapter/RoomMemberViewBinder.kt

@@ -0,0 +1,46 @@
+package com.adealink.weparty.room.invite.adapter
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.adealink.frame.aab.util.getCompatString
+import com.adealink.frame.util.onClick
+import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
+import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
+import com.adealink.weparty.room.databinding.LayoutRoomMemberListItemBinding
+import com.adealink.weparty.room.invite.data.RoomMemberItemData
+import com.adealink.weparty.R as APP_R
+
+class RoomMemberViewBinder(
+    val invite: (item: RoomMemberItemData, position: Int) -> Unit
+) : ItemViewBinder<RoomMemberItemData, BindingViewHolder<LayoutRoomMemberListItemBinding>>() {
+    override fun onCreateViewHolder(
+        inflater: LayoutInflater,
+        parent: ViewGroup
+    ): BindingViewHolder<LayoutRoomMemberListItemBinding> {
+        return BindingViewHolder(LayoutRoomMemberListItemBinding.inflate(inflater, parent, false))
+    }
+
+    @SuppressLint("SetTextI18n")
+    override fun onBindViewHolder(
+        holder: BindingViewHolder<LayoutRoomMemberListItemBinding>,
+        item: RoomMemberItemData
+    ) {
+        holder.binding.tvIndex.text = (holder.layoutPosition + 1).toString()
+        holder.binding.ivAvatar.setImageUrl(item.data.avatar)
+        holder.binding.tvName.text = item.data.nickName
+        holder.binding.vGender.setGender(item.data.gender)
+
+        if (item.invited) {
+            holder.binding.btnInvite.isEnabled = false
+            holder.binding.btnInvite.text = getCompatString(APP_R.string.common_invited)
+        } else {
+            holder.binding.btnInvite.isEnabled = true
+            holder.binding.btnInvite.text = getCompatString(APP_R.string.common_invite)
+            holder.binding.btnInvite.onClick {
+                invite.invoke(item, holder.layoutPosition)
+            }
+        }
+    }
+
+}

+ 12 - 0
module/room/src/main/java/com/adealink/weparty/room/invite/data/ApplyMicItemData.kt

@@ -0,0 +1,12 @@
+package com.adealink.weparty.room.invite.data
+
+import com.adealink.weparty.commonui.recycleview.diffutil.BaseListItemData
+import com.adealink.weparty.module.profile.data.UserInfo
+
+data class RoomMemberItemData(
+    val data: UserInfo
+) : BaseListItemData {
+
+    var invited: Boolean = false
+
+}

+ 114 - 0
module/room/src/main/java/com/adealink/weparty/room/invite/viewmodel/InviteViewModel.kt

@@ -0,0 +1,114 @@
+package com.adealink.weparty.room.invite.viewmodel
+
+import androidx.lifecycle.LiveData
+import com.adealink.frame.base.Rlt
+import com.adealink.frame.mvvm.livedata.ExtMutableLiveData
+import com.adealink.frame.mvvm.livedata.OnceMutableLiveData
+import com.adealink.frame.mvvm.viewmodel.BaseViewModel
+import com.adealink.frame.network.data.PageReq
+import com.adealink.weparty.App
+import com.adealink.weparty.module.room.data.MIC_ASSIGN_BY_REMOTE
+import com.adealink.weparty.network.data.NoMoreDataError
+import com.adealink.weparty.room.data.GetRoomMemberReq
+import com.adealink.weparty.room.data.InviteMicReq
+import com.adealink.weparty.room.datasource.remote.RoomHttpService
+import com.adealink.weparty.room.invite.data.RoomMemberItemData
+import com.adealink.weparty.room.sdk.service.roomService
+import com.adealink.weparty.util.PageHandler
+import kotlinx.coroutines.launch
+
+class InviteViewModel : BaseViewModel() {
+
+    private val roomHttpService by lazy {
+        App.instance.networkService.getHttpService(RoomHttpService::class.java)
+    }
+
+    fun invite(uid: String, micIndex: Int?): LiveData<Rlt<Any>> {
+        val liveData = OnceMutableLiveData<Rlt<Any>>()
+        viewModelScope.launch {
+            val roomId = roomId
+            if (roomId.isNullOrEmpty()) {
+                return@launch
+            }
+            liveData.send(
+                roomHttpService.inviteOnMic(
+                    InviteMicReq(
+                        roomId, uid, micIndex ?: MIC_ASSIGN_BY_REMOTE
+                    )
+                )
+            )
+        }
+        return liveData
+    }
+
+
+    private val memberListResultSet = mutableSetOf<String>()
+    val memberListResultLD = ExtMutableLiveData<List<RoomMemberItemData>>()
+    val memberListRltLD = ExtMutableLiveData<Rlt<Any>>()
+    private val memberList = mutableListOf<RoomMemberItemData>()
+    private val pageHandler = PageHandler()
+
+    private var roomId: String? = null
+    private var filterCategory: List<String>? = null
+
+    fun pullMemberList(
+        filterCategory: List<String>? = null
+    ) {
+        this.filterCategory = filterCategory
+        this.roomId = roomService.joinController.getJoinedRoomId()
+
+        pageHandler.reset()
+        memberListResultSet.clear()
+        memberList.clear()
+        loadMore()
+    }
+
+    fun hasMoreData(): Boolean {
+        return !pageHandler.isEnd
+    }
+
+    fun loadMore() {
+        if (pageHandler.isEnd) {
+            memberListRltLD.send(Rlt.Failed(NoMoreDataError()))
+            return
+        }
+        viewModelScope.launch {
+            val roomId = this@InviteViewModel.roomId
+            if (roomId.isNullOrEmpty()) {
+                memberListRltLD.send(Rlt.Failed(NoMoreDataError()))
+                return@launch
+            }
+            val rlt = roomHttpService.getRoomMembers(
+                GetRoomMemberReq(
+                    roomId = roomId,
+                    page = PageReq(size = pageHandler.pageSize, next = pageHandler.currentPage),
+
+                    filterPlaymate = !filterCategory.isNullOrEmpty(),
+                    skillCategories = filterCategory
+                )
+            )
+            when (rlt) {
+                is Rlt.Failed -> {
+                    memberListRltLD.send(rlt)
+                }
+
+                is Rlt.Success -> {
+                    pageHandler.nextPage(rlt.data.data?.next)
+
+                    val nextList = rlt.data.data?.list?.filter {
+                        !memberListResultSet.contains(it.uid)
+                    } ?: emptyList()
+
+                    val nextItemList = nextList.map {
+                        RoomMemberItemData(it)
+                    }
+                    memberListResultSet.addAll(nextList.map { it.uid })
+                    memberList.addAll(nextItemList)
+                    memberListRltLD.send(rlt)
+                    memberListResultLD.send(memberList)
+                }
+            }
+        }
+    }
+
+}

+ 101 - 0
module/room/src/main/java/com/adealink/weparty/room/member/RoomPlaymateFilterDialog.kt

@@ -0,0 +1,101 @@
+package com.adealink.weparty.room.member
+
+import androidx.fragment.app.activityViewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.adealink.frame.base.fastLazy
+import com.adealink.frame.mvvm.view.viewBinding
+import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
+import com.adealink.weparty.commonui.widget.BottomDialogFragment
+import com.adealink.weparty.module.profile.data.UserPlaymateSkill
+import com.adealink.weparty.room.R
+import com.adealink.weparty.room.databinding.DialogRoomPlaymateCategoryFilterBinding
+import com.adealink.weparty.room.member.adapter.RoomPlaymateAllCategoryItemBinder
+import com.adealink.weparty.room.member.adapter.RoomPlaymateCategoryItemBinder
+import com.adealink.weparty.room.member.data.BasePlaymateCategoryItem
+import com.adealink.weparty.room.member.data.PlaymateCategoryAllItemData
+import com.adealink.weparty.room.member.data.PlaymateCategoryItemData
+import com.adealink.weparty.room.member.viewmodel.RoomPlaymateSkillViewModel
+
+class RoomPlaymateFilterDialog : BottomDialogFragment(R.layout.dialog_room_playmate_category_filter) {
+
+    private val binding by viewBinding(DialogRoomPlaymateCategoryFilterBinding::bind)
+    private val categoryAdapter by fastLazy { MultiTypeListAdapter<BasePlaymateCategoryItem>() }
+
+    private val viewModel by activityViewModels<RoomPlaymateSkillViewModel>()
+
+    private var listener: OnCategorySelectListener? = null
+
+    private var currentSkillId: String? = null
+
+    fun setListener(listener: OnCategorySelectListener?) {
+        this.listener = listener
+    }
+
+    fun setCurrentSelect(skillId: String?) {
+        this.currentSkillId = skillId
+    }
+
+    override fun initViews() {
+        super.initViews()
+        categoryAdapter.register(
+            RoomPlaymateCategoryItemBinder {
+                select(it.skill)
+            }
+        )
+        categoryAdapter.register(
+            RoomPlaymateAllCategoryItemBinder {
+                selectAll()
+            }
+        )
+        binding.rvCategory.adapter = categoryAdapter
+        binding.rvCategory.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+    }
+
+    override fun observeViewModel() {
+        super.observeViewModel()
+        viewModel.skillListLD.observe(viewLifecycleOwner) { list ->
+            val itemList = mutableListOf<BasePlaymateCategoryItem>()
+            var hasSelected = false
+            itemList.addAll(
+                list.map { skill ->
+                    PlaymateCategoryItemData(
+                        skill
+                    ).also {
+                        hasSelected = it.skill.id == currentSkillId
+                        it.selected = hasSelected
+                    }
+                }
+            )
+            itemList.add(
+                PlaymateCategoryAllItemData.also {
+                    it.selected = !hasSelected && currentSkillId.isNullOrEmpty()
+                }
+            )
+            categoryAdapter.submitList(itemList)
+        }
+    }
+
+    override fun loadData() {
+        super.loadData()
+        viewModel.loadRoomPlaymateSkill()
+    }
+
+    private fun select(skill: UserPlaymateSkill) {
+        listener?.onSelect(skill)
+        dismiss()
+    }
+
+    private fun selectAll() {
+        listener?.onSelectAll()
+        dismiss()
+    }
+
+
+    interface OnCategorySelectListener {
+        fun onSelect(skill: UserPlaymateSkill)
+
+        fun onSelectAll()
+    }
+
+}

+ 28 - 0
module/room/src/main/java/com/adealink/weparty/room/member/adapter/RoomPlaymateAllCategoryItemBinder.kt

@@ -0,0 +1,28 @@
+package com.adealink.weparty.room.member.adapter
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.adealink.frame.aab.util.getCompatString
+import com.adealink.frame.util.onClick
+import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
+import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
+import com.adealink.weparty.room.databinding.LayoutRoomPlaymateCategoryFilterItemBinding
+import com.adealink.weparty.room.member.data.PlaymateCategoryAllItemData
+import com.adealink.weparty.R as APP_R
+
+class RoomPlaymateAllCategoryItemBinder(
+    private val onClick: () -> Unit
+) : ItemViewBinder<PlaymateCategoryAllItemData, BindingViewHolder<LayoutRoomPlaymateCategoryFilterItemBinding>>() {
+    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): BindingViewHolder<LayoutRoomPlaymateCategoryFilterItemBinding> {
+        return BindingViewHolder(
+            LayoutRoomPlaymateCategoryFilterItemBinding.inflate(inflater, parent, false)
+        )
+    }
+
+    override fun onBindViewHolder(holder: BindingViewHolder<LayoutRoomPlaymateCategoryFilterItemBinding>, item: PlaymateCategoryAllItemData) {
+        holder.binding.root.onClick {
+            onClick.invoke()
+        }
+        holder.binding.tvTitle.text = getCompatString(APP_R.string.common_all)
+    }
+}

+ 26 - 0
module/room/src/main/java/com/adealink/weparty/room/member/adapter/RoomPlaymateCategoryItemBinder.kt

@@ -0,0 +1,26 @@
+package com.adealink.weparty.room.member.adapter
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.adealink.frame.util.onClick
+import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
+import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
+import com.adealink.weparty.room.databinding.LayoutRoomPlaymateCategoryFilterItemBinding
+import com.adealink.weparty.room.member.data.PlaymateCategoryItemData
+
+class RoomPlaymateCategoryItemBinder(
+    private val onClick: (item: PlaymateCategoryItemData) -> Unit
+) : ItemViewBinder<PlaymateCategoryItemData, BindingViewHolder<LayoutRoomPlaymateCategoryFilterItemBinding>>() {
+    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): BindingViewHolder<LayoutRoomPlaymateCategoryFilterItemBinding> {
+        return BindingViewHolder(
+            LayoutRoomPlaymateCategoryFilterItemBinding.inflate(inflater, parent, false)
+        )
+    }
+
+    override fun onBindViewHolder(holder: BindingViewHolder<LayoutRoomPlaymateCategoryFilterItemBinding>, item: PlaymateCategoryItemData) {
+        holder.binding.root.onClick {
+            onClick.invoke(item)
+        }
+
+    }
+}

+ 11 - 1
module/room/src/main/java/com/adealink/weparty/room/member/data/MemberData.kt

@@ -1,7 +1,17 @@
 package com.adealink.weparty.room.member.data
 
+import com.adealink.weparty.commonui.recycleview.diffutil.BaseListItemData
 import com.adealink.weparty.module.profile.data.UserPlaymateSkill
 
+
+sealed class BasePlaymateCategoryItem : BaseListItemData
+
 data class PlaymateCategoryItemData(
     val skill: UserPlaymateSkill
-)
+) : BasePlaymateCategoryItem() {
+    var selected: Boolean = false
+}
+
+object PlaymateCategoryAllItemData : BasePlaymateCategoryItem() {
+    var selected: Boolean = false
+}

+ 7 - 6
module/room/src/main/java/com/adealink/weparty/room/member/viewmodel/RoomMemberViewModel.kt

@@ -16,6 +16,13 @@ class RoomMemberViewModel : BaseViewModel(),
     IMemberListener {
 
     override val onlineMemberCountLD: LiveData<Long> = MutableLiveData()
+
+    private val memberController by lazy { roomService.memberController }
+
+    init {
+        memberController.addListener(this)
+    }
+
     override fun getRoomMemberInfo(uid: String): LiveData<Rlt<UserInfo>> {
         val liveData = OnceMutableLiveData<Rlt<UserInfo>>()
         viewModelScope.launch {
@@ -32,12 +39,6 @@ class RoomMemberViewModel : BaseViewModel(),
         return liveData
     }
 
-    private val memberController by lazy { roomService.memberController }
-
-    init {
-        memberController.addListener(this)
-    }
-
 
     override fun onCleared() {
         super.onCleared()

+ 19 - 0
module/room/src/main/java/com/adealink/weparty/room/member/viewmodel/RoomPlaymateSkillViewModel.kt

@@ -0,0 +1,19 @@
+package com.adealink.weparty.room.member.viewmodel
+
+import androidx.lifecycle.MutableLiveData
+import com.adealink.frame.mvvm.viewmodel.BaseViewModel
+import com.adealink.weparty.module.profile.data.UserPlaymateSkill
+import kotlinx.coroutines.launch
+
+class RoomPlaymateSkillViewModel : BaseViewModel() {
+
+    val skillListLD = MutableLiveData<List<UserPlaymateSkill>>()
+
+    fun loadRoomPlaymateSkill() {
+        viewModelScope.launch {
+
+        }
+    }
+
+
+}

+ 12 - 9
module/room/src/main/java/com/adealink/weparty/room/micseat/BaseSeatsTemplate.kt

@@ -25,9 +25,10 @@ import com.adealink.weparty.module.room.listener.IMemberInfoListener
 import com.adealink.weparty.room.R
 import com.adealink.weparty.room.constant.logRoomTime
 import com.adealink.weparty.room.invite.InviteMicDialog
-import com.adealink.weparty.room.member.RoomMemberDialog
 import com.adealink.weparty.room.member.viewmodel.RoomMemberViewModel
 import com.adealink.weparty.room.micseat.defaults.BaseDefaultSeatView
+import com.adealink.weparty.room.micseat.dispatcenter.MIC_GUEST
+import com.adealink.weparty.room.micseat.dispatcenter.MIC_HOST
 import com.adealink.weparty.room.sdk.service.roomService
 import com.adealink.weparty.room.viewmodel.RoomViewModelFactory
 import io.trtc.tuikit.atomicxcore.api.live.SeatInfo
@@ -99,15 +100,14 @@ abstract class BaseSeatsTemplate<SV : BaseDefaultSeatView, VM : BaseSeatsTemplat
     }
 
     open fun onSeatClick(seatView: SV) {
-        // TODO:
         RoomTextActionDialog
             .Builder()
-//            .addTitle(
-//                getCompatString(
-//                    R.string.room_mic_index_title,
-//                    seatView.index.getMicName() ?: ""
-//                )
-//            )
+            .addTitle(
+                getCompatString(
+                    R.string.room_mic_index_title,
+                    seatView.micIndex.micName.invoke()
+                )
+            )
             .addItem(R.id.id_mic_operate_invite, getCompatString(R.string.room_mic_operate_invite))
             .addItem(
                 R.id.id_mic_operate_member_info,
@@ -126,7 +126,10 @@ abstract class BaseSeatsTemplate<SV : BaseDefaultSeatView, VM : BaseSeatsTemplat
                 override fun onActionClick(viewId: Int) {
                     when (viewId) {
                         R.id.id_mic_operate_invite -> {
-                            InviteMicDialog().show(childFragmentManager)
+                            InviteMicDialog().apply {
+                                inviteMicIndex(seatView.micIndex.index)
+                                enableFilter(seatView.micIndex.index != MIC_HOST && seatView.micIndex.index != MIC_GUEST)
+                            }.show(childFragmentManager)
                         }
 
                         R.id.id_mic_operate_on -> {

+ 10 - 10
module/room/src/main/java/com/adealink/weparty/room/micseat/dispatcenter/DispatchCenterSeatsTemplate.kt

@@ -29,35 +29,35 @@ class DispatchCenterSeatsTemplate :
     }
 
     override fun bindSeatViews() {
-        setSeatView(MicIndex(0) {
+        setSeatView(MicIndex(MIC_HOST) {
             getCompatString(APP_R.string.room_mic_host)
         }, binding.micHost)
-        setSeatView(MicIndex(1) {
+        setSeatView(MicIndex(MIC_GUEST) {
             getCompatString(APP_R.string.room_mic_guest)
         }, binding.micGuest)
 
-        setSeatView(MicIndex(2) {
+        setSeatView(MicIndex(MIC_1) {
             getCompatString(APP_R.string.room_mic_1)
         }, binding.mic1)
-        setSeatView(MicIndex(3) {
+        setSeatView(MicIndex(MIC_2) {
             getCompatString(APP_R.string.room_mic_2)
         }, binding.mic2)
-        setSeatView(MicIndex(4) {
+        setSeatView(MicIndex(MIC_3) {
             getCompatString(APP_R.string.room_mic_3)
         }, binding.mic3)
-        setSeatView(MicIndex(5) {
+        setSeatView(MicIndex(MIC_4) {
             getCompatString(APP_R.string.room_mic_4)
         }, binding.mic4)
-        setSeatView(MicIndex(6) {
+        setSeatView(MicIndex(MIC_5) {
             getCompatString(APP_R.string.room_mic_5)
         }, binding.mic5)
-        setSeatView(MicIndex(7) {
+        setSeatView(MicIndex(MIC_6) {
             getCompatString(APP_R.string.room_mic_6)
         }, binding.mic6)
-        setSeatView(MicIndex(8) {
+        setSeatView(MicIndex(MIC_7) {
             getCompatString(APP_R.string.room_mic_7)
         }, binding.mic7)
-        setSeatView(MicIndex(9) {
+        setSeatView(MicIndex(MIC_8) {
             getCompatString(APP_R.string.room_mic_8)
         }, binding.mic8)
     }

+ 12 - 0
module/room/src/main/java/com/adealink/weparty/room/micseat/dispatcenter/DispatchMicIndex.kt

@@ -0,0 +1,12 @@
+package com.adealink.weparty.room.micseat.dispatcenter
+
+const val MIC_HOST = 0
+const val MIC_GUEST = 1
+const val MIC_1 = 2
+const val MIC_2 = 3
+const val MIC_3 = 4
+const val MIC_4 = 5
+const val MIC_5 = 6
+const val MIC_6 = 7
+const val MIC_7 = 8
+const val MIC_8 = 9

+ 0 - 5
module/room/src/main/java/com/adealink/weparty/room/sdk/listener/IMemberListener.kt

@@ -9,9 +9,4 @@ interface IMemberListener : IListener {
      */
     fun onMemberCountChanged(count: Long)
 
-    /**
-     * 角色变化回调
-     */
-//    fun onSelfRoleChanged(before: MemberRoomRole, after: MemberRoomRole) {}
-
 }

+ 3 - 2
module/room/src/main/res/layout/dialog_room_apply_mic_host_playmate_page.xml

@@ -8,6 +8,7 @@
     android:paddingBottom="24dp">
 
     <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/cl_top"
         android:layout_width="match_parent"
         android:layout_height="@dimen/common_title_height"
         android:paddingStart="16dp"
@@ -35,8 +36,8 @@
             android:id="@+id/btn_filter"
             android:layout_width="wrap_content"
             android:layout_height="30dp"
-            android:paddingHorizontal="16dp"
             android:background="@drawable/room_bottom_item_bg"
+            android:paddingHorizontal="16dp"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintTop_toTopOf="parent">
@@ -72,7 +73,7 @@
         android:layout_height="400dp"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/tv_title">
+        app:layout_constraintTop_toBottomOf="@id/cl_top">
 
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/rv_list"

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

@@ -7,19 +7,61 @@
     android:background="@drawable/room_bottom_dialog_bg"
     android:paddingBottom="24dp">
 
-    <androidx.appcompat.widget.AppCompatTextView
-        android:id="@+id/tv_title"
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/cl_top"
         android:layout_width="match_parent"
         android:layout_height="@dimen/common_title_height"
-        android:gravity="start|center_vertical"
-        android:includeFontPadding="false"
-        android:paddingHorizontal="16dp"
-        android:textColor="@color/white"
-        android:textSize="14sp"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:text="10人申请上麦" />
+        app:layout_constraintTop_toTopOf="parent">
+
+        <androidx.appcompat.widget.AppCompatTextView
+            android:id="@+id/tv_title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="start|center_vertical"
+            android:includeFontPadding="false"
+            android:paddingHorizontal="16dp"
+            android:textColor="@color/white"
+            android:textSize="14sp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:text="10人在房间内" />
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/btn_filter"
+            android:layout_width="wrap_content"
+            android:layout_height="30dp"
+            android:background="@drawable/room_bottom_item_bg"
+            android:paddingHorizontal="16dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <androidx.appcompat.widget.AppCompatTextView
+                android:id="@+id/tv_filter"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="start|center_vertical"
+                android:includeFontPadding="false"
+                android:text="@string/room_playmate_category_filter"
+                android:textColor="@color/white"
+                android:textSize="14sp"
+                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:src="@drawable/common_go_white_ic"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toEndOf="@id/tv_filter"
+                app:layout_constraintTop_toTopOf="parent" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
 
     <com.scwang.smart.refresh.layout.SmartRefreshLayout
         android:id="@+id/v_refresh"
@@ -27,7 +69,7 @@
         android:layout_height="400dp"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/tv_title">
+        app:layout_constraintTop_toBottomOf="@id/cl_top">
 
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/rv_list"
@@ -36,26 +78,15 @@
 
     </com.scwang.smart.refresh.layout.SmartRefreshLayout>
 
-    <View
+    <com.adealink.weparty.commonui.widget.CommonEmptyErrorView
+        android:id="@+id/v_error_view"
         android:layout_width="0dp"
         android:layout_height="0dp"
-        android:background="@drawable/room_bottom_mask_bg"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="@id/btn_cancel" />
-
-    <com.adealink.weparty.commonui.widget.CommonButton
-        android:id="@+id/btn_cancel"
-        android:layout_width="0dp"
-        android:layout_height="@dimen/common_button_height"
-        android:layout_marginHorizontal="20dp"
-        app:common_button_type="room_cancel"
+        android:visibility="gone"
         app:layout_constraintBottom_toBottomOf="@id/v_refresh"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:text="@string/room_apply_mic_cancel"
-        app:textSize="16sp" />
+        app:layout_constraintEnd_toEndOf="@id/v_refresh"
+        app:layout_constraintStart_toStartOf="@id/v_refresh"
+        app:layout_constraintTop_toTopOf="@id/v_refresh" />
 
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 89 - 0
module/room/src/main/res/layout/layout_room_member_list_item.xml

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="60dp"
+    tools:background="@color/color_FF242138">
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_index"
+        android:layout_width="38dp"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:includeFontPadding="false"
+        android:textColor="@color/color_FF878A99"
+        android:textSize="16sp"
+        app:fontFamily="@font/poppins_semibold"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="1" />
+
+    <com.adealink.weparty.commonui.imageview.AvatarView
+        android:id="@+id/iv_avatar"
+        style="@style/CommonNetworkImage"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@id/tv_index"
+        app:layout_constraintTop_toTopOf="parent"
+        app:roundAsCircle="true"
+        app:roundingBorderColor="@color/color_4DFFFFFF"
+        app:roundingBorderWidth="0.5dp" />
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="12dp"
+        android:gravity="start|center_vertical"
+        android:includeFontPadding="false"
+        android:singleLine="true"
+        android:textColor="@color/white"
+        android:textSize="14sp"
+        app:fontFamily="@font/poppins_semibold"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintBottom_toBottomOf="@id/iv_avatar"
+        app:layout_constraintEnd_toStartOf="@id/v_gender"
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toEndOf="@id/iv_avatar"
+        app:layout_constraintTop_toTopOf="@id/iv_avatar"
+        tools:text="NameNameName" />
+
+    <com.adealink.weparty.module.profile.widget.GenderView
+        android:id="@+id/v_gender"
+        style="@style/CommonGenderView"
+        android:layout_marginStart="2dp"
+        app:layout_constraintBottom_toBottomOf="@id/tv_name"
+        app:layout_constraintEnd_toStartOf="@id/btn_invite"
+        app:layout_constraintStart_toEndOf="@id/tv_name"
+        app:layout_constraintTop_toTopOf="@id/tv_name" />
+
+    <com.adealink.weparty.commonui.widget.CommonButton
+        android:id="@+id/btn_invite"
+        android:layout_width="wrap_content"
+        android:layout_height="22dp"
+        android:layout_marginEnd="16dp"
+        android:gravity="start|center_vertical"
+        android:includeFontPadding="false"
+        android:paddingHorizontal="10dp"
+        android:singleLine="true"
+        android:textColor="@color/color_FFC9CDD4"
+        app:layout_constraintBottom_toBottomOf="@id/iv_avatar"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="@id/iv_avatar"
+        app:text="@string/common_invite"
+        app:textSize="12sp" />
+
+    <View
+        android:layout_width="0dp"
+        android:layout_height="1dp"
+        android:layout_marginHorizontal="16dp"
+        android:background="@color/color_0DFFFFFF"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>