From 9bba588160abbd0b12cd16cf634f7493e8f308ff Mon Sep 17 00:00:00 2001 From: SkyD666 Date: Sun, 10 Dec 2023 22:29:10 +0800 Subject: [PATCH] [fix|build] Fix issue with not catching exceptions when checking for update; add upload Mapping file for GitHub Action --- .github/workflows/pre_release.yml | 6 +++++ app/build.gradle | 6 ++--- .../com/skyd/rays/ui/activity/MainActivity.kt | 6 ++++- .../skyd/rays/ui/screen/about/AboutScreen.kt | 26 ++++++++++++++++++- .../ui/screen/about/update/UpdateDialog.kt | 22 +++++++++++++++- .../ui/screen/about/update/UpdateEvent.kt | 14 ++++++++++ .../ui/screen/about/update/UpdateIntent.kt | 2 +- .../about/update/UpdatePartialStateChange.kt | 4 +++ .../ui/screen/about/update/UpdateViewModel.kt | 24 ++++++++++++++--- app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 12 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateEvent.kt diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 2d3a0d2..f93caf0 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -56,6 +56,12 @@ jobs: with: name: Pre-Release Apk path: app/build/outputs/apk/GitHub/release/*.apk + # 上传 mapping + - name: Upload Pre-Release Mapping + uses: actions/upload-artifact@v3 + with: + name: Pre-Release Mapping + path: app/build/outputs/mapping/GitHubRelease/mapping.txt # 获取 apk 路径 - name: Get Pre-Release Apk File Path run: | diff --git a/app/build.gradle b/app/build.gradle index 48805f3..42fa9dc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,7 +22,7 @@ android { minSdk 24 targetSdk 34 versionCode 54 - versionName "2.0-alpha08" + versionName "2.0-alpha09" flavorDimensions = ["versionName"] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -164,8 +164,8 @@ dependencies { implementation "com.google.mlkit:text-recognition-chinese:$mlkit_recognition_version" implementation "com.google.mlkit:text-recognition-japanese:$mlkit_recognition_version" implementation "com.google.mlkit:text-recognition-korean:$mlkit_recognition_version" - implementation 'com.google.mlkit:image-labeling-custom:17.0.2' - implementation 'com.google.mlkit:segmentation-selfie:16.0.0-beta4' + implementation "com.google.mlkit:image-labeling-custom:17.0.2" + implementation "com.google.mlkit:segmentation-selfie:16.0.0-beta4" // TF Lite implementation 'org.tensorflow:tensorflow-lite:2.14.0' diff --git a/app/src/main/java/com/skyd/rays/ui/activity/MainActivity.kt b/app/src/main/java/com/skyd/rays/ui/activity/MainActivity.kt index b633e96..a0e229b 100644 --- a/app/src/main/java/com/skyd/rays/ui/activity/MainActivity.kt +++ b/app/src/main/java/com/skyd/rays/ui/activity/MainActivity.kt @@ -284,7 +284,11 @@ class MainActivity : AppCompatActivity() { } if (openUpdateDialog) { - UpdateDialog(silence = true, onClosed = { openUpdateDialog = false }) + UpdateDialog( + silence = true, + onClosed = { openUpdateDialog = false }, + onError = { openUpdateDialog = false }, + ) } } } diff --git a/app/src/main/java/com/skyd/rays/ui/screen/about/AboutScreen.kt b/app/src/main/java/com/skyd/rays/ui/screen/about/AboutScreen.kt index 87f2eb4..b8de5cd 100644 --- a/app/src/main/java/com/skyd/rays/ui/screen/about/AboutScreen.kt +++ b/app/src/main/java/com/skyd/rays/ui/screen/about/AboutScreen.kt @@ -38,6 +38,8 @@ import androidx.compose.material3.Icon import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults @@ -45,6 +47,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -81,6 +84,7 @@ import com.skyd.rays.ui.screen.about.license.LICENSE_SCREEN_ROUTE import com.skyd.rays.ui.screen.about.update.UpdateDialog import com.skyd.rays.util.CommonUtil import com.skyd.rays.util.CommonUtil.openBrowser +import kotlinx.coroutines.launch const val ABOUT_SCREEN_ROUTE = "aboutScreen" @@ -88,10 +92,14 @@ const val ABOUT_SCREEN_ROUTE = "aboutScreen" fun AboutScreen() { val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val navController = LocalNavController.current + val context = LocalContext.current + val scope = rememberCoroutineScope() + val snackbarHostState = remember { SnackbarHostState() } var openUpdateDialog by rememberSaveable { mutableStateOf(false) } var openSponsorDialog by rememberSaveable { mutableStateOf(false) } Scaffold( + snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, topBar = { RaysTopBar( style = RaysTopBarStyle.Large, @@ -170,8 +178,24 @@ fun AboutScreen() { } } + var isRetry by rememberSaveable { mutableStateOf(false) } + if (openUpdateDialog) { - UpdateDialog(onClosed = { openUpdateDialog = false }) + UpdateDialog( + isRetry = isRetry, + onClosed = { openUpdateDialog = false }, + onSuccess = { isRetry = false }, + onError = { msg -> + isRetry = true + openUpdateDialog = false + scope.launch { + snackbarHostState.showSnackbar( + message = context.getString(R.string.update_check_failed, msg), + withDismissAction = true, + ) + } + } + ) } } } diff --git a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateDialog.kt b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateDialog.kt index 71e547b..7508738 100644 --- a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateDialog.kt +++ b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateDialog.kt @@ -20,6 +20,7 @@ import androidx.compose.material3.LocalContentColor import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment @@ -46,12 +47,22 @@ import okhttp3.internal.toLongOrDefault @Composable fun UpdateDialog( silence: Boolean = false, + isRetry: Boolean = false, + onSuccess: () -> Unit = {}, onClosed: () -> Unit = {}, + onError: (String) -> Unit = {}, viewModel: UpdateViewModel = hiltViewModel() ) { val uiState by viewModel.viewState.collectAsStateWithLifecycle() + val uiEvent by viewModel.singleEvent.collectAsStateWithLifecycle(initialValue = null) - val dispatch = viewModel.getDispatcher(startWith = UpdateIntent.CheckUpdate) + val dispatch = viewModel.getDispatcher(startWith = UpdateIntent.CheckUpdate(isRetry = false)) + + LaunchedEffect(Unit) { + if (isRetry) { + dispatch(UpdateIntent.CheckUpdate(isRetry = true)) + } + } WaitingDialog(visible = uiState.loadingDialog && !silence) @@ -83,6 +94,15 @@ fun UpdateDialog( ) } } + + when (val event = uiEvent) { + is UpdateEvent.CheckError -> LaunchedEffect(event) { + onError(event.msg) + } + + is UpdateEvent.CheckSuccess -> onSuccess() + null -> Unit + } } @Composable diff --git a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateEvent.kt b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateEvent.kt new file mode 100644 index 0000000..b6751be --- /dev/null +++ b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateEvent.kt @@ -0,0 +1,14 @@ +package com.skyd.rays.ui.screen.about.update + +import com.skyd.rays.base.mvi.MviSingleEvent +import kotlin.random.Random + +sealed interface UpdateEvent : MviSingleEvent { + data class CheckError( + val msg: String, + private val random: Long = Random.nextLong() + System.currentTimeMillis(), + ) : UpdateEvent + + data class CheckSuccess(private val random: Long = Random.nextLong() + System.currentTimeMillis()) : + UpdateEvent +} diff --git a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateIntent.kt b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateIntent.kt index 4b3f75a..c78870e 100644 --- a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateIntent.kt +++ b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateIntent.kt @@ -4,6 +4,6 @@ import com.skyd.rays.base.mvi.MviIntent sealed interface UpdateIntent : MviIntent { data object CloseDialog : UpdateIntent - data object CheckUpdate : UpdateIntent + data class CheckUpdate(val isRetry: Boolean) : UpdateIntent data class Update(val url: String?) : UpdateIntent } \ No newline at end of file diff --git a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdatePartialStateChange.kt b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdatePartialStateChange.kt index 1d811c8..23d31c6 100644 --- a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdatePartialStateChange.kt +++ b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdatePartialStateChange.kt @@ -5,6 +5,10 @@ import com.skyd.rays.model.bean.UpdateBean internal sealed interface UpdatePartialStateChange { fun reduce(oldState: UpdateState): UpdateState + data class Error(val msg: String) : UpdatePartialStateChange { + override fun reduce(oldState: UpdateState) = oldState.copy(loadingDialog = false) + } + data object LoadingDialog : UpdatePartialStateChange { override fun reduce(oldState: UpdateState) = oldState.copy(loadingDialog = true) } diff --git a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateViewModel.kt b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateViewModel.kt index 8d8e101..bedb420 100644 --- a/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateViewModel.kt +++ b/app/src/main/java/com/skyd/rays/ui/screen/about/update/UpdateViewModel.kt @@ -2,8 +2,8 @@ package com.skyd.rays.ui.screen.about.update import androidx.lifecycle.viewModelScope import com.skyd.rays.base.mvi.AbstractMviViewModel -import com.skyd.rays.base.mvi.MviSingleEvent import com.skyd.rays.config.GITHUB_REPO +import com.skyd.rays.ext.catchMap import com.skyd.rays.ext.startWith import com.skyd.rays.model.respository.UpdateRepository import com.skyd.rays.util.CommonUtil.getAppVersionCode @@ -13,11 +13,13 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.flatMapConcat import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.take @@ -29,7 +31,7 @@ import javax.inject.Inject @HiltViewModel class UpdateViewModel @Inject constructor(private var updateRepo: UpdateRepository) : - AbstractMviViewModel() { + AbstractMviViewModel() { override val viewState: StateFlow @@ -37,12 +39,14 @@ class UpdateViewModel @Inject constructor(private var updateRepo: UpdateReposito val initialVS = UpdateState.initial() viewState = merge( - intentSharedFlow.filterIsInstance().take(1), + intentSharedFlow.filter { it is UpdateIntent.CheckUpdate && !it.isRetry }.take(1), + intentSharedFlow.filter { it is UpdateIntent.CheckUpdate && it.isRetry }, intentSharedFlow.filterNot { it is UpdateIntent.CheckUpdate } ) .shareWhileSubscribed() .toUpdatePartialStateChangeFlow() .debugLog("UpdatePartialStateChange") + .sendSingleEvent() .scan(initialVS) { vs, change -> change.reduce(vs) } .debugLog("ViewState") .stateIn( @@ -52,6 +56,19 @@ class UpdateViewModel @Inject constructor(private var updateRepo: UpdateReposito ) } + private fun Flow.sendSingleEvent(): Flow { + return onEach { change -> + val event = when (change) { + is UpdatePartialStateChange.Error -> UpdateEvent.CheckError(change.msg) + is UpdatePartialStateChange.CheckUpdate.NoUpdate, + is UpdatePartialStateChange.CheckUpdate.HasUpdate -> UpdateEvent.CheckSuccess() + + else -> return@onEach + } + sendEvent(event) + } + } + private fun SharedFlow.toUpdatePartialStateChangeFlow(): Flow { return merge( filterIsInstance().flatMapConcat { @@ -76,6 +93,7 @@ class UpdateViewModel @Inject constructor(private var updateRepo: UpdateReposito UpdatePartialStateChange.CheckUpdate.NoUpdate } }.startWith(UpdatePartialStateChange.LoadingDialog) + .catchMap { UpdatePartialStateChange.Error(it.message.orEmpty()) } }, filterIsInstance().map { intent -> diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c68d50e..ff475f6 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -184,6 +184,7 @@ 新版本:%1$s\n发布时间:%2$s\n下载数:%3$s\n 下载 忽略本次更新 + 检查更新失败:%s 创建时间 修改时间 标签数量 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index d90c7f2..10d3e4f 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -256,6 +256,7 @@ 數據 警告 忽略此更新 + 檢查更新失敗:%s UUID 關閉 檢查備份文件格式中… diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index de8e65e..a3624e6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -193,6 +193,7 @@ New version: %1$s\nPublished on: %2$s\nDownloads: %3$s\n Download Ignore this update + Check for update failed: %s Create time Modify time Number of tags