From de28107287d0b40a0ef46d9067ccac531ece095f Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Fri, 8 Nov 2024 15:39:29 +0800 Subject: [PATCH] Fix(WebView): Support check WebView version --- app/build.gradle.kts | 1 + .../top/fatweb/oxygen/toolbox/MainActivity.kt | 60 +++++++++++++++++++ .../oxygen/toolbox/MainActivityViewModel.kt | 9 ++- .../userdata/OxygenPreferencesDataSource.kt | 11 +++- .../oxygen/toolbox/model/userdata/UserData.kt | 3 +- .../repository/userdata/UserDataRepository.kt | 2 + .../userdata/impl/LocalUserDataRepository.kt | 4 ++ .../oxygen/toolbox/ui/about/AboutScreen.kt | 11 ++++ .../toolbox/ui/settings/SettingsDialog.kt | 3 +- .../toolbox/data/user_preferences.proto | 1 + app/src/main/res/values-zh/strings.xml | 4 ++ app/src/main/res/values/strings.xml | 4 ++ gradle/libs.versions.toml | 6 +- 13 files changed, 113 insertions(+), 6 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6d5684e..32569c2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -192,6 +192,7 @@ dependencies { implementation(libs.lifecycle.viewmodel.compose) implementation(libs.androidx.core.splashscreen) implementation(libs.hilt.android) + implementation(libs.androidx.web.kit) ksp(libs.hilt.android) ksp(libs.hilt.compiler) implementation(libs.coil.kt) diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivity.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivity.kt index 730e274..85bbd85 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivity.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivity.kt @@ -8,6 +8,9 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.Composable @@ -16,11 +19,14 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.webkit.WebViewCompat import dagger.hilt.EntryPoint import dagger.hilt.InstallIn import dagger.hilt.android.AndroidEntryPoint @@ -86,6 +92,9 @@ class MainActivity : ComponentActivity() { LaunchedEffect(locale) { LocaleUtils.switchLocale(this@MainActivity, locale) } + UseIsFirstLaunch(viewModel) { + CheckWebView(it) + } } val darkTheme = shouldUseDarkTheme(uiState) @@ -154,6 +163,57 @@ class MainActivity : ComponentActivity() { } } +@Composable +private fun UseIsFirstLaunch(viewModel: MainActivityViewModel, callback: @Composable (ondDismiss: () -> Unit) -> Unit) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + if (!whatIsFirstLaunch(uiState)) { + return + } + + callback { + viewModel.updateIsNotFirstLaunch() + } +} + +@Composable +private fun whatIsFirstLaunch(uiState: MainActivityUiState): Boolean = + when (uiState) { + MainActivityUiState.Loading -> false + is MainActivityUiState.Success -> + !uiState.userData.isNotFirstLaunch + } + +@Composable +private fun CheckWebView(onDismiss: () -> Unit) { + val versionName = WebViewCompat.getCurrentWebViewPackage(LocalContext.current)?.versionName + if (versionName == null) { + AlertDialog( + onDismissRequest = onDismiss, + title = {Text(text = stringResource(R.string.core_web_view_warning))}, + text = { Text(text = stringResource(R.string.core_cannot_load_web_view_version)) }, + confirmButton = { + TextButton(onClick = onDismiss) { + Text(text = stringResource(R.string.core_dismiss)) + } + } + ) + return + } + if (versionName.split(".").first().toInt() < 80) { + AlertDialog( + onDismissRequest = onDismiss, + title = {Text(text = stringResource(R.string.core_web_view_warning))}, + text = { Text(text = stringResource(R.string.core_web_view_version_too_low)) }, + confirmButton = { + TextButton(onClick = onDismiss) { + Text(text = stringResource(R.string.core_dismiss)) + } + } + ) + return + } +} + @Composable private fun shouldUseDarkTheme(uiState: MainActivityUiState): Boolean = when (uiState) { diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivityViewModel.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivityViewModel.kt index 524b7b8..6c99c8f 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivityViewModel.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/MainActivityViewModel.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn + import kotlinx.coroutines.launch import top.fatweb.oxygen.toolbox.model.userdata.UserData import top.fatweb.oxygen.toolbox.repository.userdata.UserDataRepository import javax.inject.Inject @@ -14,7 +15,7 @@ import kotlin.time.Duration.Companion.seconds @HiltViewModel class MainActivityViewModel @Inject constructor( - userDataRepository: UserDataRepository + private val userDataRepository: UserDataRepository ) : ViewModel() { val uiState: StateFlow = userDataRepository.userData.map { MainActivityUiState.Success(it) @@ -23,6 +24,12 @@ class MainActivityViewModel @Inject constructor( initialValue = MainActivityUiState.Loading, started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5.seconds.inWholeMilliseconds) ) + + fun updateIsNotFirstLaunch() { + viewModelScope.launch { + userDataRepository.updateIsNotFirstLaunch() + } + } } sealed interface MainActivityUiState { diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/userdata/OxygenPreferencesDataSource.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/userdata/OxygenPreferencesDataSource.kt index 491c38a..34e8df5 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/userdata/OxygenPreferencesDataSource.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/data/userdata/OxygenPreferencesDataSource.kt @@ -69,7 +69,8 @@ class OxygenPreferencesDataSource @Inject constructor( DarkThemeConfigProto.DARK_THEME_CONFIG_DARK -> DarkThemeConfig.Dark }, - useDynamicColor = it.useDynamicColor + useDynamicColor = it.useDynamicColor, + isNotFirstLaunch = it.isNotFirstLaunch ) } @@ -126,4 +127,12 @@ class OxygenPreferencesDataSource @Inject constructor( } } } + + suspend fun updateIsNotFirstLaunch() { + userPreferences.updateData { + it.copy { + this.isNotFirstLaunch = true + } + } + } } diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/userdata/UserData.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/userdata/UserData.kt index f169ddd..3a9f01e 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/userdata/UserData.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/model/userdata/UserData.kt @@ -5,5 +5,6 @@ data class UserData( val launchPageConfig: LaunchPageConfig, val themeBrandConfig: ThemeBrandConfig, val darkThemeConfig: DarkThemeConfig, - val useDynamicColor: Boolean + val useDynamicColor: Boolean, + val isNotFirstLaunch: Boolean ) diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/UserDataRepository.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/UserDataRepository.kt index 5680534..3eff393 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/UserDataRepository.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/UserDataRepository.kt @@ -19,4 +19,6 @@ interface UserDataRepository { suspend fun setDarkThemeConfig(darkThemeConfig: DarkThemeConfig) suspend fun setUseDynamicColor(useDynamicColor: Boolean) + + suspend fun updateIsNotFirstLaunch() } diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/impl/LocalUserDataRepository.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/impl/LocalUserDataRepository.kt index 72339b4..396d12a 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/impl/LocalUserDataRepository.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/repository/userdata/impl/LocalUserDataRepository.kt @@ -35,4 +35,8 @@ internal class LocalUserDataRepository @Inject constructor( override suspend fun setUseDynamicColor(useDynamicColor: Boolean) { oxygenPreferencesDataSource.setUseDynamicColor(useDynamicColor) } + + override suspend fun updateIsNotFirstLaunch() { + oxygenPreferencesDataSource.updateIsNotFirstLaunch() + } } diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/about/AboutScreen.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/about/AboutScreen.kt index 1c838e6..2134100 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/about/AboutScreen.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/about/AboutScreen.kt @@ -43,6 +43,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.webkit.WebViewCompat import kotlinx.coroutines.delay import top.fatweb.oxygen.toolbox.R import top.fatweb.oxygen.toolbox.icon.OxygenIcons @@ -126,6 +127,7 @@ internal fun AboutScreen( private fun AboutAppInfo( modifier: Modifier = Modifier ) { + val context = LocalContext.current val logo = AnimatedImageVector.animatedVectorResource(R.drawable.ic_launcher) var atEnd by remember { mutableStateOf(false) } LaunchedEffect(Unit) { @@ -169,6 +171,15 @@ private fun AboutAppInfo( ) })" ) + Text( + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.outline, + text = "WebView: ${ + WebViewCompat.getCurrentWebViewPackage(context)?.versionName ?: stringResource( + R.string.core_unknown + ) + }" + ) } } diff --git a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/settings/SettingsDialog.kt b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/settings/SettingsDialog.kt index 75958d0..ddeb126 100644 --- a/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/settings/SettingsDialog.kt +++ b/app/src/main/kotlin/top/fatweb/oxygen/toolbox/ui/settings/SettingsDialog.kt @@ -271,7 +271,8 @@ private fun SettingDialogPreview() { launchPageConfig = LaunchPageConfig.Tools, themeBrandConfig = ThemeBrandConfig.Default, darkThemeConfig = DarkThemeConfig.FollowSystem, - useDynamicColor = true + useDynamicColor = true, + isNotFirstLaunch = true ) ), onChangeLanguageConfig = {}, diff --git a/app/src/main/proto/com/fatweb/oxygen/toolbox/data/user_preferences.proto b/app/src/main/proto/com/fatweb/oxygen/toolbox/data/user_preferences.proto index 7ea1577..5797706 100644 --- a/app/src/main/proto/com/fatweb/oxygen/toolbox/data/user_preferences.proto +++ b/app/src/main/proto/com/fatweb/oxygen/toolbox/data/user_preferences.proto @@ -14,4 +14,5 @@ message UserPreferences { ThemeBrandConfigProto theme_brand_config = 3; DarkThemeConfigProto dark_theme_config = 4; bool use_dynamic_color = 5; + bool is_not_first_launch = 6; } \ No newline at end of file diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index ca52924..cbcea8d 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -26,6 +26,7 @@ 取消收藏 取消 撤消 + 忽略 空空如也 未找到相关内容 选择一个文件 @@ -33,6 +34,9 @@ 选择一个文本文件 选择文本文件 只能下载 HTTP/HTTPS URI:%1$s + ⚠️ WebView 警告 ⚠️ + 无法获取 WebView 版本信息,WebView 版本过低可能会导致工具使用异常,请知悉。 + 当前 WebView 版本过低,可能会导致工具使用异常,请知悉。 商店 重试 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5189579..d437bf4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,6 +25,7 @@ Unstar Cancel Undo + Dismiss Nothing Nothing found Select a file @@ -32,6 +33,9 @@ Select a text file Select text files Can only download HTTP/HTTPS URIs: %1$s + ⚠️ WebView warning ⚠️ + The WebView version information cannot be obtained. If the WebView version is too low, it may cause abnormal tool usage. Please be informed. + The current WebView version is too low, which may cause abnormal use of the tool. Please be informed. Store try again diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c552f65..04be50f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agp = "8.7.2" -kotlin = "2.0.20" +kotlin = "2.0.21" ksp = "2.0.20-1.0.25" aboutlibraries = "11.2.3" protobufPlugin = "0.9.4" @@ -8,7 +8,7 @@ kotlinxSerialization = "2.0.20" secrets = "2.0.1" paging = "3.3.2" -desugarJdkLibs = "2.1.2" +desugarJdkLibs = "2.1.3" composeBom = "2024.10.01" junit = "4.13.2" coreKtx = "1.15.0" @@ -19,6 +19,7 @@ activityCompose = "1.9.3" appcompat = "1.7.0" androidxLifecycle = "2.8.7" androidxCoreSplashscreen = "1.0.1" +androidxWebKit = "1.12.1" hilt = "2.52" coil = "2.7.0" kotlinxDatetime = "0.6.1" @@ -79,6 +80,7 @@ lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-ru lifecycle-runtime-testing = { group = "androidx.lifecycle", name = "lifecycle-runtime-testing", version.ref = "androidxLifecycle" } lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" } androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxCoreSplashscreen" } +androidx-web-kit = { group = "androidx.webkit", name = "webkit", version.ref = "androidxWebKit" } dagger-compiler = { group = "com.google.dagger", name = "dagger-compiler", version.ref = "hilt" } hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" }