500 lines
23 KiB
Kotlin
500 lines
23 KiB
Kotlin
package com.img.rabbit
|
||
|
||
import android.annotation.SuppressLint
|
||
import android.app.Activity
|
||
import android.os.Bundle
|
||
import android.util.Log
|
||
import androidx.activity.ComponentActivity
|
||
import androidx.activity.compose.setContent
|
||
import androidx.activity.enableEdgeToEdge
|
||
import androidx.compose.foundation.background
|
||
import androidx.compose.foundation.layout.Box
|
||
import androidx.compose.foundation.layout.fillMaxSize
|
||
import androidx.compose.material3.CircularProgressIndicator
|
||
import androidx.compose.material3.MaterialTheme
|
||
import androidx.compose.runtime.Composable
|
||
import androidx.compose.runtime.LaunchedEffect
|
||
import androidx.compose.runtime.collectAsState
|
||
import androidx.compose.runtime.getValue
|
||
import androidx.compose.runtime.mutableFloatStateOf
|
||
import androidx.compose.runtime.mutableLongStateOf
|
||
import androidx.compose.runtime.mutableStateOf
|
||
import androidx.compose.runtime.remember
|
||
import androidx.compose.runtime.rememberCoroutineScope
|
||
import androidx.compose.runtime.setValue
|
||
import androidx.compose.ui.Alignment
|
||
import androidx.compose.ui.Modifier
|
||
import androidx.compose.ui.graphics.Color
|
||
import androidx.compose.ui.platform.LocalContext
|
||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||
import androidx.lifecycle.ViewModelProvider
|
||
import androidx.lifecycle.lifecycleScope
|
||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||
import com.img.rabbit.bean.response.UniVersionEntity
|
||
import com.img.rabbit.components.CenterToast
|
||
import com.img.rabbit.components.GlobalToast
|
||
import com.img.rabbit.pages.LoadingCallback
|
||
import com.img.rabbit.pages.LoginScreen
|
||
import com.img.rabbit.pages.LoginScreenType
|
||
import com.img.rabbit.pages.MainScreen
|
||
import com.img.rabbit.pages.dialog.TipsDialog
|
||
import com.img.rabbit.pages.dialog.TipsUniMpDialog
|
||
import com.img.rabbit.pages.dialog.TipsUniMpToPageDialog
|
||
import com.img.rabbit.pages.dialog.UpdateDialog
|
||
import com.img.rabbit.pages.screen.SplashScreenContent
|
||
import com.img.rabbit.provider.storage.PreferenceUtil
|
||
import com.img.rabbit.utils.AppEventBus
|
||
import com.img.rabbit.utils.AppUpdate
|
||
import com.img.rabbit.utils.FileUtils
|
||
import com.img.rabbit.utils.GlobalEvent
|
||
import com.img.rabbit.utils.GlobalEventBus
|
||
import com.img.rabbit.utils.LoginBindEvent
|
||
import com.img.rabbit.utils.UniAppUtils
|
||
import com.img.rabbit.utils.UniAppUtils.distributeUniMp
|
||
import com.img.rabbit.utils.UpdateUtils
|
||
import com.img.rabbit.viewmodel.GeneralViewModel
|
||
import com.img.rabbit.viewmodel.LoginViewModel
|
||
import com.img.rabbit.viewmodel.ReportViewModel
|
||
import com.img.rabbit.viewmodel.SplashViewModel
|
||
import io.dcloud.feature.sdk.DCUniMPSDK
|
||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||
import kotlinx.coroutines.delay
|
||
import kotlinx.coroutines.launch
|
||
import org.json.JSONObject
|
||
|
||
class MainActivity : ComponentActivity(), LoadingCallback {
|
||
private lateinit var generalViewModel: GeneralViewModel
|
||
private var isRequestConfigJumpUniMp = true//请求完用户配置后是否跳转小程序页面
|
||
@OptIn(DelicateCoroutinesApi::class, ExperimentalPermissionsApi::class)
|
||
@SuppressLint("UnrememberedMutableState", "CoroutineCreationDuringComposition",
|
||
"SourceLockedOrientationActivity"
|
||
)
|
||
override fun onCreate(savedInstanceState: Bundle?) {
|
||
val splashScreen = installSplashScreen()
|
||
super.onCreate(savedInstanceState)
|
||
// 启用Edge-to-Edge模式(沉浸模式)
|
||
enableEdgeToEdge()
|
||
|
||
setContent {
|
||
val context = LocalContext.current
|
||
val coroutineScope = rememberCoroutineScope()
|
||
val loginViewModel: LoginViewModel = viewModel()
|
||
val splashViewModel: SplashViewModel = viewModel()
|
||
val reportViewModel:ReportViewModel = viewModel()
|
||
generalViewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(application))[GeneralViewModel::class.java]
|
||
|
||
var lastClickTime by remember { mutableLongStateOf(0L) }
|
||
|
||
// UniMp小程序资源下载更新实体
|
||
var downloadUniEntity by remember { mutableStateOf<UniVersionEntity?>(null) }
|
||
var updateUniEntity by remember { mutableStateOf<UniVersionEntity?>(null) }
|
||
|
||
// 下载更新进度(App、UniMp资源下载更新)
|
||
val progressForApp = mutableFloatStateOf(0f)
|
||
val progressForUniMpDownload = remember { mutableFloatStateOf(0f) }
|
||
val progressForUniMpUpdate = mutableFloatStateOf(0f)
|
||
// 是否开始下载App(标记下载状态)
|
||
val isDownloadingForApp = mutableStateOf(false)
|
||
// 是否开始下载UniApp更新(标记下载状态)
|
||
val isDownloadingForUniUpdate = remember { mutableStateOf(false) }
|
||
|
||
// 是否全局加载中(Progress加载框)
|
||
val isGlobalLoading by generalViewModel.isLoading.collectAsState()
|
||
// 登录提示
|
||
var showLoginDialog by remember { mutableStateOf(false) }
|
||
// 软件更新提示
|
||
var showUpdateDialog by remember { mutableStateOf(false) }
|
||
// 下载小程序资源(在跳转指定页面时,未下载资源需要提示)
|
||
var showUniDownloadDialog by remember { mutableStateOf(false) }
|
||
// 小程序资源更新提示
|
||
var showUniUpdateDialog by remember { mutableStateOf(false) }
|
||
|
||
// 是否加载splashScreen完成
|
||
val isSplashDone = remember { mutableStateOf(false) }
|
||
// 是否启动小程序完成
|
||
val isUniMpDone = remember { mutableStateOf(false) }
|
||
// 加载UniMp小程序
|
||
var isLoadingUniMp by remember { mutableStateOf(false) }
|
||
|
||
// 是否退出登录
|
||
var isLogout by remember { mutableStateOf(false) }
|
||
// 加载显示MainScreen
|
||
var showMainScreen by remember { mutableStateOf(false) }
|
||
// 延迟加载MainScreen通知
|
||
var delayLoadingMainScreen by remember { mutableStateOf(false) }
|
||
|
||
// 设置启动页显示条件
|
||
splashScreen.setKeepOnScreenCondition {
|
||
splashViewModel.isLoading.value // 当为 true 时,启动页不消失
|
||
}
|
||
|
||
//以下为流事件收集订阅
|
||
LaunchedEffect(Unit) {
|
||
GlobalEventBus.events.collect { event ->
|
||
when (event) {
|
||
// 软件更新提示
|
||
is GlobalEvent.ShowAppUpdateNotify -> {
|
||
val userConfigEntity = PreferenceUtil.getUserConfig()
|
||
if(userConfigEntity != null){
|
||
showUpdateDialog = true
|
||
}
|
||
}
|
||
// 小程序资源下载提示
|
||
is GlobalEvent.ShowUniDownloadNotify -> {
|
||
downloadUniEntity = event.entity
|
||
showUniDownloadDialog = true
|
||
}
|
||
// 小程序资源更新提示
|
||
is GlobalEvent.ShowUniUpdateNotify -> {
|
||
updateUniEntity = event.entity
|
||
showUniUpdateDialog = true
|
||
}
|
||
// 启动小程序
|
||
is GlobalEvent.StartupUniMpNotify -> {
|
||
downloadUniEntity = PreferenceUtil.getUserConfig()?.config?.uniVersionEntity?.get(2)//添加需要下载的资源
|
||
isLoadingUniMp = true//加载启动小程序(如无小程序置于自动下载,需要更新自动更新,已有小程序,直接启动)
|
||
}
|
||
// 登录提示
|
||
is GlobalEvent.ShowLoginNotify -> {
|
||
showLoginDialog = true
|
||
}
|
||
// ... 可以处理其他事件
|
||
else -> {}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理全局事件,类似与EventBus订阅
|
||
LaunchedEffect(Unit) {
|
||
AppEventBus.events.collect { event ->
|
||
when (event) {
|
||
is LoginBindEvent.Login -> {
|
||
if(!event.isLogin){
|
||
loginViewModel.reset()
|
||
isLogout = true
|
||
}else{
|
||
isLogout = false
|
||
}
|
||
isRequestConfigJumpUniMp = false
|
||
loginViewModel.requestUserConfig()
|
||
}
|
||
is LoginBindEvent.Bind -> {
|
||
isRequestConfigJumpUniMp = false
|
||
loginViewModel.requestUserConfig()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// UniMp事件监听
|
||
LaunchedEffect(Unit) {
|
||
DCUniMPSDK.getInstance().setOnUniMPEventCallBack { appid, event, data, callback ->//appid, event, data, callback ->
|
||
Log.i("MainScreen", "onUniMPEventCallBack: $event")
|
||
if("start_combo_pay" == event){
|
||
//拉起微信小程序来支付
|
||
val weixinMpOriId = JSONObject(data.toString()).optString("weixinMpOriId")
|
||
val outTradeNo = JSONObject(data.toString()).optString("outTradeNo")
|
||
UniAppUtils.startUniPay(
|
||
api = generalViewModel.api,
|
||
weixinMpOriId = weixinMpOriId,
|
||
outTradeNo = outTradeNo
|
||
)
|
||
}else if("unimp_BackPress_goMe" == event){
|
||
//这里处理切换到我的页面
|
||
coroutineScope.launch {
|
||
GlobalEventBus.emit(
|
||
GlobalEvent.JumpMineNotify)
|
||
}
|
||
UniAppUtils.getCurrentUniMp()?.closeUniMP()
|
||
}else if("unimp_BackPress_backbutton" == event){
|
||
//这里需要处理手势、虚拟返回
|
||
val currentTime = System.currentTimeMillis()
|
||
if (currentTime - lastClickTime > 2000) {
|
||
CenterToast.show("再按一次退出应用")
|
||
lastClickTime = currentTime
|
||
} else {
|
||
(context as? Activity)?.finish()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 同意隐私政策后,获取服务器时间(系统时间同步完成后获取用户配置信息,配置信息同步完成才能启动)
|
||
LaunchedEffect(generalViewModel.agreementStatus.value) {
|
||
if (generalViewModel.agreementStatus.value){
|
||
loginViewModel.setIsPolicyAgreement(true)
|
||
//获取服务器时间
|
||
generalViewModel.getServerTime()
|
||
}
|
||
}
|
||
// 系统时间同步完成,获取用户配置信息
|
||
LaunchedEffect(generalViewModel.serverTime.value) {
|
||
if (generalViewModel.serverTime.value != null){
|
||
// 获取用户配置
|
||
loginViewModel.requestUserConfig(isInitConfig = true)
|
||
}
|
||
}
|
||
// 用户配置信息获取成功,启动应用(获取用户信息)
|
||
LaunchedEffect(loginViewModel.userConfigResult.value) {
|
||
if (loginViewModel.userConfigResult.value != null){
|
||
if(isRequestConfigJumpUniMp){
|
||
if( PreferenceUtil.getUserConfig()?.config?.isUniMpOpen == true
|
||
&& PreferenceUtil.getUserConfig()?.config?.uniVersionEntity?.find { it.unimp_type == "uniapp" } != null){
|
||
downloadUniEntity = PreferenceUtil.getUserConfig()?.config?.uniVersionEntity?.get(2)//添加需要下载的资源
|
||
isLoadingUniMp = true//加载启动小程序(如无小程序置于自动下载,需要更新自动更新,已有小程序,直接启动)
|
||
}else{
|
||
isSplashDone.value = true
|
||
}
|
||
}
|
||
|
||
// 用户配置信息获取成功
|
||
loginViewModel.requestUserInfo()
|
||
loginViewModel.userConfigResult.value = null
|
||
}
|
||
}
|
||
|
||
//提示下载小程序资源(在跳转指定页面时,未下载资源需要提示)
|
||
LaunchedEffect(showUniDownloadDialog) {
|
||
if(showUniDownloadDialog) {
|
||
downloadUniEntity?.let{
|
||
UniAppUtils.dealUniMpDownloadLaunchForStartUp(
|
||
context = context,
|
||
scope = coroutineScope,
|
||
uniMp = it,
|
||
reportViewModel = reportViewModel
|
||
){ result, progress ->
|
||
when (result) {
|
||
-1 -> {
|
||
//下载失败
|
||
isUniMpDone.value = false
|
||
isSplashDone.value = true
|
||
}
|
||
1 -> {
|
||
//下载中
|
||
progressForUniMpDownload.floatValue = progress ?: 0f
|
||
}
|
||
2 -> {
|
||
//下载完成(关闭下载框)
|
||
showUniDownloadDialog = false
|
||
}
|
||
3 -> {
|
||
//启动成功
|
||
isUniMpDone.value = true
|
||
isSplashDone.value = true
|
||
}
|
||
4 -> {
|
||
//启动失败
|
||
isUniMpDone.value = false
|
||
isSplashDone.value = true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//启动小程序(资源存在并且最新则直接启动,否则执行下载后启动)
|
||
LaunchedEffect(isLoadingUniMp) {
|
||
if(isLoadingUniMp){
|
||
downloadUniEntity?.let { uniMp ->
|
||
if (UniAppUtils.isDownloadUniMp(uniMp)) {
|
||
//启动小程序资源下载
|
||
showUniDownloadDialog = true
|
||
} else {
|
||
// 执行分发逻辑(异步操作)
|
||
distributeUniMp(context, uniMp, reportViewModel) {
|
||
isUniMpDone.value = it
|
||
isSplashDone.value = true
|
||
}
|
||
}
|
||
}
|
||
isLoadingUniMp = false
|
||
}
|
||
}
|
||
//启动MainScreen(如果启动小程序则延迟2秒启动,否则直接启动主界面)
|
||
LaunchedEffect(delayLoadingMainScreen) {
|
||
if (delayLoadingMainScreen) {
|
||
delay(2000) // 延迟 2 秒
|
||
showMainScreen = true
|
||
}
|
||
}
|
||
|
||
// 页面显示逻辑
|
||
AppTheme {
|
||
//显示启动页
|
||
SplashScreenContent(splashDone = isSplashDone, generalViewModel = generalViewModel){
|
||
if(isUniMpDone.value){
|
||
//延迟加载MainScreen
|
||
delayLoadingMainScreen = true
|
||
}else{
|
||
showMainScreen = true
|
||
}
|
||
}
|
||
|
||
// 显示主界面,因为UniMp小程序启动时,要实现SplashScreen图片与小程序的UniMPSplashView无缝切换,所以延迟2秒
|
||
if (showMainScreen) {
|
||
MainScreen(
|
||
generalViewModel = generalViewModel,
|
||
loginViewModel = loginViewModel,
|
||
isUniMpDone = isUniMpDone.value
|
||
)
|
||
}
|
||
// 退出登录后,显示登录页
|
||
if(isLogout){
|
||
// 同意隐私协议政策,检验是否有一键登录权限
|
||
loginViewModel.oneKeyLoginForGeTuiSdk(context as Activity) { isAllowShowOneKeyScreen ->
|
||
if (isAllowShowOneKeyScreen) {
|
||
loginViewModel.loginScreenType.value = LoginScreenType.LOGIN_ONE_KEY
|
||
} else {
|
||
// 检验是否有一键登录权限失败,显示验证码登录
|
||
loginViewModel.loginScreenType.value = LoginScreenType.LOGIN_CAPTCHA
|
||
}
|
||
}
|
||
// 显示登录页
|
||
LoginScreen(generalViewModel = generalViewModel, loginViewModel = loginViewModel, isVisibilityBreak = false)
|
||
}
|
||
|
||
//提示登录
|
||
if(showLoginDialog){
|
||
TipsDialog(
|
||
title = "温馨提示",
|
||
content1 = "在使用我们功能之前,需要您先登录!",
|
||
content2 = null,
|
||
cancel = "取消",
|
||
confirm = "立即登录",
|
||
data = null,
|
||
onStatusChange = { status, isCancel, _ ->
|
||
if(!isCancel){
|
||
// 隐藏TabBar
|
||
generalViewModel.apply {
|
||
setNavigationBarVisible(false)
|
||
navController.navigate("login?type=${LoginViewModel.JumpLoginType.FROM_ADD.type}")
|
||
}
|
||
}
|
||
showLoginDialog = status
|
||
}
|
||
)
|
||
}
|
||
//下载小程序资源,直接显示下载进度(1、启动时进入小程序,未下载资源需要提示;2、在跳转指定页面时,未下载资源需要提示)
|
||
if(showUniDownloadDialog){
|
||
downloadUniEntity?.let {
|
||
TipsUniMpToPageDialog(
|
||
title = "下载资源",
|
||
content1 = "需要下载完资源才能运行,请稍后...",
|
||
content2 = null,
|
||
downProgress = progressForUniMpDownload
|
||
)
|
||
}
|
||
}
|
||
//提示更新小程序资源
|
||
if(showUniUpdateDialog){
|
||
updateUniEntity?.let {
|
||
TipsUniMpDialog(
|
||
title = "资源包更新",
|
||
content1 = "是否确定更新资源包",
|
||
content2 = null,
|
||
cancel = "取消",
|
||
confirm = "确定",
|
||
scope = coroutineScope,
|
||
data = it,
|
||
isStartDown = isDownloadingForUniUpdate,
|
||
downProgress = progressForUniMpUpdate,
|
||
onStatusChange = { isUpdateFinish, isCancel, data ->
|
||
if(!isUpdateFinish && !isCancel && data != null){
|
||
isDownloadingForUniUpdate.value = true
|
||
}else{
|
||
showUniUpdateDialog = false
|
||
}
|
||
}
|
||
)
|
||
}
|
||
}
|
||
//App更新提示
|
||
if(showUpdateDialog){
|
||
val versionEntity = PreferenceUtil.getUserConfig()?.config?.versionEntity
|
||
versionEntity?.let{ versionEntity->
|
||
UpdateDialog(
|
||
title = versionEntity.title,
|
||
newVersion = "V${versionEntity.version}",
|
||
desc = versionEntity.description,
|
||
url = versionEntity.url,
|
||
isForce = versionEntity.force,
|
||
isStartDown = isDownloadingForApp,
|
||
downProgress = progressForApp
|
||
){ state, isCancel, url ->
|
||
if(isCancel) {
|
||
showUpdateDialog = false
|
||
}
|
||
if(!isCancel){
|
||
isDownloadingForApp.value = true
|
||
UpdateUtils.download(
|
||
scope = coroutineScope,
|
||
url = url,
|
||
filePath = FileUtils.instance?.cacheDownLoadDir?.absolutePath?:"",
|
||
fileName = AppUpdate.getFileNameFromUrl(url),
|
||
onProgress = {progress->
|
||
progressForApp.floatValue = progress.toFloat()/100f
|
||
},
|
||
onFinish = {isSuccess, filePath ->
|
||
if(isSuccess){
|
||
filePath?.let {
|
||
UpdateUtils.install(context,it)
|
||
}
|
||
if(!versionEntity.force) {
|
||
showUpdateDialog = state
|
||
}
|
||
}
|
||
}
|
||
)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//全局加载提示
|
||
if(isGlobalLoading){
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxSize()
|
||
.background(Color.Black.copy(alpha = 0.5f))
|
||
) {
|
||
CircularProgressIndicator(
|
||
color = Color.White,
|
||
modifier = Modifier.align(Alignment.Center)
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 模拟加载过程,500毫秒后关闭启动页
|
||
LaunchedEffect(Unit) {
|
||
delay(500L)
|
||
splashViewModel.setLoading(false)
|
||
}
|
||
}
|
||
}
|
||
|
||
override fun showLoading() {
|
||
lifecycleScope.launch {
|
||
generalViewModel.setLoading(true)
|
||
}
|
||
|
||
}
|
||
|
||
override fun hideLoading() {
|
||
lifecycleScope.launch {
|
||
delay(2*1000L)
|
||
generalViewModel.setLoading(false)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Composable
|
||
private fun AppTheme(content: @Composable () -> Unit) {
|
||
// 使用Material3主题
|
||
MaterialTheme {
|
||
// 界面内容
|
||
content()
|
||
// 全局居中Toast
|
||
GlobalToast()
|
||
}
|
||
} |