From 0f06e04a4eb94f21aa82c4ee2c77daa9ce4214ff Mon Sep 17 00:00:00 2001 From: renhaoting <370797079@qq.com> Date: Mon, 8 Dec 2025 15:12:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=9F=BA=E7=A1=80util?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gamedog/vididin/VidiConst.kt | 1 + .../java/com/gamedog/vididin/beans/Account.kt | 1 + .../gamedog/vididin/di/GlobalInterceptor.kt | 2 + .../com/gamedog/vididin/di/NetworkModule.kt | 1 - .../gamedog/vididin/login/AccountManager.kt | 9 +- .../core/architecture/base/BaseViewModel.kt | 153 ++++++++++++++++++ .../ama/core/architecture/util/AndroidUtil.kt | 27 +++- 7 files changed, 190 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/gamedog/vididin/VidiConst.kt b/app/src/main/java/com/gamedog/vididin/VidiConst.kt index 8ce0f32..b25b204 100644 --- a/app/src/main/java/com/gamedog/vididin/VidiConst.kt +++ b/app/src/main/java/com/gamedog/vididin/VidiConst.kt @@ -14,6 +14,7 @@ object VidiConst { const val URL_YOUTUBE_API = "https://vd.rsappinc.com" + const val URL_ZERO_BUY: String = "https://jt.3idiotstudio.com" diff --git a/app/src/main/java/com/gamedog/vididin/beans/Account.kt b/app/src/main/java/com/gamedog/vididin/beans/Account.kt index 47c5fd4..eb4c5cf 100644 --- a/app/src/main/java/com/gamedog/vididin/beans/Account.kt +++ b/app/src/main/java/com/gamedog/vididin/beans/Account.kt @@ -2,6 +2,7 @@ package com.gamedog.vididin.beans data class Account( + var userId: Int = 0, val accountId: String, val deviceUUId: String, val token: String="", diff --git a/app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt b/app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt index 0b53cfe..80e96f5 100644 --- a/app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt +++ b/app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt @@ -2,6 +2,7 @@ package com.gamedog.vididin.core.network.di import android.util.Log +import com.ama.core.architecture.util.DeviceUtil import com.gamedog.vididin.request.RequestUtil import okhttp3.Headers import okhttp3.Interceptor @@ -44,6 +45,7 @@ class GlobalInterceptor : Interceptor { .add("ApplicationId", RequestUtil.Request_APPId) .add("Timestamp", timeSec.toString()) .add("Sign", RequestUtil.getRequestSign(timeSec)) + .add("DeviceId", DeviceUtil.generateDeviceId()) diff --git a/app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt b/app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt index 9fc13d7..6d79ef2 100644 --- a/app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt +++ b/app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt @@ -45,7 +45,6 @@ internal object NetworkModule { @Provides @Singleton fun providesRetrofit( - networkJson: Json, okhttpCallFactory: dagger.Lazy, ): Retrofit { return Retrofit.Builder() diff --git a/app/src/main/java/com/gamedog/vididin/login/AccountManager.kt b/app/src/main/java/com/gamedog/vididin/login/AccountManager.kt index c6a7981..cb89365 100644 --- a/app/src/main/java/com/gamedog/vididin/login/AccountManager.kt +++ b/app/src/main/java/com/gamedog/vididin/login/AccountManager.kt @@ -9,9 +9,7 @@ import com.gamedog.vididin.VidiConst import com.gamedog.vididin.VididinEvents import com.gamedog.vididin.beans.Account import com.gamedog.vididin.beans.BankInfo -import com.gamedog.vididin.main.fragments.task.TaskBean import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock object AccountManager { @@ -105,5 +103,12 @@ object AccountManager { return false } + fun saveUserIdInfo(userId: Int) { + mAccount?.let { + it.userId = userId + saveAccountInfo() + } + } + } diff --git a/core/architecture/src/main/java/com/ama/core/architecture/base/BaseViewModel.kt b/core/architecture/src/main/java/com/ama/core/architecture/base/BaseViewModel.kt index acf7d2d..0839497 100644 --- a/core/architecture/src/main/java/com/ama/core/architecture/base/BaseViewModel.kt +++ b/core/architecture/src/main/java/com/ama/core/architecture/base/BaseViewModel.kt @@ -1,5 +1,6 @@ package com.ama.core.architecture.base +import android.view.View import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ama.core.architecture.interfaces.LoadStateUiStateOwner @@ -8,10 +9,13 @@ import com.ama.core.architecture.message.MessageController import com.ama.core.architecture.message.MessageDisplayManager import com.ama.core.architecture.message.controller.DefaultMessageController import com.ama.core.architecture.stateview.LoadStateUiState +import com.ama.core.architecture.stateview.isNormalException +import com.ama.core.architecture.util.toErrorMessage import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch abstract class BaseViewModel : ViewModel(), UiStateOwner, LoadStateUiStateOwner, @@ -31,4 +35,153 @@ abstract class BaseViewModel : ViewModel(), UiStateOwner, ) } + fun requestAsync(asyncFun: suspend () -> Unit) { + // 效果说明:不隐藏内容,仅展示加载中,加载失败改为展示消息提示(普通异常)。 + requestAsyncSingleOnlyHint( + errorCallback = { + // 网络规则提示消息用于UI展示,普通异常消息用于消息提示(如:Toast),其它状态不显示。 + if (error.isNormalException()) { + // 普通异常消息用于消息提示 + showMessage(error.toErrorMessage()) + } + }, + asyncFun = asyncFun + ) + } +} + + + + +private fun BaseViewModel<*>.requestAsyncBase( + // 默认值,用于统一修改下面状态的默认值。 + isShowContentLayoutAllStateDefault: Boolean?, + isShowStateViewAllStateDefault: Boolean, + // loading + isShowContentLayoutLoading: Boolean? = isShowContentLayoutAllStateDefault, + isShowStateViewLoading: Boolean = isShowStateViewAllStateDefault, + isStateViewLoadingDialog: Boolean = false, + loadingCallback: (LoadStateUiState.Loading.() -> Unit)? = null, + // error + isShowContentLayoutError: Boolean? = isShowContentLayoutAllStateDefault, + isShowStateViewError: Boolean = isShowStateViewAllStateDefault, + errorCallback: (LoadStateUiState.Error.() -> Unit)? = null, + // empty + isShowContentLayoutEmpty: Boolean? = isShowContentLayoutAllStateDefault, + isSuccessEmpty: Data.() -> Boolean = { false }, // 判断Success下什么情况下为空,默认不支持为空。 + isShowStateViewEmpty: Boolean = isShowStateViewAllStateDefault, + emptyCallback: (LoadStateUiState.Empty.() -> Unit)? = null, + // success + successCallback: (LoadStateUiState.Success.() -> Unit)? = null, + + // asyncFun + asyncFun: suspend () -> Data, +) { + viewModelScope.launch { + // Loading + val loading = + LoadStateUiState.Loading( + isShowContentLayoutLoading, + isShowStateViewLoading, + isStateViewLoadingDialog + ) + loadStateUiState.value = loading + loadingCallback?.invoke(loading) + try { + val data = asyncFun() + if (isSuccessEmpty(data)) { + // Empty + val empty = LoadStateUiState.Empty(isShowContentLayoutEmpty, isShowStateViewEmpty) + loadStateUiState.value = empty + emptyCallback?.invoke(empty) + } else { + // Success + // 加载成功,一定要显示内容布局、显示StateView-Success,防止其它操控loadStateUiState的设置了隐藏内容布局。 + val success = + LoadStateUiState.Success(isShowContentLayout = true, isShowStateView = true) + loadStateUiState.value = success + successCallback?.invoke(success) + } + } catch (e: Exception) { + e.printStackTrace() + // Error + // 重试 + val retry: (v: View) -> Unit = { + requestAsyncBase( + isShowContentLayoutAllStateDefault, + isShowStateViewAllStateDefault, + // loading + isShowContentLayoutLoading, + isShowStateViewLoading, + isStateViewLoadingDialog, + loadingCallback, + // error + isShowContentLayoutError, + isShowStateViewError, + errorCallback, + // empty + isShowContentLayoutEmpty, + isSuccessEmpty, + isShowStateViewEmpty, + emptyCallback, + // success + successCallback, + // asyncFun + asyncFun + ) + } + val error = + LoadStateUiState.Error(isShowContentLayoutError, isShowStateViewError, e, retry) + loadStateUiState.value = error + errorCallback?.invoke(error) + } + } +} + +/** + * 请求异步-单网络-仅提示。即:内容布局全部显示,StateView仅展示加载中,加载失败默认改为展示消息提示。 + */ +fun BaseViewModel<*>.requestAsyncSingleOnlyHint( + errorCallback: (LoadStateUiState.Error.() -> Unit)? = null, + asyncFun: suspend () -> Data, +) { + if (loadStateUiState.value is LoadStateUiState.Loading) { + // 网络请求中,直接返回。 + return + } + // 效果说明:不隐藏内容,仅展示加载中,加载失败改为展示消息提示。 + requestAsyncBase( + // 所有状态默认显示内容布局 + isShowContentLayoutAllStateDefault = true, + // 所有状态默认不显示StateView(Loading除外,下面设置) + isShowStateViewAllStateDefault = false, + // 设置显示StateView-Loading + isShowStateViewLoading = true, + // 设置显示StateView-Error,改为定制(先用参数的,然后再用自己的消息提示) + errorCallback = errorCallback ?: { showMessage(kotlin.error("").toString()) }, + // 请求 + asyncFun = asyncFun + ) +} + +/** + * 请求异步-单网络-展示所有状态。即:StateView全部显示,内容布局仅加载中、成功显示。 + */ +fun BaseViewModel<*>.requestAsyncSingleShowAllState( + asyncFun: suspend () -> Data, +) { + if (loadStateUiState.value is LoadStateUiState.Loading) { + // 网络请求中,直接返回。 + return + } + requestAsyncBase( + // 所有状态默认不显示内容布局(Loading除外,下面设置) + isShowContentLayoutAllStateDefault = false, + // 所有状态默认显示StateView + isShowStateViewAllStateDefault = true, + // Loading,不操作内容(防止设置为true后,强制显示内容布局,导致显示闪烁)。 + isShowContentLayoutLoading = null, + // 请求 + asyncFun = asyncFun + ) } \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/util/AndroidUtil.kt b/core/architecture/src/main/java/com/ama/core/architecture/util/AndroidUtil.kt index d31eefd..e83dd04 100644 --- a/core/architecture/src/main/java/com/ama/core/architecture/util/AndroidUtil.kt +++ b/core/architecture/src/main/java/com/ama/core/architecture/util/AndroidUtil.kt @@ -10,18 +10,22 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.provider.Settings +import android.util.Base64 import android.view.View import android.widget.Toast import androidx.core.app.NotificationManagerCompat import com.ama.core.architecture.BaseApp import kotlin.random.Random import androidx.core.graphics.createBitmap +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import java.nio.charset.Charset class AndroidUtil private constructor() { companion object { - + val gson: Gson = Gson() fun genRandomInt(rangeBegin: Int, rangeEnd: Int): Int { return Random.nextInt(rangeBegin, rangeEnd) @@ -121,6 +125,27 @@ class AndroidUtil private constructor() { return bitmap } + + + inline fun json2Object(jsonString: String): T? { + return try { + val type = object : TypeToken() {}.type + gson.fromJson(jsonString, type) + } catch (e: Exception) { + e.printStackTrace() + null + } + } + + fun object2Json(obj : T) : String { + try { + return gson.toJson(obj) + } catch (e: Exception) { + e.printStackTrace() + } + return "" + } + } } \ No newline at end of file