feat:初步实现购买游戏接口(待完整联调)
feat:完善游戏房UI feat:初步实现游戏引擎功能
This commit is contained in:
@@ -11,6 +11,7 @@ import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_ROOM_
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -33,6 +34,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
@@ -1357,18 +1359,35 @@ public class AVRoomActivity extends BaseMvpActivity<IAvRoomView, AvRoomPresenter
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FragmentManager getFragmentManager() {
|
||||
return super.getFragmentManager();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RoomContext getRoomContext() {
|
||||
return AudioRoomContext.Companion.get();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public LiveData<? extends RoomContext> getRoomContextLiveData() {
|
||||
return AudioRoomContext.Companion.getContextLiveData();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public LifecycleOwner getLifecycleOwner() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public androidx.fragment.app.FragmentManager getViewFragmentManager() {
|
||||
return getSupportFragmentManager();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RoomWidget findWidget(@NonNull String name) {
|
||||
|
@@ -23,8 +23,10 @@ import android.widget.TextView
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.withResumed
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -1460,6 +1462,10 @@ open class BaseRoomFragment<V : IBaseRoomView?, P1 : BaseRoomPresenter<V>?> :
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getViewFragmentManager(): FragmentManager {
|
||||
return activity?.supportFragmentManager ?: childFragmentManager
|
||||
}
|
||||
|
||||
override fun findWidget(name: String): RoomWidget? {
|
||||
return widgets[name]
|
||||
}
|
||||
@@ -1468,6 +1474,10 @@ open class BaseRoomFragment<V : IBaseRoomView?, P1 : BaseRoomPresenter<V>?> :
|
||||
return AudioRoomContext.get()
|
||||
}
|
||||
|
||||
override fun getRoomContextLiveData(): LiveData<out RoomContext?> {
|
||||
return AudioRoomContext.contextLiveData
|
||||
}
|
||||
|
||||
open fun initWidget() {
|
||||
publicChatMessageWidget?.let {
|
||||
registerWidget(PublicChatRoomMessageWidget::class.java.simpleName, it)
|
||||
|
@@ -9,8 +9,8 @@ import com.chwl.app.BuildConfig;
|
||||
|
||||
public class AppConfig {
|
||||
|
||||
protected static final String APP_ID = "1578948593831571457";
|
||||
protected static final String APP_KEY = "J9lHOXvFWkAZiTfl4SK7IGt0wDnW3fWd";
|
||||
protected static boolean isTestEnv = BuildConfig.DEBUG;
|
||||
public static final String APP_ID = "1578948593831571457";
|
||||
public static final String APP_KEY = "J9lHOXvFWkAZiTfl4SK7IGt0wDnW3fWd";
|
||||
public static boolean isTestEnv = BuildConfig.DEBUG;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,93 @@
|
||||
package com.chwl.app.game.core
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.activity.viewModels
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.chwl.app.base.BaseViewBindingActivity
|
||||
import com.chwl.app.game.core.engine.GameEngineViewModel
|
||||
import com.chwl.app.game.ui.game.GameViewModel
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import com.chwl.core.support.room.RoomView
|
||||
import com.chwl.core.support.room.RoomWidget
|
||||
import com.netease.nim.uikit.StatusBarUtil
|
||||
|
||||
abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(), RoomView {
|
||||
|
||||
protected val viewModel: GameViewModel by viewModels()
|
||||
protected val gameViewModel: GameEngineViewModel by viewModels()
|
||||
protected var widgets: HashMap<String, RoomWidget> = HashMap()
|
||||
|
||||
override fun init() {
|
||||
initView()
|
||||
initEvent()
|
||||
initObserver()
|
||||
initWidgets()
|
||||
}
|
||||
|
||||
protected open fun initView() {
|
||||
}
|
||||
|
||||
protected open fun initEvent() {
|
||||
}
|
||||
|
||||
protected open fun initObserver() {
|
||||
}
|
||||
|
||||
protected open fun initWidgets() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册组件
|
||||
*/
|
||||
protected open fun registerWidget(name: String, widget: RoomWidget) {
|
||||
widgets.put(name, widget)
|
||||
widget.onStart(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消注册组件
|
||||
*/
|
||||
protected open fun unregisterWidgets() {
|
||||
widgets.values.forEach {
|
||||
it.onStop()
|
||||
}
|
||||
widgets.clear()
|
||||
}
|
||||
|
||||
override fun needSteepStateBar(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun setStatusBar() {
|
||||
super.setStatusBar()
|
||||
StatusBarUtil.transparencyBar(this)
|
||||
}
|
||||
|
||||
override fun getLifecycleOwner(): LifecycleOwner {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getActivity(): Activity? {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getRoomContext(): RoomContext? {
|
||||
return viewModel.gameContextLiveData.value
|
||||
}
|
||||
|
||||
override fun getViewFragmentManager(): FragmentManager {
|
||||
return supportFragmentManager
|
||||
}
|
||||
|
||||
override fun getRoomContextLiveData(): LiveData<out RoomContext?> {
|
||||
return viewModel.gameContextLiveData
|
||||
}
|
||||
|
||||
override fun findWidget(name: String): RoomWidget? {
|
||||
return widgets[name]
|
||||
}
|
||||
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package com.chwl.app.game.core
|
||||
|
||||
import com.chwl.app.game.data.GameModel
|
||||
import com.chwl.app.game.data.GameModel2
|
||||
import com.chwl.core.support.room.RoomAbility
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@@ -10,7 +10,7 @@ class GameStateAbility : RoomAbility() {
|
||||
|
||||
fun requestRoomInfo() {
|
||||
safeLaunch {
|
||||
val info = GameModel.getGameRoomInfo()
|
||||
val info = GameModel2.getGameRoomInfo()
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,206 @@
|
||||
package com.chwl.app.game.core.engine
|
||||
|
||||
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 com.chwl.app.R
|
||||
import com.chwl.app.avroom.game.AppConfig
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.core.engine.model.GameStateResponse
|
||||
import com.chwl.app.game.core.engine.model.GameViewInfoModel
|
||||
import com.chwl.app.game.core.engine.model.GameViewInfoModel.GameViewRectModel
|
||||
import com.chwl.core.auth.AuthModel
|
||||
import com.chwl.core.room.game.GameModel
|
||||
import com.chwl.core.room.game.bean.GameCfg
|
||||
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 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(), ILog, LifecycleEventObserver {
|
||||
|
||||
private var isRunning = true
|
||||
|
||||
private val gameFSMMG = GameSudFSMMG(this)
|
||||
|
||||
private val gameFSTAPP = GameSudFSTAPP(this)
|
||||
|
||||
private var lifecycle: Lifecycle? = null
|
||||
private var gameLayout: FrameLayout? = null
|
||||
private var gameViewRect: GameViewRectModel = GameViewRectModel()
|
||||
private var roomId: String = ""
|
||||
|
||||
fun init(lifecycle: Lifecycle, gameLayout: FrameLayout) {
|
||||
this.lifecycle = lifecycle
|
||||
this.gameLayout = gameLayout
|
||||
lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
fun loadGame(activity: Activity, roomId: String, gameId: Long) {
|
||||
if (!this.isRunning) {
|
||||
return
|
||||
}
|
||||
if (lifecycle == null) {
|
||||
throw IllegalStateException("未初始化")
|
||||
}
|
||||
this.roomId = roomId
|
||||
getGameCode({
|
||||
initSDK(activity, gameId, it)
|
||||
}, {
|
||||
toast(it.message)
|
||||
})
|
||||
}
|
||||
|
||||
private fun initSDK(activity: Activity, gameId: Long, code: String) {
|
||||
SudMGP.initSDK(
|
||||
activity,
|
||||
getAppId(),
|
||||
getAppKey(),
|
||||
isTestEnv(),
|
||||
object : ISudListenerInitSDK {
|
||||
override fun onSuccess() {
|
||||
loadGameSDK(activity, gameId, code)
|
||||
}
|
||||
|
||||
override fun onFailure(code: Int, errInfo: String) {
|
||||
val msg =
|
||||
activity.getString(R.string.game_failed_tips).format("$code-${errInfo}")
|
||||
toast(msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun loadGameSDK(activity: Activity, gameId: Long, code: String) {
|
||||
if (!isRunning) {
|
||||
return
|
||||
}
|
||||
val userId = AuthModel.get().currentUid.toString()
|
||||
gameFSTAPP.destroyMG()
|
||||
val iSudFSTAPP =
|
||||
SudMGP.loadMG(activity, userId, getRoomId(), code, gameId, getGameLanguage(), gameFSMMG)
|
||||
gameFSTAPP.updateSudFSTAPP(iSudFSTAPP)
|
||||
updateGameView(iSudFSTAPP.gameView)
|
||||
}
|
||||
|
||||
private fun updateGameView(view: View?) {
|
||||
gameLayout?.removeAllViews()
|
||||
if (view != null) {
|
||||
gameLayout?.addView(view)
|
||||
}
|
||||
}
|
||||
|
||||
fun setGameViewRect(rect: GameViewRectModel) {
|
||||
this.gameViewRect = rect
|
||||
}
|
||||
|
||||
private fun getGameCode(onSuccess: (String) -> Unit, onFailed: (Throwable) -> Unit) {
|
||||
addDisposable(
|
||||
GameModel.getGameCode()
|
||||
.subscribe({
|
||||
onSuccess.invoke(it.code)
|
||||
}, {
|
||||
onFailed.invoke(it)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private fun toast(message: String?) {
|
||||
if (!message.isNullOrEmpty()) {
|
||||
SingleToastUtil.showToast(message)
|
||||
}
|
||||
}
|
||||
|
||||
fun onExpireCode(handle: ISudFSMStateHandle) {
|
||||
getGameCode({
|
||||
handle.success(GameStateResponse.success().toJson())
|
||||
gameFSTAPP.updateCode(it, null)
|
||||
}, {
|
||||
logE(it)
|
||||
})
|
||||
}
|
||||
|
||||
fun onGetGameCfg(handle: ISudFSMStateHandle) {
|
||||
handle.success(JsonUtils.toJson(GameCfg()))
|
||||
}
|
||||
|
||||
fun onGetGameViewInfo(handle: ISudFSMStateHandle) {
|
||||
val gameLayout = gameLayout
|
||||
if (gameLayout == null) {
|
||||
handle.failure("gameLayout is NULL")
|
||||
return
|
||||
}
|
||||
val gameViewWidth = gameLayout.measuredWidth
|
||||
val gameViewHeight = gameLayout.measuredHeight
|
||||
if (gameViewWidth > 0 && gameViewHeight > 0) {
|
||||
notifyGameViewInfo(handle, gameViewWidth, gameViewHeight)
|
||||
return
|
||||
}
|
||||
gameLayout.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
gameLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
notifyGameViewInfo(handle, gameLayout.measuredWidth, gameLayout.measuredHeight)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun notifyGameViewInfo(handle: ISudFSMStateHandle, width: Int, height: Int) {
|
||||
val response = GameViewInfoModel()
|
||||
response.ret_code = 0
|
||||
response.view_size.width = width
|
||||
response.view_size.height = height
|
||||
response.view_game_rect = gameViewRect
|
||||
handle.success(JsonUtils.toJson(response))
|
||||
}
|
||||
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||
if (event == Lifecycle.Event.ON_DESTROY) {
|
||||
onViewDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
LanguageHelper.AR -> {
|
||||
"ar-SA"
|
||||
}
|
||||
|
||||
else -> {
|
||||
"en-US"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
onViewDestroy()
|
||||
}
|
||||
|
||||
private fun onViewDestroy() {
|
||||
isRunning = false
|
||||
lifecycle?.removeObserver(this)
|
||||
lifecycle = null
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package com.chwl.app.game.core.engine
|
||||
|
||||
import com.chwl.app.game.core.engine.model.GameStateResponse
|
||||
import com.example.lib_utils.log.ILog
|
||||
import tech.sud.mgp.core.ISudFSMMG
|
||||
import tech.sud.mgp.core.ISudFSMStateHandle
|
||||
|
||||
class GameSudFSMMG(private val engineViewModel: GameEngineViewModel) : ISudFSMMG, ILog {
|
||||
override fun onGameLog(p0: String?) {
|
||||
if (p0 != null) {
|
||||
logD(p0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGameLoadingProgress(p0: Int, p1: Int, p2: Int) {
|
||||
}
|
||||
|
||||
override fun onGameStarted() {
|
||||
}
|
||||
|
||||
override fun onGameDestroyed() {
|
||||
}
|
||||
|
||||
override fun onExpireCode(p0: ISudFSMStateHandle, p1: String?) {
|
||||
engineViewModel.onExpireCode(p0)
|
||||
}
|
||||
|
||||
override fun onGetGameViewInfo(p0: ISudFSMStateHandle, p1: String?) {
|
||||
engineViewModel.onGetGameViewInfo(p0)
|
||||
}
|
||||
|
||||
override fun onGetGameCfg(p0: ISudFSMStateHandle, p1: String?) {
|
||||
engineViewModel.onGetGameCfg(p0)
|
||||
}
|
||||
|
||||
override fun onGameStateChange(p0: ISudFSMStateHandle, p1: String?, p2: String?) {
|
||||
p0.success(GameStateResponse.success().toJson())
|
||||
}
|
||||
|
||||
override fun onPlayerStateChange(
|
||||
p0: ISudFSMStateHandle,
|
||||
p1: String?,
|
||||
p2: String?,
|
||||
p3: String?
|
||||
) {
|
||||
p0.success(GameStateResponse.success().toJson())
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
package com.chwl.app.game.core.engine
|
||||
|
||||
import tech.sud.mgp.core.ISudFSTAPP
|
||||
import tech.sud.mgp.core.ISudListenerNotifyStateChange
|
||||
|
||||
class GameSudFSTAPP(private val engineViewModel: GameEngineViewModel) {
|
||||
private var sudFSTAPP: ISudFSTAPP? = null
|
||||
|
||||
fun updateSudFSTAPP(iSudFSTAPP: ISudFSTAPP) {
|
||||
this.sudFSTAPP = iSudFSTAPP
|
||||
}
|
||||
|
||||
fun updateCode(code: String, listener: ISudListenerNotifyStateChange?) {
|
||||
this.sudFSTAPP?.updateCode(code, listener)
|
||||
}
|
||||
|
||||
fun startMG() {
|
||||
this.sudFSTAPP?.startMG()
|
||||
}
|
||||
|
||||
fun playMG() {
|
||||
this.sudFSTAPP?.playMG()
|
||||
}
|
||||
|
||||
fun pauseMG() {
|
||||
this.sudFSTAPP?.pauseMG()
|
||||
}
|
||||
|
||||
fun stopMG() {
|
||||
this.sudFSTAPP?.stopMG()
|
||||
}
|
||||
|
||||
fun destroyMG() {
|
||||
sudFSTAPP?.destroyMG()
|
||||
sudFSTAPP = null
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package com.chwl.app.game.core.engine.model
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.chwl.library.utils.json.JsonUtils
|
||||
import java.io.Serializable
|
||||
|
||||
@Keep
|
||||
data class GameStateResponse(
|
||||
var ret_code: Int = CODE_SUCCESS, // 返回码
|
||||
var ret_msg: String? = null // 返回消息
|
||||
) : Serializable {
|
||||
|
||||
fun toJson(): String {
|
||||
return JsonUtils.toJson(this)
|
||||
}
|
||||
|
||||
// 返回码,成功
|
||||
companion object {
|
||||
val CODE_SUCCESS = 0
|
||||
|
||||
fun success(): GameStateResponse {
|
||||
return GameStateResponse(CODE_SUCCESS, "success")
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright © Sud.Tech
|
||||
* https://sud.tech
|
||||
*/
|
||||
|
||||
package com.chwl.app.game.core.engine.model;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
/**
|
||||
* 游戏视图
|
||||
* 参考文档:https://docs.sud.tech/zh-CN/app/Client/API/ISudFSMMG/onGetGameViewInfo.html
|
||||
*/
|
||||
@Keep
|
||||
public class GameViewInfoModel {
|
||||
// 返回码
|
||||
public int ret_code;
|
||||
|
||||
// 返回消息
|
||||
public String ret_msg;
|
||||
|
||||
// 游戏View的大小
|
||||
public GameViewSizeModel view_size = new GameViewSizeModel();
|
||||
|
||||
// 游戏安全操作区域
|
||||
public GameViewRectModel view_game_rect = new GameViewRectModel();
|
||||
@Keep
|
||||
public static class GameViewSizeModel {
|
||||
// 游戏View的宽 (单位像素)
|
||||
public int width;
|
||||
|
||||
// 游戏View的高 (单位像素)
|
||||
public int height;
|
||||
}
|
||||
@Keep
|
||||
public static class GameViewRectModel {
|
||||
// 相对于view_size左边框偏移(单位像素)
|
||||
public int left;
|
||||
// 相对于view_size上边框偏移(单位像素)
|
||||
public int top;
|
||||
// 相对于view_size右边框偏移(单位像素)
|
||||
public int right;
|
||||
// 相对于view_size下边框偏移(单位像素)
|
||||
public int bottom;
|
||||
}
|
||||
|
||||
}
|
@@ -7,9 +7,12 @@ import com.chwl.core.bean.response.ServiceResult
|
||||
import com.chwl.core.home.bean.*
|
||||
import com.chwl.core.utils.net.launchRequest
|
||||
import com.chwl.library.net.rxnet.RxNet
|
||||
import retrofit2.http.Field
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
|
||||
object GameModel : BaseModel() {
|
||||
object GameModel2 : BaseModel() {
|
||||
|
||||
private val api = RxNet.create(Api::class.java)
|
||||
|
||||
@@ -23,6 +26,11 @@ object GameModel : BaseModel() {
|
||||
api.getGameRoomInfo()
|
||||
}
|
||||
|
||||
suspend fun startGame(gameId: String, gameMode: Int): String? =
|
||||
launchRequest {
|
||||
api.startGame(gameId, gameMode)
|
||||
}
|
||||
|
||||
private interface Api {
|
||||
/**
|
||||
* 游戏房信息
|
||||
@@ -37,6 +45,16 @@ object GameModel : BaseModel() {
|
||||
*/
|
||||
@GET("miniGame/nav/config")
|
||||
suspend fun getHomeGameConfig(): ServiceResult<GameConfigBean>
|
||||
|
||||
/**
|
||||
* 开始游戏
|
||||
*/
|
||||
@POST("/miniGame/nav/start")
|
||||
@FormUrlEncoded
|
||||
suspend fun startGame(
|
||||
@Field("mgId") mgId: String,
|
||||
@Field("gameMode") gameMode: Int
|
||||
): ServiceResult<String>
|
||||
}
|
||||
|
||||
}
|
@@ -9,4 +9,6 @@ class GameModeBean : Serializable {
|
||||
val modeIcon: String? = null
|
||||
val gameMode: Int? = null
|
||||
val scores: List<Int>? = null
|
||||
val ruleUrl: String? = null
|
||||
val modeName: String? = null
|
||||
}
|
@@ -1,9 +1,115 @@
|
||||
package com.chwl.app.game.ui.buy
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.common.widget.dialog.DialogManager
|
||||
import com.chwl.app.databinding.GameBuyDialogBinding
|
||||
import com.chwl.library.common.base.BaseDialogFragment
|
||||
import com.chwl.app.game.data.bean.GameConfigBean
|
||||
import com.chwl.app.game.data.bean.GameModeBean
|
||||
import com.chwl.app.game.ui.game.GameActivity
|
||||
import com.chwl.app.game.ui.game.GameIntent
|
||||
import com.chwl.app.game.ui.home.GameHomeViewModel
|
||||
import com.chwl.app.ui.pay.ChargeActivity
|
||||
import com.chwl.app.ui.webview.DialogWebViewActivity
|
||||
import com.chwl.core.utils.net.BalanceNotEnoughExeption
|
||||
import com.chwl.library.utils.ResUtil
|
||||
import com.chwl.library.utils.SingleToastUtil
|
||||
import com.example.lib_utils.ktx.singleClick
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class GameBuyDialog : BaseDialogFragment<GameBuyDialogBinding>() {
|
||||
class GameBuyDialog(private val gameConfig: GameConfigBean, private val gameMode: GameModeBean) :
|
||||
BottomSheetDialogFragment() {
|
||||
|
||||
private var binding: GameBuyDialogBinding? = null
|
||||
|
||||
private val viewModel: GameHomeViewModel by activityViewModels()
|
||||
|
||||
private var dialogManager: DialogManager? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
dialogManager = DialogManager(requireContext())
|
||||
initView()
|
||||
initObserver()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
binding?.tvTitle?.text = context?.getString(R.string.game_ticket_format, gameMode.modeName)
|
||||
binding?.tvCoins?.text = gameMode.ticket?.toString()
|
||||
binding?.ivHelp?.singleClick {
|
||||
DialogWebViewActivity.start(context, gameMode.ruleUrl ?: "", true)
|
||||
}
|
||||
binding?.tvStart?.singleClick {
|
||||
dialogManager?.showProgressDialog(requireContext())
|
||||
viewModel.startGame(gameConfig.mgIdStr ?: "", gameMode.gameMode ?: -1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initObserver() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.startGameFlow.collectLatest {
|
||||
dialogManager?.dismissDialog()
|
||||
if (it.isSuccess) {
|
||||
dismissAllowingStateLoss()
|
||||
val intent =
|
||||
GameIntent(1, gameConfig.mgId ?: 0L, gameMode.gameMode ?: -1)
|
||||
GameActivity.start(requireContext(), intent)
|
||||
} else {
|
||||
if (it.code == BalanceNotEnoughExeption.code) {
|
||||
showBalanceNotEnoughDialog()
|
||||
} else {
|
||||
it.message?.let { msg ->
|
||||
SingleToastUtil.showToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showBalanceNotEnoughDialog() {
|
||||
dialogManager?.showOkCancelDialog(
|
||||
ResUtil.getString(R.string.star_send_gift_balance),
|
||||
ResUtil.getString(R.string.treasure_to_charge)
|
||||
) {
|
||||
ChargeActivity.start(context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
dialogManager?.dismissDialog()
|
||||
dialogManager = null
|
||||
}
|
||||
|
||||
override fun getTheme(): Int {
|
||||
return R.style.ErbanBottomSheetDialog
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = GameBuyDialogBinding.inflate(LayoutInflater.from(context))
|
||||
return binding?.root
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
this.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,17 +2,19 @@ package com.chwl.app.game.ui.game
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.activity.viewModels
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.base.BaseViewBindingActivity
|
||||
import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener
|
||||
import com.chwl.app.databinding.GameActivityBinding
|
||||
import com.chwl.app.game.core.BaseGameActivity
|
||||
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.message.GameMessageWidget
|
||||
import com.chwl.app.game.ui.game.widgets.queue.GameQueueWidget
|
||||
import com.chwl.core.support.room.RoomView
|
||||
import com.example.lib_utils.ktx.singleClick
|
||||
import com.netease.nim.uikit.StatusBarUtil
|
||||
import com.example.lib_utils.log.ILog
|
||||
|
||||
class GameActivity : BaseViewBindingActivity<GameActivityBinding>() {
|
||||
|
||||
private val viewModel: GameViewModel by viewModels()
|
||||
private val gameViewModel: GameEngineViewModel by viewModels()
|
||||
class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
|
||||
companion object {
|
||||
fun start(context: Context, intent: GameIntent) {
|
||||
@@ -29,36 +31,60 @@ class GameActivity : BaseViewBindingActivity<GameActivityBinding>() {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
initView()
|
||||
initEvent()
|
||||
initObserver()
|
||||
super.init()
|
||||
viewModel.init(intentData)
|
||||
initGameEngine(intentData)
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
|
||||
private fun initGameEngine(intentData: GameIntent) {
|
||||
gameViewModel.init(lifecycle, binding.layoutGame)
|
||||
binding.spaceGameRect.post {
|
||||
val rect = 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}")
|
||||
gameViewModel.setGameViewRect(rect)
|
||||
gameViewModel.loadGame(this, intentData.roomId.toString(), intentData.gameId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initEvent() {
|
||||
override fun initEvent() {
|
||||
super.initEvent()
|
||||
binding.ivClose.singleClick {
|
||||
toast("close")
|
||||
finish()
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initObserver() {
|
||||
gameViewModel.gameViewLiveData.observe(this) {
|
||||
|
||||
}
|
||||
override fun initObserver() {
|
||||
super.initObserver()
|
||||
}
|
||||
|
||||
override fun needSteepStateBar(): Boolean {
|
||||
return true
|
||||
override fun initWidgets() {
|
||||
super.initWidgets()
|
||||
registerWidget(GameMessageWidget::class.java.simpleName, binding.messageWidget)
|
||||
registerWidget(GameQueueWidget::class.java.simpleName, binding.queueWidget)
|
||||
registerWidget(GameBottomWidget::class.java.simpleName, binding.bottomWidget)
|
||||
}
|
||||
|
||||
override fun setStatusBar() {
|
||||
super.setStatusBar()
|
||||
StatusBarUtil.transparencyBar(this)
|
||||
override fun onBackPressed() {
|
||||
// super.onBackPressed()
|
||||
showExitTips()
|
||||
}
|
||||
|
||||
private fun showExitTips() {
|
||||
dialogManager.showOkCancelDialog(
|
||||
getString(R.string.game_exit_tips),
|
||||
getString(R.string.layout_dialog_game_exit_04),
|
||||
getString(R.string.exit_text), object : OkCancelDialogListener {
|
||||
override fun onOk() {
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
super.onCancel()
|
||||
this@GameActivity.finish()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
package com.chwl.app.game.ui.game
|
||||
|
||||
import android.view.View
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
|
||||
class GameEngineViewModel : BaseViewModel() {
|
||||
|
||||
val gameViewLiveData = MutableLiveData<View?>()
|
||||
}
|
@@ -4,5 +4,5 @@ import androidx.annotation.Keep
|
||||
import java.io.Serializable
|
||||
|
||||
@Keep
|
||||
data class GameIntent(val roomId: Long, val gameId: String, val gameMode: String) : Serializable {
|
||||
data class GameIntent(val roomId: Long, val gameId: Long, val gameMode: Int) : Serializable {
|
||||
}
|
@@ -1,13 +1,16 @@
|
||||
package com.chwl.app.game.ui.game
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.core.GameContext
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
|
||||
class GameViewModel : BaseViewModel() {
|
||||
|
||||
private var roomContext: GameContext? = null
|
||||
val gameContextLiveData = MutableLiveData<GameContext>()
|
||||
|
||||
fun init(intent: GameIntent) {
|
||||
roomContext = GameContext(intent.roomId)
|
||||
val gameContext = GameContext(intent.roomId)
|
||||
gameContextLiveData.value = gameContext
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
package com.chwl.app.game.ui.game.input
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.common.widget.dialog.DialogManager
|
||||
import com.chwl.app.databinding.GameMessageInputDialogBinding
|
||||
import com.chwl.library.utils.SingleToastUtil
|
||||
import com.chwl.library.utils.keyboard.KeyboardUtil
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class GameMessageInputDialog :
|
||||
BottomSheetDialogFragment() {
|
||||
|
||||
private var binding: GameMessageInputDialogBinding? = null
|
||||
|
||||
private var dialogManager: DialogManager? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
dialogManager = DialogManager(requireContext())
|
||||
initView()
|
||||
initObserver()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
binding?.inputEdit?.let {
|
||||
KeyboardUtil.showKeyboardInDialog(this.dialog, it)
|
||||
}
|
||||
binding?.inputSend?.setOnClickListener {
|
||||
SingleToastUtil.showToast("SEND")
|
||||
}
|
||||
}
|
||||
|
||||
private fun initObserver() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
dialogManager?.dismissDialog()
|
||||
dialogManager = null
|
||||
}
|
||||
|
||||
override fun getTheme(): Int {
|
||||
return R.style.ErbanBottomSheetDialogDimFalse
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = GameMessageInputDialogBinding.inflate(LayoutInflater.from(context))
|
||||
return binding?.root
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
this.setCanceledOnTouchOutside(true)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.chwl.app.game.ui.game.widgets.bottom
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.databinding.GameBottomWidgetBinding
|
||||
import com.chwl.app.game.ui.game.input.GameMessageInputDialog
|
||||
import com.chwl.core.support.room.FrameLayoutRoomWidget
|
||||
|
||||
class GameBottomWidget : FrameLayoutRoomWidget {
|
||||
|
||||
private val binding: GameBottomWidgetBinding =
|
||||
DataBindingUtil.inflate(
|
||||
LayoutInflater.from(
|
||||
context
|
||||
), R.layout.game_bottom_widget, this, true
|
||||
)
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
|
||||
init {
|
||||
binding.tvInput.setOnClickListener {
|
||||
roomView?.let {
|
||||
GameMessageInputDialog().show(it.getViewFragmentManager(), "MESSAGE_INPUT")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,8 +6,7 @@ import com.chwl.app.base.BaseViewBindingFragment
|
||||
import com.chwl.app.databinding.GameHomeFragmentBinding
|
||||
import com.chwl.app.game.data.bean.GameConfigBean
|
||||
import com.chwl.app.game.ui.buy.GameBuyDialog
|
||||
import com.chwl.app.game.ui.game.GameActivity
|
||||
import com.chwl.app.game.ui.game.GameIntent
|
||||
import com.chwl.app.support.FragmentVisibleStateHelper
|
||||
import com.chwl.app.ui.pay.ChargeActivity
|
||||
import com.chwl.app.ui.utils.load
|
||||
import com.chwl.app.ui.utils.loadAvatar
|
||||
@@ -32,6 +31,9 @@ class GameHomeFragment : BaseViewBindingFragment<GameHomeFragmentBinding>(), Mai
|
||||
initView()
|
||||
initEvent()
|
||||
initObserver()
|
||||
FragmentVisibleStateHelper(this) {
|
||||
onVisibleChanged(it)
|
||||
}
|
||||
PayModel.get().refreshWalletInfo(true)
|
||||
refreshWalletInfo()
|
||||
refreshUserInfo()
|
||||
@@ -54,16 +56,22 @@ class GameHomeFragment : BaseViewBindingFragment<GameHomeFragmentBinding>(), Mai
|
||||
}
|
||||
binding.ivRank.singleClick {
|
||||
toast("RANK")
|
||||
GameActivity.start(requireContext(), GameIntent(111,"2","2"))
|
||||
}
|
||||
adapter.setOnItemClickListener { adapter, view, position ->
|
||||
toast("$position")
|
||||
GameBuyDialog().show(childFragmentManager,"GAME_BUY")
|
||||
adapter.setOnItemClickListener { _, view, position ->
|
||||
val config = viewModel.gameConfigLiveData.value?.data
|
||||
val gameMode = adapter.getItem(position)
|
||||
if (config == null || gameMode == null) {
|
||||
return@setOnItemClickListener
|
||||
}
|
||||
GameBuyDialog(config, gameMode).show(childFragmentManager, "GAME_BUY")
|
||||
}
|
||||
}
|
||||
|
||||
private fun initObserver() {
|
||||
viewModel.gameConfigLiveData.observe(this) {
|
||||
if (it == null) {
|
||||
return@observe
|
||||
}
|
||||
val configData = it.data
|
||||
if (it.isSuccess && configData != null) {
|
||||
loadGameInfo(configData)
|
||||
@@ -71,7 +79,14 @@ class GameHomeFragment : BaseViewBindingFragment<GameHomeFragmentBinding>(), Mai
|
||||
toast(it.message)
|
||||
}
|
||||
}
|
||||
viewModel.getGameList()
|
||||
}
|
||||
|
||||
private fun onVisibleChanged(isVisible: Boolean) {
|
||||
if (isVisible) {
|
||||
if (viewModel.gameConfigLiveData.value?.isSuccess != true) {
|
||||
viewModel.getGameList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadGameInfo(config: GameConfigBean) {
|
||||
|
@@ -2,19 +2,33 @@ package com.chwl.app.game.ui.home
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.data.GameModel
|
||||
import com.chwl.app.game.data.GameModel2
|
||||
import com.chwl.app.game.data.bean.GameConfigBean
|
||||
import com.chwl.core.bean.response.BeanResult
|
||||
import com.chwl.core.pay.PayModel
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
class GameHomeViewModel : BaseViewModel() {
|
||||
val gameConfigLiveData = MutableLiveData<BeanResult<GameConfigBean>>()
|
||||
val gameConfigLiveData = MutableLiveData<BeanResult<GameConfigBean>?>()
|
||||
|
||||
val startGameFlow = MutableSharedFlow<BeanResult<String>>()
|
||||
|
||||
fun getGameList() {
|
||||
safeLaunch(onError = {
|
||||
gameConfigLiveData.postValue(BeanResult.Companion.failed(it))
|
||||
}) {
|
||||
val configBean = GameModel.getHomeGameConfig()
|
||||
val configBean = GameModel2.getHomeGameConfig()
|
||||
gameConfigLiveData.postValue(BeanResult.success(configBean))
|
||||
}
|
||||
}
|
||||
|
||||
fun startGame(gameId: String, gameMode: Int) {
|
||||
safeLaunch(onError = {
|
||||
startGameFlow.emit(BeanResult.Companion.failed(it))
|
||||
}) {
|
||||
PayModel.get().refreshWalletInfo(true)
|
||||
val value = GameModel2.startGame(gameId, gameMode)
|
||||
startGameFlow.emit(BeanResult.success(value))
|
||||
}
|
||||
}
|
||||
}
|
@@ -49,18 +49,19 @@
|
||||
android:id="@+id/queue_widget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/space_title_bar" />
|
||||
android:layout_marginTop="@dimen/dp_13"
|
||||
app:layout_constraintTop_toTopOf="@id/space_title_bar" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_award_tips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-5dp"
|
||||
android:layout_marginTop="@dimen/dp_9"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_14"
|
||||
app:layout_constraintBottom_toBottomOf="@id/queue_widget"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/queue_widget"
|
||||
tools:text="@string/game_award_tips_format" />
|
||||
|
||||
<FrameLayout
|
||||
@@ -100,34 +101,25 @@
|
||||
android:src="@drawable/game_ic_coins" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<com.chwl.app.game.ui.game.widgets.message.GameMessageWidget
|
||||
android:id="@+id/message_widget"
|
||||
app:layout_constraintBottom_toTopOf="@id/layout_bottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="@dimen/dp_100"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottom_widget"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/layout_bottom"
|
||||
<com.chwl.app.game.ui.game.widgets.bottom.GameBottomWidget
|
||||
android:id="@+id/bottom_widget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_61"
|
||||
android:background="@drawable/game_bg_bottom"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_28"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="@dimen/dp_39"
|
||||
android:background="@drawable/base_shape_190b032d_14dp"
|
||||
android:gravity="center_vertical|start"
|
||||
android:paddingHorizontal="@dimen/dp_21"
|
||||
android:text="@string/room_say_something"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_10" />
|
||||
|
||||
</FrameLayout>
|
||||
<Space
|
||||
android:id="@+id/space_game_rect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/message_widget"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/queue_widget" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
29
app/src/module_game/res/layout/game_bottom_widget.xml
Normal file
29
app/src/module_game/res/layout/game_bottom_widget.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/layout_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_61"
|
||||
android:background="@drawable/game_bg_bottom">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_28"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="@dimen/dp_39"
|
||||
android:background="@drawable/base_shape_190b032d_14dp"
|
||||
android:gravity="center_vertical|start"
|
||||
android:paddingHorizontal="@dimen/dp_21"
|
||||
android:text="@string/room_say_something"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_10"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</layout>
|
@@ -25,12 +25,13 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.13"
|
||||
tools:text="Name" />
|
||||
tools:text="@string/game_ticket_format" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_help"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dp_32"
|
||||
android:layout_marginEnd="@dimen/dp_21"
|
||||
android:src="@drawable/game_buy_ic_help"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -86,6 +87,7 @@
|
||||
tools:text="0" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/game_buy_btn"
|
||||
|
37
app/src/module_game/res/layout/game_message_input_dialog.xml
Normal file
37
app/src/module_game/res/layout/game_message_input_dialog.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@android:color/white"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/input_edit"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/white"
|
||||
android:hint="@string/room_say_here"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:textColor="#888889"
|
||||
android:textColorHint="#c8c8c8"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/input_send"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="@drawable/click_white_gray_selector"
|
||||
android:scaleType="center"
|
||||
android:src="@android:drawable/ic_menu_send" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
@@ -18,6 +18,20 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@string/matchmaking" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_state"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="-4.5dp"
|
||||
android:layout_marginEnd="-4.5dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/game_ic_link"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_queue1_border"
|
||||
app:layout_constraintEnd_toStartOf="@id/iv_queue2_border"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_queue1_border"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_queue1_border"
|
||||
tools:src="@drawable/game_ic_vs" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/iv_queue1"
|
||||
android:layout_width="0dp"
|
||||
@@ -33,14 +47,14 @@
|
||||
android:id="@+id/iv_queue1_border"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/dp_30"
|
||||
android:layout_marginTop="@dimen/dp_26"
|
||||
android:src="@drawable/game_ic_queue_avatar_border"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.194"
|
||||
app:layout_constraintHorizontal_bias="0.311"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_percent="0.213" />
|
||||
app:layout_constraintWidth_percent="0.152" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/iv_queue2"
|
||||
@@ -60,23 +74,10 @@
|
||||
android:src="@drawable/game_ic_queue_avatar_border"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.805"
|
||||
app:layout_constraintHorizontal_bias="0.688"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_queue1_border"
|
||||
app:layout_constraintWidth_percent="0.213" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_state_link"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/game_ic_link"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_queue1_border"
|
||||
app:layout_constraintEnd_toStartOf="@id/iv_queue2_border"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_queue1_border"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_queue1_border"
|
||||
tools:src="@drawable/game_ic_vs" />
|
||||
|
||||
app:layout_constraintWidth_percent="0.152" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</layout>
|
@@ -3,4 +3,6 @@
|
||||
<string name="matchmaking">匹配中</string>
|
||||
<string name="game_award_tips_format">獲勝獎勵%s金幣</string>
|
||||
<string name="start">开始</string>
|
||||
<string name="game_ticket_format">入场费(%s)</string>
|
||||
<string name="game_exit_tips">遊戲已經開始,退出房間將默認遊戲失敗,確認退出房間?</string>
|
||||
</resources>
|
@@ -3,5 +3,7 @@
|
||||
|
||||
<string name="matchmaking">匹配中</string>
|
||||
<string name="game_award_tips_format">獲勝獎勵%s金幣</string>
|
||||
<string name="start">开始</string>
|
||||
<string name="start">開始</string>
|
||||
<string name="game_ticket_format">入场费(%s)</string>
|
||||
<string name="game_exit_tips">遊戲已經開始,退出房間將默認遊戲失敗,確認退出房間?</string>
|
||||
</resources>
|
@@ -3,4 +3,6 @@
|
||||
<string name="matchmaking">匹配中</string>
|
||||
<string name="game_award_tips_format">獲勝獎勵%s金幣</string>
|
||||
<string name="start">开始</string>
|
||||
<string name="game_ticket_format">入场费(%s)</string>
|
||||
<string name="game_exit_tips">遊戲已經開始,退出房間將默認遊戲失敗,確認退出房間?</string>
|
||||
</resources>
|
@@ -27,9 +27,15 @@ import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.Exception
|
||||
|
||||
open class ChatRoomClient(val sessionId: String) : ICleared, ILog {
|
||||
|
||||
private val clientScope = MainScope()
|
||||
private var isLogin = false
|
||||
private var loginData: EnterChatRoomResultData? = null
|
||||
private val messagePublishSubject: PublishSubject<List<ChatRoomMessage>> =
|
||||
@@ -39,6 +45,7 @@ open class ChatRoomClient(val sessionId: String) : ICleared, ILog {
|
||||
.toObservable()
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
val stateFlow = MutableStateFlow<StatusCode>(StatusCode.INVALID)
|
||||
|
||||
private val receiveMessageObserver = Observer<List<ChatRoomMessage>> {
|
||||
val list = it.filter { item ->
|
||||
@@ -55,6 +62,9 @@ open class ChatRoomClient(val sessionId: String) : ICleared, ILog {
|
||||
} else {
|
||||
isLogin = false
|
||||
}
|
||||
clientScope.launch {
|
||||
stateFlow.emit(it.status)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -126,8 +136,8 @@ open class ChatRoomClient(val sessionId: String) : ICleared, ILog {
|
||||
}.compose(RxHelper.handleSchedulers())
|
||||
}
|
||||
|
||||
fun exitChatRoom(sessionId: String) {
|
||||
logD("exitChatRoom() sessionId:${sessionId}")
|
||||
fun exitChatRoom() {
|
||||
logD("exitChatRoom()")
|
||||
NIMChatRoomSDK.getChatRoomService().exitChatRoom(sessionId)
|
||||
}
|
||||
|
||||
@@ -208,6 +218,11 @@ open class ChatRoomClient(val sessionId: String) : ICleared, ILog {
|
||||
ChatRoomClientManager.onClientCleared(this)
|
||||
registerReceiveMessage(false)
|
||||
registerOnlineStatus(false)
|
||||
exitChatRoom(sessionId)
|
||||
exitChatRoom()
|
||||
try {
|
||||
clientScope.cancel()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,7 +5,6 @@ import android.util.AttributeSet
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.chwl.core.utils.extension.toast
|
||||
import com.chwl.library.net.rxnet.exception.ExceptionHandle
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
@@ -64,13 +63,13 @@ abstract class FrameLayoutRoomWidget : FrameLayout, RoomWidget {
|
||||
@CallSuper
|
||||
override fun onStart(roomView: RoomView) {
|
||||
this.roomView = roomView
|
||||
AudioRoomContext.contextLiveData.observeForever(contextObserver)
|
||||
roomView.getRoomContextLiveData().observeForever(contextObserver)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onStop() {
|
||||
// 注销监听
|
||||
AudioRoomContext.contextLiveData.removeObserver(contextObserver)
|
||||
roomView?.getRoomContextLiveData()?.removeObserver(contextObserver)
|
||||
// 解绑
|
||||
onUnbindContext()
|
||||
this.roomView = null
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package com.chwl.core.support.room
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Room
|
||||
|
||||
/**
|
||||
* Created by Max on 2023/10/26 15:05
|
||||
@@ -13,6 +16,10 @@ interface RoomView {
|
||||
|
||||
fun getActivity(): Activity?
|
||||
|
||||
fun getViewFragmentManager(): FragmentManager
|
||||
|
||||
fun getRoomContextLiveData(): LiveData<out RoomContext?>
|
||||
|
||||
/**
|
||||
* 获取房间上下文
|
||||
*/
|
||||
|
@@ -7,11 +7,16 @@ import com.google.gson.Gson;
|
||||
*/
|
||||
public class JsonUtils {
|
||||
|
||||
public static Gson gson;
|
||||
|
||||
public static String toJson(Object object) {
|
||||
if (gson == null) {
|
||||
gson = new Gson();
|
||||
}
|
||||
String result = null;
|
||||
try {
|
||||
if (object != null) {
|
||||
result = new Gson().toJson(object);
|
||||
result = gson.toJson(object);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
Reference in New Issue
Block a user