feat:完成游戏结算
@@ -12,12 +12,19 @@ import androidx.viewbinding.ViewBinding
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.base.BaseViewBindingActivity
|
||||
import com.chwl.app.common.widget.dialog.DialogManager
|
||||
import com.chwl.app.game.core.engine.GameEngineViewModel
|
||||
import com.chwl.app.game.core.engine.GameEngineAbility
|
||||
import com.chwl.app.game.data.bean.GameInfoUiState
|
||||
import com.chwl.app.game.data.bean.GameResultBean
|
||||
import com.chwl.app.game.ui.game.GameViewModel
|
||||
import com.chwl.app.game.ui.result.GameResultDialog
|
||||
import com.chwl.app.ui.pay.ChargeActivity
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import com.chwl.core.support.room.RoomView
|
||||
import com.chwl.core.support.room.RoomWidget
|
||||
import com.chwl.core.utils.net.BalanceNotEnoughExeption
|
||||
import com.chwl.core.utils.net.ServerException
|
||||
import com.chwl.library.utils.ResUtil
|
||||
import com.chwl.library.utils.SingleToastUtil
|
||||
import com.netease.nim.uikit.StatusBarUtil
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.zip
|
||||
@@ -26,25 +33,29 @@ import kotlinx.coroutines.launch
|
||||
abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(), RoomView {
|
||||
|
||||
protected val viewModel: GameViewModel by viewModels()
|
||||
protected val gameEngineViewModel: GameEngineViewModel by viewModels()
|
||||
|
||||
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)
|
||||
protected val gameEngineAbility
|
||||
get() = gameContext?.findAbility<GameEngineAbility>(
|
||||
GameEngineAbility::class.java.simpleName
|
||||
)
|
||||
|
||||
private var gameInfoDialogManager: DialogManager? = null
|
||||
protected var loadingDialogManager: DialogManager? = null
|
||||
protected var matchFailedDialogManager: DialogManager? = null
|
||||
|
||||
private var resultDialog: GameResultDialog? = null
|
||||
override fun init() {
|
||||
initView()
|
||||
initEvent()
|
||||
initObserver()
|
||||
initWidgets()
|
||||
gameEngineViewModel.init(lifecycle)
|
||||
}
|
||||
|
||||
protected open fun initView() {
|
||||
gameInfoDialogManager = DialogManager(this)
|
||||
loadingDialogManager = DialogManager(this)
|
||||
}
|
||||
|
||||
@@ -52,23 +63,32 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
}
|
||||
|
||||
protected open fun initObserver() {
|
||||
lifecycleScope.launch {
|
||||
viewModel.closeRoomFlow.collectLatest {
|
||||
loadingDialogManager?.dismissDialog()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
viewModel.gameContextLiveData.observe(this) {
|
||||
onGameContext(it)
|
||||
}
|
||||
gameEngineViewModel.gameViewLiveData.observe(this) {
|
||||
onGameViewChanged(it)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun initWidgets() {
|
||||
}
|
||||
|
||||
protected open fun onGameContext(gameContext: GameContext) {
|
||||
gameEngineViewModel.setGameContext(gameContext)
|
||||
gameContext.onViewAttach(this)
|
||||
stateAbility?.let {
|
||||
observeGameInfoUiState(it)
|
||||
updateGameEngine(it)
|
||||
|
||||
lifecycleScope.launch {
|
||||
it.matchFailedFlow.collectLatest {
|
||||
onMatchFailed()
|
||||
}
|
||||
}
|
||||
}
|
||||
initGameEngine(gameContext)
|
||||
}
|
||||
|
||||
private fun observeGameInfoUiState(stateAbility: GameStateAbility) {
|
||||
@@ -76,17 +96,26 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
stateAbility.gameInfoUiStateFlow.collectLatest {
|
||||
when (it) {
|
||||
is GameInfoUiState.Loading -> {
|
||||
if (gameInfoDialogManager == null) {
|
||||
gameInfoDialogManager = DialogManager(context)
|
||||
}
|
||||
gameInfoDialogManager?.showProgressDialog(context)
|
||||
}
|
||||
|
||||
is GameInfoUiState.Success -> {
|
||||
dialogManager?.dismissDialog()
|
||||
resultDialog?.dismissAllowingStateLoss()
|
||||
gameInfoDialogManager?.dismissDialog()
|
||||
}
|
||||
|
||||
is GameInfoUiState.Failed -> {
|
||||
gameInfoDialogManager?.dismissDialog()
|
||||
it.throwable.message?.let { msg ->
|
||||
toast(msg)
|
||||
if (it.throwable is ServerException && it.throwable.code == BalanceNotEnoughExeption.code) {
|
||||
onBalanceNotEnough()
|
||||
} else {
|
||||
it.throwable.message?.let { msg ->
|
||||
toast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +129,11 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateGameEngine(stateAbility: GameStateAbility) {
|
||||
protected open fun initGameEngine(gameContext: GameContext) {
|
||||
val gameEngineAbility =
|
||||
gameContext.findAbility<GameEngineAbility>(GameEngineAbility::class.java.simpleName)
|
||||
lifecycleScope.launch {
|
||||
val stateAbility = stateAbility ?: return@launch
|
||||
stateAbility.gameIdFlow.zip(stateAbility.roomIdFlow) { gameId, roomId ->
|
||||
if (gameId?.toLongOrNull() != null && roomId != null) {
|
||||
Pair(gameId.toLong(), roomId)
|
||||
@@ -110,7 +142,7 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
}
|
||||
}.collectLatest {
|
||||
if (it != null) {
|
||||
gameEngineViewModel.loadGame(
|
||||
gameEngineAbility?.loadGame(
|
||||
this@BaseGameActivity,
|
||||
it.second.toString(),
|
||||
it.first
|
||||
@@ -118,6 +150,71 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
gameEngineAbility?.gameResultFlow?.collectLatest {
|
||||
onGameResult(it)
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
gameEngineAbility?.gameViewFlow?.collectLatest {
|
||||
onGameViewChanged(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onGameResult(list: List<GameResultBean>?) {
|
||||
if (list == null) {
|
||||
return
|
||||
}
|
||||
resultDialog = GameResultDialog(list, onClose = {
|
||||
closeRoom()
|
||||
}, onRestart = {
|
||||
restart()
|
||||
})
|
||||
resultDialog?.show(supportFragmentManager, "GAME_RESULT")
|
||||
}
|
||||
|
||||
private fun onMatchFailed() {
|
||||
if (matchFailedDialogManager == null) {
|
||||
matchFailedDialogManager = DialogManager(context)
|
||||
}
|
||||
matchFailedDialogManager?.showOkCancelDialog(null,
|
||||
getString(R.string.game_match_failed),
|
||||
getString(R.string.game_rematch),
|
||||
getString(R.string.exit_text), false, false, object :
|
||||
DialogManager.OkCancelDialogListener {
|
||||
override fun onOk() {
|
||||
restart()
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
super.onCancel()
|
||||
closeRoom()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected open fun onBalanceNotEnough() {
|
||||
dialogManager?.showOkCancelDialog(
|
||||
ResUtil.getString(R.string.star_send_gift_balance),
|
||||
ResUtil.getString(R.string.treasure_to_charge)
|
||||
) {
|
||||
ChargeActivity.start(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun closeRoom() {
|
||||
loadingDialogManager?.showProgressDialog(this@BaseGameActivity)
|
||||
viewModel.closeRoom()
|
||||
}
|
||||
|
||||
private fun restart() {
|
||||
val intent = viewModel.getGameIntent()
|
||||
if (intent == null) {
|
||||
toast(R.string.data_error)
|
||||
return
|
||||
}
|
||||
stateAbility?.restart(intent)
|
||||
}
|
||||
|
||||
protected open fun onGameViewChanged(view: View?) {
|
||||
@@ -140,7 +237,7 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
* 注册组件
|
||||
*/
|
||||
protected open fun registerWidget(name: String, widget: RoomWidget) {
|
||||
widgets.put(name, widget)
|
||||
widgets[name] = widget
|
||||
widget.onStart(this)
|
||||
}
|
||||
|
||||
@@ -193,5 +290,9 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
gameInfoDialogManager = null
|
||||
loadingDialogManager?.dismissDialog()
|
||||
loadingDialogManager = null
|
||||
resultDialog?.dismissAllowingStateLoss()
|
||||
resultDialog = null
|
||||
matchFailedDialogManager?.dismissDialog()
|
||||
matchFailedDialogManager = null
|
||||
}
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
package com.chwl.app.game.core
|
||||
|
||||
import com.chwl.app.game.core.engine.GameEngineAbility
|
||||
import com.chwl.core.bean.game.GameRoomInfo
|
||||
import com.chwl.core.support.room.RoomAbility
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
|
||||
@@ -7,13 +9,18 @@ class GameContext(roomId: Long) : RoomContext(roomId) {
|
||||
|
||||
override fun loadAbility(list: MutableMap<String, RoomAbility>) {
|
||||
super.loadAbility(list)
|
||||
list.put(GameStateAbility::class.java.simpleName, GameStateAbility())
|
||||
list.put(GameIMEngineAbility::class.java.simpleName, GameIMEngineAbility())
|
||||
list.put(GameQueueAbility::class.java.simpleName, GameQueueAbility())
|
||||
list.put(GameMessageAbility::class.java.simpleName, GameMessageAbility())
|
||||
list[GameStateAbility::class.java.simpleName] = GameStateAbility()
|
||||
list[GameEngineAbility::class.java.simpleName] = GameEngineAbility()
|
||||
list[GameIMEngineAbility::class.java.simpleName] = GameIMEngineAbility()
|
||||
list[GameQueueAbility::class.java.simpleName] = GameQueueAbility()
|
||||
list[GameMessageAbility::class.java.simpleName] = GameMessageAbility()
|
||||
}
|
||||
|
||||
override fun performStart() {
|
||||
super.performStart()
|
||||
}
|
||||
|
||||
fun restart(roomInfo: GameRoomInfo) {
|
||||
val stateAbility = findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
|
||||
}
|
||||
}
|
@@ -16,4 +16,10 @@ class GameQueueAbility : RoomAbility() {
|
||||
suspend fun updateQueue(data: List<RoomMicBean>?) {
|
||||
queueFlow.value = data
|
||||
}
|
||||
|
||||
fun findQueueItem(uid: Long): RoomMicBean? {
|
||||
return queueFlow.value?.firstOrNull {
|
||||
it.micUser?.uid == uid
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ package com.chwl.app.game.core
|
||||
|
||||
import com.chwl.app.game.data.GameModel2
|
||||
import com.chwl.app.game.data.bean.GameInfoUiState
|
||||
import com.chwl.app.game.ui.game.GameIntent
|
||||
import com.chwl.core.bean.game.GameRoomInfo
|
||||
import com.chwl.core.im.custom.bean.CustomAttachment
|
||||
import com.chwl.core.im.custom.bean.GameQueueChangedAttachment
|
||||
@@ -14,12 +15,26 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class GameStateAbility : RoomAbility(), GameIMEngineAbility.Listener {
|
||||
|
||||
companion object {
|
||||
// 匹配中
|
||||
const val STATE_MATCHING = 0
|
||||
|
||||
// 匹配成功
|
||||
const val STATE_MATCH_SUCCESS = 1
|
||||
|
||||
// 游戏结束
|
||||
const val STATE_GAME_END = 2
|
||||
|
||||
// 匹配失败
|
||||
const val STATE_MATCH_FAILED = 3
|
||||
}
|
||||
|
||||
/**
|
||||
* 游戏状态: 本地定义状态+匹配状态
|
||||
* 本地定义状态:(NULL:不合法状态)
|
||||
* 匹配状态(服务端定义):(0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败)
|
||||
*/
|
||||
val gameStateFlow: MutableStateFlow<Int?> = MutableStateFlow(0)
|
||||
val gameStateFlow: MutableStateFlow<Int?> = MutableStateFlow(STATE_MATCHING)
|
||||
|
||||
val gameIconFlow = MutableStateFlow<String?>(null)
|
||||
|
||||
@@ -64,6 +79,16 @@ class GameStateAbility : RoomAbility(), GameIMEngineAbility.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
fun restart(intent: GameIntent) {
|
||||
gameInfoUiStateFlow.value = GameInfoUiState.Loading
|
||||
safeLaunch(onError = {
|
||||
gameInfoUiStateFlow.value = GameInfoUiState.Failed(it, gameInfoFlow.value)
|
||||
}) {
|
||||
val roomId = GameModel2.startGame(intent.gameId.toString(), intent.gameMode)
|
||||
requestRoomInfo()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun syncRoomInfo(info: GameRoomInfo) {
|
||||
roomContext?.roomId = info.chatRoomId ?: 0
|
||||
gameInfoFlow.value = info
|
||||
|
@@ -0,0 +1,112 @@
|
||||
package com.chwl.app.game.core.engine
|
||||
|
||||
import com.chwl.app.game.core.GameQueueAbility
|
||||
import com.chwl.app.game.core.GameStateAbility
|
||||
import com.chwl.app.game.data.bean.GameResultBean
|
||||
import com.chwl.core.sud.state.SudMGPMGState
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import tech.sud.mgp.core.ISudFSMStateHandle
|
||||
|
||||
class GameEngineAbility : SudEngineAbility() {
|
||||
val gameResultFlow = MutableSharedFlow<List<GameResultBean>?>()
|
||||
|
||||
private val stateAbility get() = roomContext?.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
|
||||
override fun onStart(context: RoomContext) {
|
||||
super.onStart(context)
|
||||
safeLaunch {
|
||||
stateAbility?.gameStateFlow?.collectLatest {
|
||||
logD("GameEngineAbility gameStateFlow state:${it}")
|
||||
when (it) {
|
||||
GameStateAbility.STATE_MATCH_SUCCESS -> {
|
||||
autoPlayGame()
|
||||
}
|
||||
|
||||
GameStateAbility.STATE_MATCHING -> {
|
||||
tryStopGame()
|
||||
}
|
||||
|
||||
GameStateAbility.STATE_MATCH_FAILED -> {
|
||||
tryStopGame()
|
||||
}
|
||||
|
||||
GameStateAbility.STATE_GAME_END -> {
|
||||
tryStopGame()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryStopGame() {
|
||||
}
|
||||
|
||||
private fun autoPlayGame() {
|
||||
val stateAbility = stateAbility ?: return
|
||||
logD("autoPlayGame state:${stateAbility.gameStateFlow.value}")
|
||||
if (stateAbility.gameStateFlow.value != GameStateAbility.STATE_MATCH_SUCCESS) {
|
||||
return
|
||||
}
|
||||
val queueAbility =
|
||||
roomContext?.findAbility<GameQueueAbility>(GameQueueAbility::class.java.simpleName)
|
||||
?: return
|
||||
val queueSize = queueAbility.queueFlow.value?.size ?: 0
|
||||
if (queueSize == 0) {
|
||||
return
|
||||
}
|
||||
logD("autoPlayGame queueSize:$queueSize size:${sudFSMMG.sudFSMMGCache.playerReadySet.size}")
|
||||
if (sudFSMMG.sudFSMMGCache.playerReadySet.size >= queueSize) {
|
||||
sudFSTAPP.notifyAPPCommonSelfPlaying(true, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun autoJoinGame() {
|
||||
sudFSTAPP.notifyAPPCommonSelfIn(true, -1, true, 1)
|
||||
sudFSTAPP.notifyAPPCommonSelfReady(true)
|
||||
}
|
||||
|
||||
override fun onGameStarted() {
|
||||
super.onGameStarted()
|
||||
autoJoinGame()
|
||||
}
|
||||
|
||||
override fun onPlayerMGCommonPlayerReady(
|
||||
handle: ISudFSMStateHandle?,
|
||||
userId: String?,
|
||||
model: SudMGPMGState.MGCommonPlayerReady?
|
||||
) {
|
||||
super.onPlayerMGCommonPlayerReady(handle, userId, model)
|
||||
autoPlayGame()
|
||||
}
|
||||
|
||||
override fun onGameMGCommonGameSettle(
|
||||
handle: ISudFSMStateHandle,
|
||||
model: SudMGPMGState.MGCommonGameSettle?
|
||||
) {
|
||||
super.onGameMGCommonGameSettle(handle, model)
|
||||
val list = ArrayList<GameResultBean>()
|
||||
val queueAbility =
|
||||
roomContext?.findAbility<GameQueueAbility>(GameQueueAbility::class.java.simpleName)
|
||||
val stateAbility =
|
||||
roomContext?.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
|
||||
val scoresList = stateAbility?.scoresFlow?.value
|
||||
model?.results?.sortedBy { it.rank }?.forEachIndexed { index, it ->
|
||||
val uid = it.uid?.toLong() ?: -1
|
||||
val queueItem = queueAbility?.findQueueItem(uid)
|
||||
val scores = scoresList?.getOrNull(index)
|
||||
val item = GameResultBean().apply {
|
||||
this.uid = it.uid
|
||||
this.rank = it.rank
|
||||
this.score = it.score
|
||||
this.nick = queueItem?.micUser?.nick
|
||||
this.avatar = queueItem?.micUser?.avatar
|
||||
this.coins = scores
|
||||
}
|
||||
list.add(item)
|
||||
}
|
||||
safeLaunch {
|
||||
gameResultFlow.emit(list)
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,17 +4,12 @@ import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.FrameLayout
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.avroom.game.AppConfig
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.core.GameContext
|
||||
import com.chwl.app.game.core.GameQueueAbility
|
||||
import com.chwl.app.game.core.GameStateAbility
|
||||
import com.chwl.core.auth.AuthModel
|
||||
import com.chwl.core.room.game.GameModel
|
||||
import com.chwl.core.room.game.bean.GameCfg
|
||||
@@ -24,50 +19,36 @@ import com.chwl.core.sud.decorator.SudFSTAPPDecorator
|
||||
import com.chwl.core.sud.model.GameViewInfoModel
|
||||
import com.chwl.core.sud.state.MGStateResponse
|
||||
import com.chwl.core.sud.state.SudMGPMGState
|
||||
import com.chwl.core.support.room.RoomAbility
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import com.chwl.library.language.LanguageHelper
|
||||
import com.chwl.library.utils.SingleToastUtil
|
||||
import com.chwl.library.utils.json.JsonUtils
|
||||
import com.example.lib_utils.log.ILog
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import tech.sud.mgp.core.ISudFSMStateHandle
|
||||
import tech.sud.mgp.core.ISudListenerInitSDK
|
||||
import tech.sud.mgp.core.SudMGP
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
open class GameEngineViewModel : BaseViewModel(), SudFSMMGListener, ILog,
|
||||
LifecycleEventObserver {
|
||||
open class SudEngineAbility : RoomAbility(), SudFSMMGListener, ILog {
|
||||
|
||||
val gameViewLiveData = MutableLiveData<View>(null)
|
||||
private var isRunning = true
|
||||
private val sudFSMMG = SudFSMMGDecorator().apply {
|
||||
setSudFSMMGListener(this@GameEngineViewModel)
|
||||
val gameViewFlow = MutableStateFlow<View?>(null)
|
||||
protected var isRunning = true
|
||||
protected val sudFSMMG = SudFSMMGDecorator().apply {
|
||||
setSudFSMMGListener(this@SudEngineAbility)
|
||||
}
|
||||
private val sudFSTAPP = SudFSTAPPDecorator()
|
||||
private var lifecycle: Lifecycle? = null
|
||||
protected val sudFSTAPP = SudFSTAPPDecorator()
|
||||
private var gameViewRect: GameViewInfoModel.GameViewRectModel =
|
||||
GameViewInfoModel.GameViewRectModel()
|
||||
private var roomId: String = ""
|
||||
|
||||
private var gameContext: GameContext? = null
|
||||
|
||||
fun init(lifecycle: Lifecycle) {
|
||||
this.lifecycle = lifecycle
|
||||
lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
fun setGameContext(gameContext: GameContext) {
|
||||
this.gameContext = gameContext
|
||||
}
|
||||
|
||||
fun loadGame(activity: Activity, roomId: String, gameId: Long) {
|
||||
logD("loadGame() roomId:$roomId gameId:$gameId")
|
||||
if (!this.isRunning) {
|
||||
return
|
||||
}
|
||||
if (lifecycle == null) {
|
||||
throw IllegalStateException("未初始化")
|
||||
}
|
||||
this.roomId = roomId
|
||||
getGameCode({
|
||||
initSDK(activity, gameId, it)
|
||||
@@ -104,7 +85,7 @@ open class GameEngineViewModel : BaseViewModel(), SudFSMMGListener, ILog,
|
||||
val iSudFSTAPP =
|
||||
SudMGP.loadMG(activity, userId, getRoomId(), code, gameId, getGameLanguage(), sudFSMMG)
|
||||
sudFSTAPP.setISudFSTAPP(iSudFSTAPP)
|
||||
gameViewLiveData.value = iSudFSTAPP.gameView
|
||||
gameViewFlow.value = iSudFSTAPP.gameView
|
||||
}
|
||||
|
||||
fun setGameViewRect(rect: GameViewInfoModel.GameViewRectModel) {
|
||||
@@ -137,57 +118,50 @@ open class GameEngineViewModel : BaseViewModel(), SudFSMMGListener, ILog,
|
||||
handle.success(JsonUtils.toJson(response))
|
||||
}
|
||||
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||
if (event == Lifecycle.Event.ON_DESTROY) {
|
||||
onViewDestroy()
|
||||
}
|
||||
override fun onStop(context: RoomContext) {
|
||||
super.onStop(context)
|
||||
destroyGame()
|
||||
}
|
||||
|
||||
private fun getRoomId() = roomId
|
||||
|
||||
private fun getAppId() = AppConfig.APP_ID
|
||||
|
||||
private fun getAppKey() = AppConfig.APP_KEY
|
||||
|
||||
private fun isTestEnv() = AppConfig.isTestEnv
|
||||
|
||||
private fun getGameLanguage(): String {
|
||||
return when (LanguageHelper.getCurrentLanguageType()) {
|
||||
LanguageHelper.ZH -> {
|
||||
"zh-TW"
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||
super.onStateChanged(source, event)
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_START -> {
|
||||
sudFSTAPP.startMG()
|
||||
}
|
||||
|
||||
LanguageHelper.AR -> {
|
||||
"ar-SA"
|
||||
Lifecycle.Event.ON_STOP -> {
|
||||
sudFSTAPP.stopMG()
|
||||
}
|
||||
|
||||
Lifecycle.Event.ON_RESUME -> {
|
||||
sudFSTAPP.playMG()
|
||||
}
|
||||
|
||||
Lifecycle.Event.ON_PAUSE -> {
|
||||
sudFSTAPP.pauseMG()
|
||||
}
|
||||
|
||||
Lifecycle.Event.ON_DESTROY -> {
|
||||
destroyGame()
|
||||
}
|
||||
|
||||
else -> {
|
||||
"en-US"
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
onViewDestroy()
|
||||
}
|
||||
|
||||
private fun onViewDestroy() {
|
||||
isRunning = false
|
||||
lifecycle?.removeObserver(this)
|
||||
lifecycle = null
|
||||
}
|
||||
|
||||
override fun onGameStarted() {
|
||||
autoJoinGame()
|
||||
}
|
||||
|
||||
override fun onGameDestroyed() {
|
||||
|
||||
}
|
||||
|
||||
private fun autoJoinGame() {
|
||||
sudFSTAPP.notifyAPPCommonSelfIn(true, -1, true, 1)
|
||||
sudFSTAPP.notifyAPPCommonSelfReady(true)
|
||||
private fun destroyGame() {
|
||||
isRunning = false
|
||||
sudFSTAPP.destroyMG()
|
||||
}
|
||||
|
||||
override fun onExpireCode(handle: ISudFSMStateHandle, p1: String?) {
|
||||
@@ -200,7 +174,7 @@ open class GameEngineViewModel : BaseViewModel(), SudFSMMGListener, ILog,
|
||||
}
|
||||
|
||||
override fun onGetGameViewInfo(handle: ISudFSMStateHandle, p1: String?) {
|
||||
val gameLayout = gameViewLiveData.value
|
||||
val gameLayout = gameViewFlow.value
|
||||
if (gameLayout == null) {
|
||||
handle.failure("gameLayout is NULL")
|
||||
return
|
||||
@@ -231,22 +205,27 @@ open class GameEngineViewModel : BaseViewModel(), SudFSMMGListener, ILog,
|
||||
sudFSTAPP.notifyAPPCommonSelfIn(true, -1, true, 1)
|
||||
}
|
||||
|
||||
override fun onPlayerMGCommonPlayerReady(
|
||||
handle: ISudFSMStateHandle?,
|
||||
userId: String?,
|
||||
model: SudMGPMGState.MGCommonPlayerReady?
|
||||
) {
|
||||
super.onPlayerMGCommonPlayerReady(handle, userId, model)
|
||||
val queueAbility =
|
||||
gameContext?.findAbility<GameQueueAbility>(GameQueueAbility::class.java.simpleName)
|
||||
?: return
|
||||
val queueSize = queueAbility.queueFlow.value?.size ?: 0
|
||||
if (queueSize == 0) {
|
||||
return
|
||||
}
|
||||
logD("onPlayerMGCommonPlayerReady queueSize:$queueSize size:${sudFSMMG.sudFSMMGCache.playerReadySet.size}")
|
||||
if (sudFSMMG.sudFSMMGCache.playerReadySet.size >= queueSize) {
|
||||
sudFSTAPP.notifyAPPCommonSelfPlaying(true, null, null)
|
||||
protected open fun getRoomId() = roomId
|
||||
|
||||
protected open fun getAppId() = AppConfig.APP_ID
|
||||
|
||||
protected open fun getAppKey() = AppConfig.APP_KEY
|
||||
|
||||
protected open fun isTestEnv() = AppConfig.isTestEnv
|
||||
|
||||
protected open fun getGameLanguage(): String {
|
||||
return when (LanguageHelper.getCurrentLanguageType()) {
|
||||
LanguageHelper.ZH -> {
|
||||
"zh-TW"
|
||||
}
|
||||
|
||||
LanguageHelper.AR -> {
|
||||
"ar-SA"
|
||||
}
|
||||
|
||||
else -> {
|
||||
"en-US"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.chwl.app.game.data.bean
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import java.io.Serializable
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Keep
|
||||
class GameResultBean : Serializable {
|
||||
var rank: Int? = null
|
||||
var uid: String? = null
|
||||
var avatar: String? = null
|
||||
var nick: String? = null
|
||||
var score: Int? = null
|
||||
var coins: Double? = null
|
||||
|
||||
fun getCoinsStr(): String {
|
||||
val coinsValue = coins ?: return "0"
|
||||
try {
|
||||
val bigDecimal = BigDecimal.valueOf(coinsValue)
|
||||
val coinsStr = bigDecimal.stripTrailingZeros().toPlainString()
|
||||
if (coinsValue > 0) {
|
||||
return "+$coinsStr"
|
||||
}
|
||||
return coinsStr
|
||||
} catch (e: Exception) {
|
||||
return coins?.toString() ?: "0"
|
||||
}
|
||||
}
|
||||
}
|
@@ -47,15 +47,6 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
|
||||
override fun initView() {
|
||||
super.initView()
|
||||
binding.spaceGameRect.post {
|
||||
val rect = GameViewInfoModel.GameViewRectModel().apply {
|
||||
top = binding.spaceGameRect.top
|
||||
bottom = binding.root.height - binding.spaceGameRect.bottom
|
||||
}
|
||||
logD("initGameEngine() height:${binding.root.height}")
|
||||
logD("initGameEngine() top:${rect.top} bottom:${rect.bottom}")
|
||||
gameEngineViewModel.setGameViewRect(rect)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initEvent() {
|
||||
@@ -81,12 +72,19 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
updateAward(it?.first())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
stateAbility.matchFailedFlow.collectLatest {
|
||||
showMatchFailed()
|
||||
override fun initGameEngine(gameContext: GameContext) {
|
||||
binding.spaceGameRect.post {
|
||||
val rect = GameViewInfoModel.GameViewRectModel().apply {
|
||||
top = binding.spaceGameRect.top
|
||||
bottom = binding.root.height - binding.spaceGameRect.bottom
|
||||
}
|
||||
logD("initGameEngine() height:${binding.root.height}")
|
||||
logD("initGameEngine() top:${rect.top} bottom:${rect.bottom}")
|
||||
gameEngineAbility?.setGameViewRect(rect)
|
||||
}
|
||||
super.initGameEngine(gameContext)
|
||||
}
|
||||
|
||||
private fun updateAward(number: Double?) {
|
||||
@@ -106,19 +104,6 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
|
||||
override fun initObserver() {
|
||||
super.initObserver()
|
||||
lifecycleScope.launch {
|
||||
viewModel.closeRoomFlow.collectLatest {
|
||||
loadingDialogManager?.dismissDialog()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.restartFlow.collectLatest {
|
||||
loadingDialogManager?.dismissDialog()
|
||||
// TODO 待完善
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initWidgets() {
|
||||
@@ -137,24 +122,6 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
return binding.layoutGame
|
||||
}
|
||||
|
||||
private fun showMatchFailed() {
|
||||
dialogManager.showOkCancelDialog(null,
|
||||
getString(R.string.game_match_failed),
|
||||
getString(R.string.game_rematch),
|
||||
getString(R.string.exit_text), false, false, object : OkCancelDialogListener {
|
||||
override fun onOk() {
|
||||
loadingDialogManager?.showProgressDialog(this@GameActivity)
|
||||
viewModel.restart()
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
super.onCancel()
|
||||
loadingDialogManager?.showProgressDialog(this@GameActivity)
|
||||
viewModel.closeRoom()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun showExitTips() {
|
||||
dialogManager.showOkCancelDialog(null,
|
||||
getString(R.string.game_exit_tips),
|
||||
|
@@ -4,6 +4,7 @@ import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.core.GameContext
|
||||
import com.chwl.app.game.core.GameStateAbility
|
||||
import com.chwl.app.game.data.GameModel2
|
||||
import com.chwl.core.bean.response.BeanResult
|
||||
import com.chwl.library.utils.ResUtil
|
||||
@@ -15,8 +16,6 @@ class GameViewModel : BaseViewModel() {
|
||||
|
||||
val closeRoomFlow = MutableSharedFlow<BeanResult<String?>>()
|
||||
|
||||
val restartFlow = MutableSharedFlow<BeanResult<String?>>()
|
||||
|
||||
private var gameIntent: GameIntent? = null
|
||||
|
||||
fun init(intent: GameIntent) {
|
||||
@@ -26,25 +25,15 @@ class GameViewModel : BaseViewModel() {
|
||||
gameContextLiveData.value = gameContext
|
||||
}
|
||||
|
||||
fun getGameIntent(): GameIntent? {
|
||||
return gameIntent
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
gameContextLiveData.value?.performStop()
|
||||
}
|
||||
|
||||
fun restart() {
|
||||
val intent = gameIntent
|
||||
if (intent == null) {
|
||||
safeLaunch {
|
||||
restartFlow.emit(BeanResult.failed(NullPointerException(ResUtil.getString(R.string.utils_net_beanobserver_05))))
|
||||
}
|
||||
return
|
||||
}
|
||||
safeLaunch {
|
||||
val result = GameModel2.startGame(intent.gameId.toString(), intent.gameMode)
|
||||
// TODO 待完善
|
||||
}
|
||||
}
|
||||
|
||||
fun closeRoom() {
|
||||
val roomId = gameContextLiveData.value?.roomId
|
||||
if (roomId != null) {
|
||||
|
@@ -0,0 +1,37 @@
|
||||
package com.chwl.app.game.ui.result
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.BaseViewHolder
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.game.data.bean.GameResultBean
|
||||
import com.chwl.app.ui.utils.loadAvatar
|
||||
|
||||
class GameResultAdapter :
|
||||
BaseQuickAdapter<GameResultBean, BaseViewHolder>(R.layout.game_result_item) {
|
||||
override fun convert(helper: BaseViewHolder, item: GameResultBean?) {
|
||||
helper.setText(R.id.tv_name, item?.nick ?: "")
|
||||
helper.setText(R.id.tv_coins, item?.getCoinsStr() ?: "0")
|
||||
helper.getView<ImageView>(R.id.iv_user_avatar).loadAvatar(item?.avatar)
|
||||
val rank = helper.bindingAdapterPosition
|
||||
val rankView = helper.getView<TextView>(R.id.tv_rank)
|
||||
val rootView = helper.getView<View>(R.id.layout_root)
|
||||
if (rank == 0) {
|
||||
rankView.setBackgroundResource(R.drawable.game_result_ic_top1)
|
||||
rankView.text = ""
|
||||
} else if (rank == 1) {
|
||||
rankView.setBackgroundResource(R.drawable.game_result_ic_top2)
|
||||
rankView.text = ""
|
||||
} else {
|
||||
rankView.background = null
|
||||
rankView.text = "${(rank + 1)}"
|
||||
}
|
||||
if (rank % 2 == 0) {
|
||||
rootView.setBackgroundResource(R.drawable.game_result_item_bg_top1)
|
||||
} else {
|
||||
rootView.setBackgroundResource(R.drawable.game_result_item_bg_top2)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
package com.chwl.app.game.ui.result
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.databinding.GameResultDialogBinding
|
||||
import com.chwl.app.game.data.bean.GameResultBean
|
||||
import com.chwl.app.ui.widget.recyclerview.decoration.SpacingDecoration
|
||||
import com.chwl.core.auth.AuthModel
|
||||
import com.chwl.library.common.util.Utils
|
||||
import com.example.lib_utils.ktx.singleClick
|
||||
|
||||
class GameResultDialog(
|
||||
private val list: List<GameResultBean>,
|
||||
private var onClose: (() -> Unit)?,
|
||||
private var onRestart: (() -> Unit)?
|
||||
) : DialogFragment() {
|
||||
|
||||
private var binding: GameResultDialogBinding? = null
|
||||
|
||||
private val adapter = GameResultAdapter()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
initView()
|
||||
adapter.setNewData(list)
|
||||
var isSuccess = false
|
||||
if (list.firstOrNull()?.uid?.toLongOrNull() == AuthModel.get().currentUid) {
|
||||
isSuccess = true
|
||||
}
|
||||
if (isSuccess) {
|
||||
binding?.ivState?.setBackgroundResource(R.drawable.game_result_bg_win)
|
||||
} else {
|
||||
binding?.ivState?.setBackgroundResource(R.drawable.game_result_bg_lose)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
binding?.tvClose?.singleClick {
|
||||
onClose?.invoke()
|
||||
}
|
||||
binding?.tvRestart?.singleClick {
|
||||
onRestart?.invoke()
|
||||
}
|
||||
binding?.recyclerView?.addItemDecoration(
|
||||
SpacingDecoration(
|
||||
0,
|
||||
Utils.dip2px(context, 10f),
|
||||
false
|
||||
)
|
||||
)
|
||||
binding?.recyclerView?.adapter = adapter
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
onClose = null
|
||||
onRestart = null
|
||||
}
|
||||
|
||||
override fun getTheme(): Int {
|
||||
return R.style.full_screen_dialog
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = GameResultDialogBinding.inflate(LayoutInflater.from(context))
|
||||
return binding?.root
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
this.setCancelable(false)
|
||||
this.setCanceledOnTouchOutside(false)
|
||||
window?.setLayout(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 15 KiB |
BIN
app/src/module_game/res/drawable-xxhdpi/game_result_bg_close.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
app/src/module_game/res/drawable-xxhdpi/game_result_bg_lose.png
Normal file
After Width: | Height: | Size: 718 KiB |
After Width: | Height: | Size: 12 KiB |
BIN
app/src/module_game/res/drawable-xxhdpi/game_result_bg_win.png
Normal file
After Width: | Height: | Size: 729 KiB |
BIN
app/src/module_game/res/drawable-xxhdpi/game_result_ic_top1.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
app/src/module_game/res/drawable-xxhdpi/game_result_ic_top2.png
Normal file
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 6.4 KiB |
5
app/src/module_game/res/drawable/game_result_bg_1.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#1ADCE5" />
|
||||
<corners android:radius="@dimen/dp_16" />
|
||||
</shape>
|
5
app/src/module_game/res/drawable/game_result_bg_2.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#E2F6FF" />
|
||||
<corners android:radius="@dimen/dp_12" />
|
||||
</shape>
|
13
app/src/module_game/res/drawable/game_result_coins_top1.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<corners
|
||||
android:bottomLeftRadius="0px"
|
||||
android:bottomRightRadius="@dimen/dp_5"
|
||||
android:topLeftRadius="0px"
|
||||
android:topRightRadius="@dimen/dp_5" />
|
||||
<solid android:color="#9B4300" />
|
||||
<stroke
|
||||
android:width="@dimen/dp_1"
|
||||
android:color="#FFBC1E" />
|
||||
</shape>
|
13
app/src/module_game/res/drawable/game_result_coins_top2.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<corners
|
||||
android:bottomLeftRadius="0px"
|
||||
android:bottomRightRadius="@dimen/dp_5"
|
||||
android:topLeftRadius="0px"
|
||||
android:topRightRadius="@dimen/dp_5" />
|
||||
<solid android:color="#00666B" />
|
||||
<stroke
|
||||
android:width="@dimen/dp_1"
|
||||
android:color="#FCFF1E" />
|
||||
</shape>
|
96
app/src/module_game/res/layout/game_result_dialog.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?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="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/layout_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/game_result_bg_1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.47"
|
||||
app:layout_constraintWidth_percent="0.832">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/dp_7"
|
||||
android:layout_marginTop="@dimen/dp_41"
|
||||
android:layout_marginBottom="@dimen/dp_8"
|
||||
android:background="@drawable/game_result_bg_2">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/dp_13"
|
||||
android:layout_marginTop="@dimen/dp_15"
|
||||
android:maxHeight="@dimen/dp_150"
|
||||
android:minHeight="@dimen/dp_120"
|
||||
android:orientation="vertical"
|
||||
android:scrollbars="none"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:layout_height="@dimen/dp_120" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_close"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="@dimen/dp_14"
|
||||
android:layout_marginTop="@dimen/dp_30"
|
||||
android:layout_marginBottom="@dimen/dp_20"
|
||||
android:background="@drawable/game_result_bg_close"
|
||||
android:gravity="center"
|
||||
android:text="@string/close"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_18"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="132:40"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_restart"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/recycler_view" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_restart"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="@dimen/dp_6"
|
||||
android:layout_marginEnd="@dimen/dp_14"
|
||||
android:background="@drawable/game_result_bg_restart"
|
||||
android:gravity="center"
|
||||
android:text="@string/game_rematch"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_18"
|
||||
app:layout_constraintDimensionRatio="132:40"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_close"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_close" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<Space
|
||||
android:id="@+id/space_state_bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="375:85"
|
||||
app:layout_constraintTop_toTopOf="@id/layout_content" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_state"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:src="@drawable/game_result_bg_win"
|
||||
app:layout_constraintBottom_toBottomOf="@id/space_state_bottom"
|
||||
app:layout_constraintDimensionRatio="375:317" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
108
app/src/module_game/res/layout/game_result_item.xml
Normal file
@@ -0,0 +1,108 @@
|
||||
<?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:id="@+id/layout_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_60"
|
||||
android:background="@drawable/game_result_item_bg_top1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_rank"
|
||||
android:layout_width="@dimen/dp_42"
|
||||
android:layout_height="@dimen/dp_42"
|
||||
android:layout_marginStart="@dimen/dp_7"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_20"
|
||||
android:textStyle="bold"
|
||||
app:autoSizeMaxTextSize="@dimen/dp_20"
|
||||
app:autoSizeMinTextSize="@dimen/dp_12"
|
||||
app:autoSizeStepGranularity="1px"
|
||||
app:autoSizeTextType="uniform"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="1" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/iv_user_avatar"
|
||||
android:layout_width="@dimen/dp_46"
|
||||
android:layout_height="@dimen/dp_46"
|
||||
android:layout_marginStart="@dimen/dp_5"
|
||||
android:src="@drawable/default_avatar"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_rank"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:shapeAppearance="@style/shape_circle" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_user_avatar_border"
|
||||
android:layout_width="@dimen/dp_49"
|
||||
android:layout_height="@dimen/dp_49"
|
||||
android:layout_marginStart="@dimen/dp_2"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_user_avatar"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_user_avatar"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_user_avatar"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_user_avatar"
|
||||
tools:src="@drawable/game_result_avatar_border_top_1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_coins_bg"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/dp_22"
|
||||
android:layout_marginStart="@dimen/dp_9"
|
||||
android:background="@drawable/game_result_coins_top1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/tv_coins"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_coins"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_coins"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dp_10"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:minWidth="@dimen/dp_48"
|
||||
android:paddingStart="@dimen/dp_5"
|
||||
android:paddingEnd="@dimen/dp_6"
|
||||
android:text="0"
|
||||
android:textColor="#FFE829"
|
||||
android:textSize="@dimen/dp_15"
|
||||
app:autoSizeMaxTextSize="@dimen/dp_15"
|
||||
app:autoSizeMinTextSize="@dimen/dp_10"
|
||||
app:autoSizeStepGranularity="1px"
|
||||
app:autoSizeTextType="uniform"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_coins"
|
||||
android:layout_width="@dimen/dp_24"
|
||||
android:layout_height="@dimen/dp_24"
|
||||
android:src="@drawable/game_ic_coins"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_coins"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_8"
|
||||
android:layout_marginEnd="@dimen/dp_3"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_14"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/iv_coins"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_user_avatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Name" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@@ -8,6 +8,7 @@ class GameRoomData : Serializable {
|
||||
val mgId: String? = null
|
||||
val gameRoomIcon: String? = null
|
||||
val configJson: String? = null
|
||||
val gameSelectCfg: String? = null
|
||||
val scores: MutableList<Double>? = null
|
||||
|
||||
// 匹配状态(0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败)
|
||||
|