版本更新提示

This commit is contained in:
2024-10-26 16:06:59 +08:00
parent fd2f1cfc1d
commit 994e493035
5 changed files with 268 additions and 22 deletions

View File

@@ -5,7 +5,7 @@ import android.content.Context
object ConstVars { object ConstVars {
// api 地址 // api 地址
// const val BASE_SERVER = "http://192.168.31.131:8088" // const val BASE_SERVER = "http://192.168.31.131:8088"
// const val BASE_SERVER = "http://192.168.142.140:8088" // const val BASE_SERVER = "http://192.168.142.141:8088"
// const val BASE_SERVER = "https://8.137.22.101:8088" // const val BASE_SERVER = "https://8.137.22.101:8088"
const val BASE_SERVER = "https://rider-pro.aiosman.com/beta_api" const val BASE_SERVER = "https://rider-pro.aiosman.com/beta_api"

View File

@@ -22,10 +22,16 @@ import androidx.annotation.RequiresApi
import androidx.compose.animation.AnimatedContentScope import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionScope import androidx.compose.animation.SharedTransitionScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
@@ -41,6 +47,7 @@ import com.aiosman.riderpro.model.ApkInstallReceiver
import com.aiosman.riderpro.model.UpdateInfo import com.aiosman.riderpro.model.UpdateInfo
import com.aiosman.riderpro.ui.Navigation import com.aiosman.riderpro.ui.Navigation
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.dialogs.CheckUpdateDialog
import com.aiosman.riderpro.ui.navigateToPost import com.aiosman.riderpro.ui.navigateToPost
import com.aiosman.riderpro.ui.post.NewPostViewModel import com.aiosman.riderpro.ui.post.NewPostViewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
@@ -85,7 +92,7 @@ class MainActivity : ComponentActivity() {
try { try {
val client = OkHttpClient() val client = OkHttpClient()
val request = Request.Builder() val request = Request.Builder()
.url("https://rider-pro.aiosman.com/beta_api/static/update/beta/version.json") .url("${ConstVars.BASE_SERVER}/static/update/beta/version.json")
.build() .build()
val response = client.newCall(request).execute() val response = client.newCall(request).execute()
@@ -97,7 +104,7 @@ class MainActivity : ComponentActivity() {
// 检查是否有新版本 // 检查是否有新版本
Log.d("MainActivity", "Current version code: $versionCode") Log.d("MainActivity", "Current version code: $versionCode")
Log.d("MainActivity", "Server version code: ${updateInfo.versionCode}") Log.d("MainActivity", "Server version code: ${updateInfo.versionCode}")
if (updateInfo.versionCode > versionCode) { if (updateInfo.versionCode > versionCode || true) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
showUpdateDialog(updateInfo) showUpdateDialog(updateInfo)
} }
@@ -156,6 +163,7 @@ class MainActivity : ComponentActivity() {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@RequiresApi(Build.VERSION_CODES.P) @RequiresApi(Build.VERSION_CODES.P)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -186,11 +194,11 @@ class MainActivity : ComponentActivity() {
} }
enableEdgeToEdge() enableEdgeToEdge()
// 注册广播接收器 // // 注册广播接收器
val intentFilter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) // val intentFilter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
registerReceiver(apkInstallReceiver, intentFilter, RECEIVER_NOT_EXPORTED) // registerReceiver(apkInstallReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
//
checkUpdate() // checkUpdate()
// 初始化腾讯云通信 SDK // 初始化腾讯云通信 SDK
@@ -206,7 +214,7 @@ class MainActivity : ComponentActivity() {
} }
setContent { setContent {
CheckUpdateDialog()
Navigation(startDestination) { navController -> Navigation(startDestination) { navController ->
// 处理带有 postId 的通知点击 // 处理带有 postId 的通知点击
val postId = intent.getStringExtra("POST_ID") val postId = intent.getStringExtra("POST_ID")

View File

@@ -20,8 +20,11 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import cn.jpush.android.cache.Sp
import com.aiosman.riderpro.AppColors import com.aiosman.riderpro.AppColors
import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.aiosman.riderpro.ui.modifiers.noRippleClickable
@@ -41,6 +44,9 @@ fun ActionButton(
disabledBackgroundColor: Color = AppColors.disabledBackground, disabledBackgroundColor: Color = AppColors.disabledBackground,
enabled: Boolean = true, enabled: Boolean = true,
fullWidth: Boolean = false, fullWidth: Boolean = false,
roundCorner: Float = 24f,
fontSize: TextUnit = 17.sp,
fontWeight: FontWeight = FontWeight.W900,
click: () -> Unit = {} click: () -> Unit = {}
) { ) {
val animatedBackgroundColor by animateColorAsState( val animatedBackgroundColor by animateColorAsState(
@@ -59,7 +65,7 @@ fun ActionButton(
) )
Box( Box(
modifier = modifier modifier = modifier
.clip(RoundedCornerShape(24.dp)) .clip(RoundedCornerShape(roundCorner.dp))
.background(animatedBackgroundColor) .background(animatedBackgroundColor)
.noRippleClickable { .noRippleClickable {
if (enabled && !isLoading) { if (enabled && !isLoading) {
@@ -94,11 +100,10 @@ fun ActionButton(
Text( Text(
text, text,
fontSize = 17.sp, fontSize = fontSize,
color = color, color = color,
fontWeight = FontWeight.W900, fontWeight = fontWeight,
textAlign = if (expandText) TextAlign.Center else TextAlign.Start textAlign = if (expandText) TextAlign.Center else TextAlign.Start
) )
} }
} else { } else {

View File

@@ -0,0 +1,233 @@
package com.aiosman.riderpro.ui.dialogs
import android.content.Intent
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
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.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.FileProvider
import com.aiosman.riderpro.AppColors
import com.aiosman.riderpro.ConstVars
import com.aiosman.riderpro.R
import com.aiosman.riderpro.model.UpdateInfo
import com.aiosman.riderpro.ui.composables.ActionButton
import com.google.firebase.perf.config.RemoteConfigManager.getVersionCode
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CheckUpdateDialog() {
val context = LocalContext.current
val scope = rememberCoroutineScope()
var showDialog by remember { mutableStateOf(false) }
var newApkUrl by remember { mutableStateOf("") }
var progress by remember { mutableStateOf(0f) }
var isDownloading by remember { mutableStateOf(false) } // Add downloading state
var message by remember { mutableStateOf("") }
var versionName by remember { mutableStateOf("") }
fun checkUpdate() {
scope.launch(Dispatchers.IO) {
try {
val client = OkHttpClient()
val request = Request.Builder()
.url("${ConstVars.BASE_SERVER}/static/update/beta/version.json")
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
val responseBody = response.body?.string()
val updateInfo = Gson().fromJson(responseBody, UpdateInfo::class.java)
val versionCode = getVersionCode(context)
if (updateInfo.versionCode > versionCode) {
withContext(Dispatchers.Main) {
message = updateInfo.updateContent
versionName = updateInfo.versionName
showDialog = true
newApkUrl = updateInfo.downloadUrl
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun downloadApk() {
isDownloading = true
scope.launch(Dispatchers.IO) {
val request = Request.Builder()
.url(newApkUrl)
.build()
val client = OkHttpClient()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw Exception("Unexpected code $response")
val body = response.body
if (body != null) {
val apkFile = File(context.cacheDir, "rider_pro.apk")
val totalBytes = body.contentLength()
var downloadedBytes = 0L
apkFile.outputStream().use { output ->
body.byteStream().use { input ->
val buffer = ByteArray(8 * 1024)
var bytesRead: Int
while (input.read(buffer).also { bytesRead = it } != -1) {
output.write(buffer, 0, bytesRead)
downloadedBytes += bytesRead
progress = downloadedBytes / totalBytes.toFloat()
}
}
}
val apkUri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", apkFile)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
context.startActivity(intent)
}
}
isDownloading = false
}
}
LaunchedEffect(Unit) {
checkUpdate()
}
if (showDialog) {
BasicAlertDialog(
onDismissRequest = {
if (!isDownloading) {
showDialog = false
}
},
modifier = Modifier,
) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(start = 24.dp, end = 24.dp, bottom = 120.dp),
) {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.TopCenter
) {
Column(
modifier = Modifier
.fillMaxWidth()
) {
Spacer(modifier = Modifier.height(96.dp))
Column(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(32.dp))
.background(AppColors.background)
.padding(vertical = 32.dp, horizontal = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(48.dp))
Text(
"New version",
fontWeight = FontWeight.W900,
fontSize = 22.sp
)
Spacer(modifier = Modifier.height(16.dp))
Text(
versionName,
modifier = Modifier.fillMaxWidth()
)
Text(
message,
modifier = Modifier.fillMaxWidth()
)
if (progress > 0) {
Spacer(modifier = Modifier.height(16.dp))
LinearProgressIndicator(
progress = { progress },
color = AppColors.main,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp)),
trackColor = AppColors.basicMain
)
}
Spacer(modifier = Modifier.height(32.dp))
Row(
modifier = Modifier.fillMaxWidth()
) {
ActionButton(
text = "Cancel",
color = AppColors.text,
backgroundColor = AppColors.basicMain,
modifier = Modifier.weight(1f),
fullWidth = false,
roundCorner = 16f,
fontSize = 14.sp,
fontWeight = FontWeight.Normal,
) {
showDialog = false
}
Spacer(modifier = Modifier.width(16.dp))
ActionButton(
text = "Update",
backgroundColor = AppColors.main,
color = AppColors.mainText,
modifier = Modifier.weight(1f),
fullWidth = false,
roundCorner = 16f,
fontSize = 14.sp,
fontWeight = FontWeight.Normal,
) {
downloadApk()
}
}
Spacer(modifier = Modifier.height(16.dp))
}
}
Image(
painter = painterResource(id = R.mipmap.rider_pro_update_header),
contentDescription = null,
modifier = Modifier.padding(16.dp)
)
}
}
}
}
}

View File

@@ -71,7 +71,7 @@ fun OtherProfileAction(
text = stringResource(if (profile.isFollowing) R.string.unfollow_upper else R.string.follow_upper), text = stringResource(if (profile.isFollowing) R.string.unfollow_upper else R.string.follow_upper),
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.W600, fontWeight = FontWeight.W600,
color = if (profile.isFollowing) AppColors.text else AppColors.mainText, color = if (profile.isFollowing) AppColors.mainText else AppColors.text,
modifier = Modifier.padding(8.dp), modifier = Modifier.padding(8.dp),
) )