feat:完成部分房间信息获取逻辑对接

This commit is contained in:
max
2024-05-29 19:31:29 +08:00
parent 65ef4810e3
commit 2396eb9089
19 changed files with 234 additions and 33 deletions

View File

@@ -85,6 +85,14 @@ fun ImageView.loadAvatar(url: String?) {
.into(this) .into(this)
} }
fun ImageView.loadImage(url: String? = "") {
if (context.isDestroyed()) return
GlideApp.with(context).load(url)
.dontAnimate()
.into(this)
}
fun Context.isDestroyed(): Boolean { fun Context.isDestroyed(): Boolean {
return (getActivityContext(this) as? Activity)?.isDestroyed == true return (getActivityContext(this) as? Activity)?.isDestroyed == true
} }

View File

@@ -17,8 +17,11 @@ import com.netease.nim.uikit.StatusBarUtil
abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(), RoomView { abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(), RoomView {
protected val viewModel: GameViewModel by viewModels() protected val viewModel: GameViewModel by viewModels()
protected val gameViewModel: GameEngineViewModel by viewModels() protected val gameEngineViewModel: GameEngineViewModel by viewModels()
protected var widgets: HashMap<String, RoomWidget> = HashMap() protected var widgets: HashMap<String, RoomWidget> = HashMap()
protected val gameContext get() = viewModel.gameContextLiveData.value
protected val stateAbility get() = gameContext?.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
override fun init() { override fun init() {
initView() initView()

View File

@@ -7,8 +7,13 @@ class GameContext(roomId: Long) : RoomContext(roomId) {
override fun loadAbility(list: MutableMap<String, RoomAbility>) { override fun loadAbility(list: MutableMap<String, RoomAbility>) {
super.loadAbility(list) super.loadAbility(list)
list.put(GameStateAbility::class.java.simpleName, GameStateAbility())
list.put(GameIMEngineAbility::class.java.simpleName, GameIMEngineAbility()) list.put(GameIMEngineAbility::class.java.simpleName, GameIMEngineAbility())
list.put(GameQueueAbility::class.java.simpleName, GameQueueAbility()) list.put(GameQueueAbility::class.java.simpleName, GameQueueAbility())
list.put(GameMessageAbility::class.java.simpleName, GameMessageAbility()) list.put(GameMessageAbility::class.java.simpleName, GameMessageAbility())
} }
override fun performStart() {
super.performStart()
}
} }

View File

@@ -12,20 +12,38 @@ import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import io.reactivex.Single import io.reactivex.Single
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import java.lang.IllegalStateException import java.lang.IllegalStateException
class GameIMEngineAbility(private val listenerOwner: ListenerOwner<GameIMEngineAbility.Listener> = SafeListenerOwner()) : class GameIMEngineAbility(private val listenerOwner: ListenerOwner<GameIMEngineAbility.Listener> = SafeListenerOwner()) :
RoomAbility(), ListenerStore<GameIMEngineAbility.Listener> by listenerOwner { RoomAbility(), ListenerStore<GameIMEngineAbility.Listener> by listenerOwner {
private var chatRoomClient: ChatRoomClient? = null
val stateFlow = MutableStateFlow<StatusCode>(StatusCode.INVALID) val stateFlow = MutableStateFlow<StatusCode>(StatusCode.INVALID)
fun enterRoom(sessionId: String) { private var chatRoomClient: ChatRoomClient? = null
private val stateAbility: GameStateAbility?
get() = roomContext?.findAbility<GameStateAbility>(
GameStateAbility::class.java.simpleName
)
override fun onStart(context: RoomContext) {
super.onStart(context)
safeLaunch {
stateAbility?.imIdFlow?.collectLatest {
loadIM(it?.toString())
}
}
}
private fun loadIM(sessionId: String?) {
if (chatRoomClient != null && chatRoomClient?.sessionId != sessionId) { if (chatRoomClient != null && chatRoomClient?.sessionId != sessionId) {
chatRoomClient?.onCleared() chatRoomClient?.onCleared()
chatRoomClient = null
}
if (sessionId != null) {
initClient(sessionId)
} }
initClient(sessionId)
} }
private fun initClient(sessionId: String) { private fun initClient(sessionId: String) {
@@ -69,6 +87,7 @@ class GameIMEngineAbility(private val listenerOwner: ListenerOwner<GameIMEngineA
super.onStop(context) super.onStop(context)
listenerOwner.removeAllListener() listenerOwner.removeAllListener()
chatRoomClient?.onCleared() chatRoomClient?.onCleared()
chatRoomClient = null
} }
interface Listener { interface Listener {

View File

@@ -1,16 +1,56 @@
package com.chwl.app.game.core package com.chwl.app.game.core
import com.chwl.app.game.data.GameModel2 import com.chwl.app.game.data.GameModel2
import com.chwl.app.game.data.bean.GameRoomInfo
import com.chwl.core.support.room.RoomAbility import com.chwl.core.support.room.RoomAbility
import com.chwl.core.support.room.RoomContext
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
class GameStateAbility : RoomAbility() { class GameStateAbility : RoomAbility() {
val gameState: MutableStateFlow<Int> = MutableStateFlow(0) /**
* 游戏状态: 本地定义状态+匹配状态
* 本地定义状态NULL:不合法状态)
* 匹配状态(服务端定义)0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败)
*/
val gameStateFlow: MutableStateFlow<Int?> = MutableStateFlow(0)
fun requestRoomInfo() { val gameIconFlow = MutableStateFlow<String?>(null)
val gameIdFlow = MutableStateFlow<String?>(null)
val roomIdFlow = MutableStateFlow<Long?>(null)
val imIdFlow = MutableStateFlow<Long?>(null)
val scoresFlow = MutableStateFlow<List<Double>?>(null)
override fun onStart(context: RoomContext) {
super.onStart(context)
requestRoomInfo()
}
private fun requestRoomInfo() {
safeLaunch { safeLaunch {
val info = GameModel2.getGameRoomInfo() val info = GameModel2.getGameRoomInfo()
if (info != null) {
syncRoomInfo(info)
} else {
syncGameState(null)
}
} }
} }
private fun syncRoomInfo(info: GameRoomInfo) {
roomIdFlow.value = info.chatRoomId
imIdFlow.value = info.roomId
gameIdFlow.value = info.data?.mgId
gameIconFlow.value = info.data?.gameRoomIcon
scoresFlow.value = info.data?.scores
syncGameState(info.data?.matchStatus)
}
private fun syncGameState(matchStatus: Int?) {
gameStateFlow.value = matchStatus
}
} }

View File

@@ -4,6 +4,7 @@ import com.chwl.app.game.data.bean.GameConfigBean
import com.chwl.app.game.data.bean.GameRoomInfo import com.chwl.app.game.data.bean.GameRoomInfo
import com.chwl.core.base.BaseModel import com.chwl.core.base.BaseModel
import com.chwl.core.bean.response.ServiceResult import com.chwl.core.bean.response.ServiceResult
import com.chwl.core.bean.room.BaseRoomInfo
import com.chwl.core.home.bean.* import com.chwl.core.home.bean.*
import com.chwl.core.utils.net.launchRequest import com.chwl.core.utils.net.launchRequest
import com.chwl.library.net.rxnet.RxNet import com.chwl.library.net.rxnet.RxNet
@@ -11,6 +12,7 @@ import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Query
object GameModel2 : BaseModel() { object GameModel2 : BaseModel() {
@@ -23,22 +25,20 @@ object GameModel2 : BaseModel() {
suspend fun getGameRoomInfo(): GameRoomInfo? = suspend fun getGameRoomInfo(): GameRoomInfo? =
launchRequest { launchRequest {
api.getGameRoomInfo() api.getChatRoomInfo(BaseRoomInfo.ROOM_TYPE_GAME)
} }
suspend fun startGame(gameId: String, gameMode: Int): String? = suspend fun startGame(gameId: String, gameMode: Int): Long? =
launchRequest { launchRequest {
api.startGame(gameId, gameMode) api.startGame(gameId, gameMode)
} }
private interface Api { private interface Api {
/** /**
* 游戏房信息 * 房信息
*
* @return -
*/ */
@GET("resource/") @GET("chatRoom/get")
suspend fun getGameRoomInfo(): ServiceResult<GameRoomInfo> suspend fun getChatRoomInfo(@Query("roomType") roomType: Int): ServiceResult<GameRoomInfo>
/** /**
* 首页游戏配置 * 首页游戏配置
@@ -54,7 +54,7 @@ object GameModel2 : BaseModel() {
suspend fun startGame( suspend fun startGame(
@Field("mgId") mgId: String, @Field("mgId") mgId: String,
@Field("gameMode") gameMode: Int @Field("gameMode") gameMode: Int
): ServiceResult<String> ): ServiceResult<Long>
} }
} }

View File

@@ -0,0 +1,18 @@
package com.chwl.app.game.data.bean
import androidx.annotation.Keep
import java.io.Serializable
@Keep
class GameRoomData : Serializable {
val mgId: String? = null
val gameRoomIcon: String? = null
val configJson: String? = null
val scores: MutableList<Double>? = null
// 匹配状态0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败)
val matchStatus: Int? = null
// 轮次状态0:进行中、1:结束)
val roundStatus: Int? = null
}

View File

@@ -1,8 +1,8 @@
package com.chwl.app.game.data.bean package com.chwl.app.game.data.bean
import androidx.annotation.Keep import androidx.annotation.Keep
import java.io.Serializable import com.chwl.core.bean.room.BaseRoomInfo
@Keep @Keep
class GameRoomInfo : Serializable { class GameRoomInfo : BaseRoomInfo<GameRoomData>() {
} }

View File

@@ -63,7 +63,7 @@ class GameBuyDialog(private val gameConfig: GameConfigBean, private val gameMode
if (it.isSuccess) { if (it.isSuccess) {
dismissAllowingStateLoss() dismissAllowingStateLoss()
val intent = val intent =
GameIntent(1, gameConfig.mgId ?: 0L, gameMode.gameMode ?: -1) GameIntent(it.data ?: 0, gameConfig.mgId ?: 0L, gameMode.gameMode ?: -1)
GameActivity.start(requireContext(), intent) GameActivity.start(requireContext(), intent)
} else { } else {
if (it.code == BalanceNotEnoughExeption.code) { if (it.code == BalanceNotEnoughExeption.code) {

View File

@@ -2,17 +2,26 @@ package com.chwl.app.game.ui.game
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.lifecycle.lifecycleScope
import com.chwl.app.R import com.chwl.app.R
import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener
import com.chwl.app.databinding.GameActivityBinding import com.chwl.app.databinding.GameActivityBinding
import com.chwl.app.game.core.BaseGameActivity import com.chwl.app.game.core.BaseGameActivity
import com.chwl.app.game.core.GameContext
import com.chwl.app.game.core.GameStateAbility
import com.chwl.app.game.core.engine.model.GameViewInfoModel.GameViewRectModel import com.chwl.app.game.core.engine.model.GameViewInfoModel.GameViewRectModel
import com.chwl.app.game.ui.game.widgets.bottom.GameBottomWidget import com.chwl.app.game.ui.game.widgets.bottom.GameBottomWidget
import com.chwl.app.game.ui.game.widgets.message.GameMessageWidget import com.chwl.app.game.ui.game.widgets.message.GameMessageWidget
import com.chwl.app.game.ui.game.widgets.queue.GameQueueWidget import com.chwl.app.game.ui.game.widgets.queue.GameQueueWidget
import com.chwl.app.ui.utils.ImageLoadUtilsV2
import com.chwl.app.ui.utils.load
import com.chwl.app.ui.utils.loadImage
import com.chwl.core.support.room.RoomView import com.chwl.core.support.room.RoomView
import com.example.lib_utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.example.lib_utils.log.ILog import com.example.lib_utils.log.ILog
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.launch
class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog { class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
@@ -32,12 +41,12 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
return return
} }
super.init() super.init()
initGameEngine()
viewModel.init(intentData) viewModel.init(intentData)
initGameEngine(intentData)
} }
private fun initGameEngine(intentData: GameIntent) { private fun initGameEngine() {
gameViewModel.init(lifecycle, binding.layoutGame) gameEngineViewModel.init(lifecycle, binding.layoutGame)
binding.spaceGameRect.post { binding.spaceGameRect.post {
val rect = GameViewRectModel().apply { val rect = GameViewRectModel().apply {
top = binding.spaceGameRect.top top = binding.spaceGameRect.top
@@ -45,8 +54,7 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
} }
logD("initGameEngine() height:${binding.root.height}") logD("initGameEngine() height:${binding.root.height}")
logD("initGameEngine() top:${rect.top} bottom:${rect.bottom}") logD("initGameEngine() top:${rect.top} bottom:${rect.bottom}")
gameViewModel.setGameViewRect(rect) gameEngineViewModel.setGameViewRect(rect)
gameViewModel.loadGame(this, intentData.roomId.toString(), intentData.gameId)
} }
} }
@@ -59,6 +67,45 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
override fun initObserver() { override fun initObserver() {
super.initObserver() super.initObserver()
viewModel.gameContextLiveData.observe(this) {
updateGameContext(it)
}
}
private fun updateGameContext(gameContext: GameContext) {
val stateAbility =
gameContext.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
?: return
lifecycleScope.launch {
stateAbility.gameIconFlow.collectLatest {
binding.ivLogo.loadImage(it)
}
stateAbility.scoresFlow.collectLatest {
val number = it?.first()?.toString() ?: ""
binding.tvAwardValue.text = number
binding.tvAwardTips.text = getString(R.string.game_award_tips_format, number)
}
updateGameEngine(stateAbility)
}
}
private suspend fun updateGameEngine(stateAbility: GameStateAbility) {
stateAbility.imIdFlow.zip(stateAbility.roomIdFlow) { imId, roomId ->
if (imId != null && roomId != null) {
Pair(imId, roomId)
} else {
null
}
}.collectLatest {
if (it != null) {
gameEngineViewModel.loadGame(
this@GameActivity,
it.second.toString(),
it.first
)
}
}
} }
override fun initWidgets() { override fun initWidgets() {

View File

@@ -3,9 +3,6 @@ package com.chwl.app.game.ui.game
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.chwl.app.base.BaseViewModel import com.chwl.app.base.BaseViewModel
import com.chwl.app.game.core.GameContext import com.chwl.app.game.core.GameContext
import com.chwl.app.game.core.GameIMEngineAbility
import com.chwl.app.public_chat.core.ChatRoomClientManager
import com.chwl.core.initial.InitialModel
class GameViewModel : BaseViewModel() { class GameViewModel : BaseViewModel() {
@@ -15,8 +12,6 @@ class GameViewModel : BaseViewModel() {
val gameContext = GameContext(intent.roomId) val gameContext = GameContext(intent.roomId)
gameContext.performStart() gameContext.performStart()
gameContextLiveData.value = gameContext gameContextLiveData.value = gameContext
gameContext.findAbility<GameIMEngineAbility>(GameIMEngineAbility::class.java.simpleName)?.enterRoom(
InitialModel.get().publicChatSessionId)
} }
override fun onCleared() { override fun onCleared() {

View File

@@ -10,7 +10,9 @@ import com.chwl.app.support.FragmentVisibleStateHelper
import com.chwl.app.ui.pay.ChargeActivity import com.chwl.app.ui.pay.ChargeActivity
import com.chwl.app.ui.utils.load import com.chwl.app.ui.utils.load
import com.chwl.app.ui.utils.loadAvatar import com.chwl.app.ui.utils.loadAvatar
import com.chwl.app.ui.webview.CommonWebViewActivity
import com.chwl.app.ui.widget.recyclerview.decoration.GridSpacingItemNewDecoration import com.chwl.app.ui.widget.recyclerview.decoration.GridSpacingItemNewDecoration
import com.chwl.core.UriProvider
import com.chwl.core.pay.PayModel import com.chwl.core.pay.PayModel
import com.chwl.core.pay.event.GetWalletInfoEvent import com.chwl.core.pay.event.GetWalletInfoEvent
import com.chwl.core.pay.event.UpdateWalletInfoEvent import com.chwl.core.pay.event.UpdateWalletInfoEvent
@@ -55,7 +57,7 @@ class GameHomeFragment : BaseViewBindingFragment<GameHomeFragmentBinding>(), Mai
ChargeActivity.start(context) ChargeActivity.start(context)
} }
binding.ivRank.singleClick { binding.ivRank.singleClick {
toast("RANK") CommonWebViewActivity.start(requireContext(), UriProvider.getGameRank())
} }
adapter.setOnItemClickListener { _, view, position -> adapter.setOnItemClickListener { _, view, position ->
val config = viewModel.gameConfigLiveData.value?.data val config = viewModel.gameConfigLiveData.value?.data

View File

@@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
class GameHomeViewModel : BaseViewModel() { class GameHomeViewModel : BaseViewModel() {
val gameConfigLiveData = MutableLiveData<BeanResult<GameConfigBean>?>() val gameConfigLiveData = MutableLiveData<BeanResult<GameConfigBean>?>()
val startGameFlow = MutableSharedFlow<BeanResult<String>>() val startGameFlow = MutableSharedFlow<BeanResult<Long>>()
fun getGameList() { fun getGameList() {
safeLaunch(onError = { safeLaunch(onError = {

View File

@@ -25,6 +25,7 @@
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
android:id="@+id/iv_logo"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginStart="@dimen/dp_11" android:layout_marginStart="@dimen/dp_11"

View File

@@ -303,6 +303,15 @@ public class UriProvider {
return JAVA_WEB_URL.concat("/molistar/modules/rule/luckyGiftRule.html?giftID=" + giftID); return JAVA_WEB_URL.concat("/molistar/modules/rule/luckyGiftRule.html?giftID=" + giftID);
} }
/**
* 游戏排行榜
*/
public static String getGameRank() {
return JAVA_WEB_URL.concat("/molistar/modules/gameRank/index.html");
}
public static String toFullUrl(String shortUrl) { public static String toFullUrl(String shortUrl) {
if (shortUrl == null) { if (shortUrl == null) {
return null; return null;

View File

@@ -0,0 +1,23 @@
package com.chwl.core.bean.room
import androidx.annotation.Keep
import java.io.Serializable
@Keep
abstract class BaseRoomInfo<T> : Serializable {
companion object {
const val ROOM_TYPE_GAME = 0
}
val chatRoomId: Long? = null
// 云信ID
val roomId: Long? = null
val roomMics: MutableList<RoomMicBean>? = null
val data: T? = null
// 房间类型0:小游戏)
val roomType: Int? = null
}

View File

@@ -0,0 +1,16 @@
package com.chwl.core.bean.room
import androidx.annotation.Keep
import java.io.Serializable
@Keep
class RoomMicBean : Serializable {
val position: Int? = null
val micUser: RoomMicUserInfo? = null
// 是否被锁
val micState: Int? = null
// 是否被禁
val posState: Int? = null
}

View File

@@ -0,0 +1,12 @@
package com.chwl.core.bean.room
import androidx.annotation.Keep
import java.io.Serializable
@Keep
class RoomMicUserInfo : Serializable {
val avatar: String? = null
val erbanNo: Long? = null
val nick: String? = null
val uid: String? = null
}

View File

@@ -1,5 +1,6 @@
package com.chwl.core.support.room package com.chwl.core.support.room
import androidx.annotation.CallSuper
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.chwl.core.room.core.RoomDataService import com.chwl.core.room.core.RoomDataService
@@ -12,7 +13,7 @@ import com.chwl.core.support.room.lifecycle.RoomLifecycleRegistry
* Desc:一个房间 * Desc:一个房间
* @param roomId roomUid * @param roomId roomUid
**/ **/
abstract class RoomContext(val roomId: Long) : ILog { abstract class RoomContext(var roomId: Long) : ILog {
/** /**
* 生命周期处理 * 生命周期处理
@@ -31,7 +32,8 @@ abstract class RoomContext(val roomId: Long) : ILog {
/** /**
* 启动(进入房间) * 启动(进入房间)
*/ */
fun performStart() { @CallSuper
open fun performStart() {
logI("performStart()", filePrinter = true) logI("performStart()", filePrinter = true)
roomLifecycle.handleLifecycleEvent(this, RoomLifecycle.Event.START) roomLifecycle.handleLifecycleEvent(this, RoomLifecycle.Event.START)
} }
@@ -39,7 +41,8 @@ abstract class RoomContext(val roomId: Long) : ILog {
/** /**
* 停止(退出房间) * 停止(退出房间)
*/ */
fun performStop() { @CallSuper
open fun performStop() {
logI("performStop()", filePrinter = true) logI("performStop()", filePrinter = true)
roomLifecycle.handleLifecycleEvent(this, RoomLifecycle.Event.STOP) roomLifecycle.handleLifecycleEvent(this, RoomLifecycle.Event.STOP)
onCleared() onCleared()