package com.img.rabbit import android.annotation.SuppressLint import android.app.Activity import android.os.Bundle 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.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.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] // UniMp小程序资源下载更新实体 var downloadUniEntity by remember { mutableStateOf(null) } var updateUniEntity by remember { mutableStateOf(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) } // 加载UniMp小程序 var isLoadingUniMp by remember { mutableStateOf(false) } // 是否退出登录 var isLogout 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 } // ... 可以处理其他事件 } } } // 处理全局事件,类似与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() } } } } LaunchedEffect(Unit) { DCUniMPSDK.getInstance().setOnUniMPEventCallBack { appid, event, data, callback ->//appid, event, data, callback -> if(event == "start_combo_pay"){ //拉起微信小程序来支付 val weixinMpOriId = JSONObject(data.toString()).optString("weixinMpOriId") val outTradeNo = JSONObject(data.toString()).optString("outTradeNo") UniAppUtils.startUniPay( api = generalViewModel.api, weixinMpOriId = weixinMpOriId, outTradeNo = outTradeNo ) } } } // 同意隐私政策后,获取服务器时间(系统时间同步完成后获取用户配置信息,配置信息同步完成才能启动) 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 -> { //下载失败 isSplashDone.value = true } 1 -> { //下载中 progressForUniMpDownload.floatValue = progress ?: 0f } 2 -> { //下载完成(关闭下载框) showUniDownloadDialog = false } 4 -> { //启动失败 isSplashDone.value = true } } } } } } LaunchedEffect(isLoadingUniMp) { if(isLoadingUniMp){ downloadUniEntity?.let { uniMp -> if (UniAppUtils.isDownloadUniMp(uniMp)) { //启动小程序资源下载 showUniDownloadDialog = true } else { // 执行分发逻辑(异步操作) distributeUniMp(context, uniMp, reportViewModel) {} } } isLoadingUniMp = false } } // 页面显示逻辑 AppTheme { SplashScreenContent(splashDone = isSplashDone, generalViewModel = generalViewModel){ 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) }else if(isSplashDone.value){ // 显示主界面 MainScreen(generalViewModel = generalViewModel, loginViewModel = loginViewModel) } } //提示登录 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() } }