mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 11:42:22 +08:00
This commit is contained in:
parent
57d92e4ce1
commit
8e3246a9a6
|
@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.debounce
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import li.songe.gkd.BuildConfig.ENABLED_UPDATE
|
||||
import li.songe.gkd.data.RawSubscription
|
||||
import li.songe.gkd.data.SubsItem
|
||||
import li.songe.gkd.db.DbSet
|
||||
|
@ -67,7 +66,7 @@ class MainViewModel : ViewModel() {
|
|||
clearCache()
|
||||
}
|
||||
|
||||
if (ENABLED_UPDATE && storeFlow.value.autoCheckAppUpdate) {
|
||||
if (BuildConfig.ENABLED_UPDATE && storeFlow.value.autoCheckAppUpdate) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
updateStatus.checkUpdate()
|
||||
|
|
|
@ -39,12 +39,13 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.ramcosta.composedestinations.navigation.navigate
|
||||
import kotlinx.coroutines.flow.update
|
||||
import li.songe.gkd.BuildConfig.ENABLED_UPDATE
|
||||
import li.songe.gkd.BuildConfig
|
||||
import li.songe.gkd.ui.component.RotatingLoadingIcon
|
||||
import li.songe.gkd.ui.component.SettingItem
|
||||
import li.songe.gkd.ui.component.TextMenu
|
||||
import li.songe.gkd.ui.component.TextSwitch
|
||||
import li.songe.gkd.ui.component.updateDialogOptions
|
||||
import li.songe.gkd.ui.component.waitResult
|
||||
import li.songe.gkd.ui.destinations.AboutPageDestination
|
||||
import li.songe.gkd.ui.destinations.AdvancedPageDestination
|
||||
import li.songe.gkd.ui.style.EmptyHeight
|
||||
|
@ -54,10 +55,12 @@ import li.songe.gkd.ui.theme.supportDynamicColor
|
|||
import li.songe.gkd.util.DarkThemeOption
|
||||
import li.songe.gkd.util.LocalMainViewModel
|
||||
import li.songe.gkd.util.LocalNavController
|
||||
import li.songe.gkd.util.UpdateChannelOption
|
||||
import li.songe.gkd.util.UpdateTimeOption
|
||||
import li.songe.gkd.util.checkUpdate
|
||||
import li.songe.gkd.util.findOption
|
||||
import li.songe.gkd.util.launchAsFn
|
||||
import li.songe.gkd.util.launchTry
|
||||
import li.songe.gkd.util.storeFlow
|
||||
import li.songe.gkd.util.throttle
|
||||
import li.songe.gkd.util.toast
|
||||
|
@ -324,15 +327,34 @@ fun useSettingsPage(): ScaffoldExt {
|
|||
storeFlow.update { s -> s.copy(updateSubsInterval = it.value) }
|
||||
}
|
||||
|
||||
if (ENABLED_UPDATE) {
|
||||
TextSwitch(name = "自动更新",
|
||||
if (BuildConfig.ENABLED_UPDATE) {
|
||||
TextSwitch(
|
||||
name = "自动更新",
|
||||
desc = "打开应用时检测新版本",
|
||||
checked = store.autoCheckAppUpdate,
|
||||
onCheckedChange = {
|
||||
storeFlow.value = store.copy(
|
||||
autoCheckAppUpdate = it
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
TextMenu(
|
||||
title = "更新渠道",
|
||||
option = UpdateChannelOption.allSubObject.findOption(store.updateChannel)
|
||||
) {
|
||||
if (it.value == UpdateChannelOption.Beta.value) {
|
||||
vm.viewModelScope.launchTry {
|
||||
mainVm.dialogFlow.waitResult(
|
||||
title = "版本渠道",
|
||||
text = "测试版本渠道更新快\n但不稳定可能存在较多BUG\n请谨慎使用",
|
||||
)
|
||||
storeFlow.update { s -> s.copy(updateChannel = it.value) }
|
||||
}
|
||||
} else {
|
||||
storeFlow.update { s -> s.copy(updateChannel = it.value) }
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
|
@ -9,8 +9,6 @@ const val FILE_UPLOAD_URL = "https://u.gkd.li/"
|
|||
const val FILE_SHORT_URL = "https://f.gkd.li/"
|
||||
const val IMPORT_BASE_URL = "https://i.gkd.li/i/"
|
||||
|
||||
const val UPDATE_URL = "https://registry.npmmirror.com/@gkd-kit/app/latest/files/index.json"
|
||||
|
||||
const val SERVER_SCRIPT_URL =
|
||||
"https://registry-direct.npmmirror.com/@gkd-kit/config/latest/files/dist/server.js"
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ val <T> Option<T>.allSubObject: Array<Option<T>>
|
|||
is DarkThemeOption -> DarkThemeOption.allSubObject
|
||||
is EnableGroupOption -> EnableGroupOption.allSubObject
|
||||
is RuleSortOption -> RuleSortOption.allSubObject
|
||||
is UpdateChannelOption -> UpdateChannelOption.allSubObject
|
||||
} as Array<Option<T>>
|
||||
|
||||
sealed class SortTypeOption(override val value: Int, override val label: String) : Option<Int> {
|
||||
|
@ -72,3 +73,20 @@ sealed class RuleSortOption(override val value: Int, override val label: String)
|
|||
val allSubObject by lazy { arrayOf(Default, ByTime, ByName) }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class UpdateChannelOption(override val value: Int, override val label: String) :
|
||||
Option<Int> {
|
||||
abstract val url: String
|
||||
|
||||
data object Stable : UpdateChannelOption(0, "稳定版") {
|
||||
override val url = "https://registry.npmmirror.com/@gkd-kit/app/latest/files/index.json"
|
||||
}
|
||||
|
||||
data object Beta : UpdateChannelOption(1, "测试版") {
|
||||
override val url = "https://registry.npmmirror.com/@gkd-kit/app-beta/latest/files/index.json"
|
||||
}
|
||||
|
||||
companion object {
|
||||
val allSubObject by lazy { arrayOf(Stable, Beta) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToString
|
||||
import li.songe.gkd.BuildConfig.ENABLED_UPDATE
|
||||
import li.songe.gkd.BuildConfig
|
||||
import li.songe.gkd.appScope
|
||||
|
||||
private inline fun <reified T> createStorageFlow(
|
||||
|
@ -48,7 +48,7 @@ data class Store(
|
|||
val httpServerPort: Int = 8888,
|
||||
val updateSubsInterval: Long = UpdateTimeOption.Everyday.value,
|
||||
val captureVolumeChange: Boolean = false,
|
||||
val autoCheckAppUpdate: Boolean = ENABLED_UPDATE,
|
||||
val autoCheckAppUpdate: Boolean = BuildConfig.ENABLED_UPDATE,
|
||||
val toastWhenClick: Boolean = true,
|
||||
val clickToast: String = "GKD",
|
||||
val autoClearMemorySubs: Boolean = true,
|
||||
|
@ -67,6 +67,7 @@ data class Store(
|
|||
val useCustomNotifText: Boolean = false,
|
||||
val customNotifText: String = "\${i}全局/\${k}应用/\${u}规则组/\${n}触发",
|
||||
val enableActivityLog: Boolean = false,
|
||||
val updateChannel: Int = if (BuildConfig.VERSION_NAME.contains("beta")) UpdateChannelOption.Beta.value else UpdateChannelOption.Stable.value,
|
||||
)
|
||||
|
||||
val storeFlow by lazy {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package li.songe.gkd.util
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
|
@ -14,8 +15,8 @@ import androidx.compose.runtime.collectAsState
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.blankj.utilcode.util.AppUtils
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.plugins.onDownload
|
||||
|
@ -31,6 +32,7 @@ import kotlinx.coroutines.withContext
|
|||
import kotlinx.serialization.Serializable
|
||||
import li.songe.gkd.BuildConfig
|
||||
import li.songe.gkd.MainViewModel
|
||||
import li.songe.gkd.app
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
|
||||
|
@ -54,9 +56,12 @@ data class VersionLog(
|
|||
class UpdateStatus {
|
||||
val checkUpdatingFlow = MutableStateFlow(false)
|
||||
val newVersionFlow = MutableStateFlow<NewVersion?>(null)
|
||||
val downloadStatusFlow = MutableStateFlow<LoadStatus<String>?>(null)
|
||||
val downloadStatusFlow = MutableStateFlow<LoadStatus<File>?>(null)
|
||||
}
|
||||
|
||||
private val UPDATE_URL: String
|
||||
get() = UpdateChannelOption.allSubObject.findOption(storeFlow.value.updateChannel).url
|
||||
|
||||
suspend fun UpdateStatus.checkUpdate(): NewVersion? {
|
||||
if (checkUpdatingFlow.value) return null
|
||||
val isAvailable = withContext(Dispatchers.IO) { NetworkUtils.isAvailable() }
|
||||
|
@ -82,7 +87,7 @@ suspend fun UpdateStatus.checkUpdate(): NewVersion? {
|
|||
private fun UpdateStatus.startDownload(viewModel: MainViewModel, newVersion: NewVersion) {
|
||||
if (downloadStatusFlow.value is LoadStatus.Loading) return
|
||||
downloadStatusFlow.value = LoadStatus.Loading(0f)
|
||||
val newApkFile = File(newVersionApkDir, "v${newVersion.versionCode}.apk")
|
||||
val newApkFile = newVersionApkDir.resolve("v${newVersion.versionCode}.apk")
|
||||
if (newApkFile.exists()) {
|
||||
newApkFile.delete()
|
||||
}
|
||||
|
@ -105,7 +110,7 @@ private fun UpdateStatus.startDownload(viewModel: MainViewModel, newVersion: New
|
|||
}.bodyAsChannel()
|
||||
if (downloadStatusFlow.value is LoadStatus.Loading) {
|
||||
channel.copyAndClose(newApkFile.writeChannel())
|
||||
downloadStatusFlow.value = LoadStatus.Success(newApkFile.absolutePath)
|
||||
downloadStatusFlow.value = LoadStatus.Success(newApkFile)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (downloadStatusFlow.value is LoadStatus.Loading) {
|
||||
|
@ -121,7 +126,7 @@ fun UpgradeDialog(status: UpdateStatus) {
|
|||
val newVersion by status.newVersionFlow.collectAsState()
|
||||
newVersion?.let { newVersionVal ->
|
||||
AlertDialog(title = {
|
||||
Text(text = "检测到新版本")
|
||||
Text(text = "新版本")
|
||||
}, text = {
|
||||
Text(text = "v${BuildConfig.VERSION_NAME} -> v${newVersionVal.versionName}\n\n${
|
||||
if (newVersionVal.versionLogs.size > 1) {
|
||||
|
@ -156,7 +161,7 @@ fun UpgradeDialog(status: UpdateStatus) {
|
|||
when (downloadStatusVal) {
|
||||
is LoadStatus.Loading -> {
|
||||
AlertDialog(
|
||||
title = { Text(text = "下载新版本中") },
|
||||
title = { Text(text = "下载中") },
|
||||
text = {
|
||||
LinearProgressIndicator(
|
||||
progress = { downloadStatusVal.progress },
|
||||
|
@ -177,7 +182,7 @@ fun UpgradeDialog(status: UpdateStatus) {
|
|||
|
||||
is LoadStatus.Failure -> {
|
||||
AlertDialog(
|
||||
title = { Text(text = "新版本下载失败") },
|
||||
title = { Text(text = "下载失败") },
|
||||
text = {
|
||||
Text(text = downloadStatusVal.exception.let {
|
||||
it.message ?: it.toString()
|
||||
|
@ -196,7 +201,10 @@ fun UpgradeDialog(status: UpdateStatus) {
|
|||
|
||||
is LoadStatus.Success -> {
|
||||
AlertDialog(
|
||||
title = { Text(text = "新版本下载完毕") },
|
||||
title = { Text(text = "下载完毕") },
|
||||
text = {
|
||||
Text(text = "可继续选择安装新版本")
|
||||
},
|
||||
onDismissRequest = {},
|
||||
dismissButton = {
|
||||
TextButton(onClick = {
|
||||
|
@ -206,9 +214,9 @@ fun UpgradeDialog(status: UpdateStatus) {
|
|||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = throttle(fn = mainVm.viewModelScope.launchAsFn {
|
||||
AppUtils.installApp(downloadStatusVal.result)
|
||||
})) {
|
||||
TextButton(onClick = throttle {
|
||||
installApk(downloadStatusVal.result)
|
||||
}) {
|
||||
Text(text = "安装")
|
||||
}
|
||||
})
|
||||
|
@ -217,14 +225,13 @@ fun UpgradeDialog(status: UpdateStatus) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private fun installApk(file: File) {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
app, "${app.packageName}.provider", file
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
app.tryStartActivity(intent)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,30 @@
|
|||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<root-path name="root" path="." />
|
||||
<paths>
|
||||
<files-path
|
||||
name="files_path"
|
||||
path="." />
|
||||
|
||||
<cache-path
|
||||
name="cache_path"
|
||||
path="." />
|
||||
|
||||
<external-path
|
||||
name="external_path"
|
||||
path="." />
|
||||
|
||||
<external-files-path
|
||||
name="external_files_path"
|
||||
path="." />
|
||||
|
||||
<external-cache-path
|
||||
name="external_cache_path"
|
||||
path="." />
|
||||
|
||||
<external-media-path
|
||||
name="external_media_path"
|
||||
path="." />
|
||||
|
||||
<root-path
|
||||
name="root"
|
||||
path="." />
|
||||
</paths>
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user