diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt index 5e8ccae47..09266cbde 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt @@ -29,34 +29,21 @@ import com.hippo.ehviewer.AppConfig import com.hippo.ehviewer.BuildConfig import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings -import com.hippo.ehviewer.client.execute -import com.hippo.ehviewer.client.executeAndParseAs import com.hippo.ehviewer.ui.LICENSE_SCREEN import com.hippo.ehviewer.ui.LocalNavController import com.hippo.ehviewer.ui.tools.DialogState import com.hippo.ehviewer.ui.tools.rememberDialogState import com.hippo.ehviewer.ui.tools.toAnnotatedString +import com.hippo.ehviewer.updater.AppUpdater import com.hippo.ehviewer.util.ExceptionUtils import com.hippo.ehviewer.util.installPackage import eu.kanade.tachiyomi.util.lang.withUIContext -import eu.kanade.tachiyomi.util.system.logcat -import io.ktor.util.encodeBase64 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import moe.tarsin.coroutines.runSuspendCatching -import okhttp3.Request -import okio.sink -import org.json.JSONObject -import tachiyomi.data.release.GithubArtifacts -import tachiyomi.data.release.GithubCommitComparison -import tachiyomi.data.release.GithubRelease -import tachiyomi.data.release.GithubWorkflowRuns import java.io.File -import java.util.zip.ZipInputStream -private const val REPO_NAME = BuildConfig.REPO_NAME -private const val REPO_URL = "https://github.com/$REPO_NAME" -private const val API_URL = "https://api.github.com/repos/$REPO_NAME" +private const val REPO_URL = "https://github.com/${BuildConfig.REPO_NAME}" private const val RELEASE_URL = "$REPO_URL/releases" @Composable @@ -97,7 +84,7 @@ fun AboutScreen() { } } if (download) { - val file = File(AppConfig.tempDir, "tmp.apk").apply { delete() } + val file = File(AppConfig.tempDir, "update.apk").apply { delete() } downloadTo(file) withUIContext { context.installPackage(file) } } @@ -146,58 +133,11 @@ fun AboutScreen() { ) WorkPreference(title = stringResource(id = R.string.settings_about_check_for_updates)) { runSuspendCatching { - if (Settings.useCIUpdateChannel) { - val curSha = BuildConfig.COMMIT_SHA - val branch = ghRequest(API_URL).execute { - JSONObject(body.string()).getString("default_branch") + AppUpdater.checkForUpdate(true)?.run { + dialogState.showNewVersion(version, changelog) { file -> + AppUpdater.downloadUpdate(downloadLink, file) } - val workflowRunsUrl = "$API_URL/actions/workflows/ci.yml/runs?branch=$branch&per_page=1" - val workflowRun = ghRequest(workflowRunsUrl).executeAndParseAs().workflowRuns[0] - val shortSha = workflowRun.headSha.take(7) - if (shortSha != curSha) { - val artifacts = ghRequest(workflowRun.artifactsUrl).executeAndParseAs() - if (artifacts.artifacts.isNotEmpty()) { - val archiveUrl = artifacts.getDownloadLink() - val changelog = runSuspendCatching { - val commitComparisonUrl = "$API_URL/compare/$curSha...$shortSha" - val result = ghRequest(commitComparisonUrl).executeAndParseAs() - result.commits.joinToString("\n") { "${it.commit.message} (@${it.author.name})" } - }.getOrDefault(workflowRun.title) - dialogState.showNewVersion(shortSha, changelog) { file -> - ghRequest(archiveUrl).execute { - ZipInputStream(body.byteStream()).use { zip -> - zip.nextEntry - file.outputStream().use { - zip.copyTo(it) - } - } - } - } - } else { - launchSnackBar(context.getString(R.string.ci_is_running)) - } - } else { - launchSnackBar(context.getString(R.string.already_latest_ci_build)) - } - } else { - val curVersion = BuildConfig.VERSION_NAME - val releaseUrl = "$API_URL/releases/latest" - val release = ghRequest(releaseUrl).executeAndParseAs() - val latestVersion = release.version - val description = release.info - val downloadUrl = release.getDownloadLink() - if (latestVersion != curVersion) { - dialogState.showNewVersion(latestVersion, description) { file -> - ghRequest(downloadUrl).execute { - file.sink().use { - body.source().readAll(it) - } - } - } - } else { - launchSnackBar(context.getString(R.string.already_latest_release, latestVersion)) - } - } + } ?: launchSnackBar(context.getString(R.string.already_latest_version)) }.onFailure { launchSnackBar(ExceptionUtils.getReadableString(it)) } @@ -205,11 +145,3 @@ fun AboutScreen() { } } } - -private inline fun ghRequest(url: String, builder: Request.Builder.() -> Unit = {}) = Request.Builder().url(url).apply { - logcat { url } - val token = "github_" + "pat_11AXZS" + "T4A0k3TArCGakP3t_7DzUE5S" + "mr1zw8rmmzVtCeRq62" + "A4qkuDMw6YQm5ZUtHSLZ2MLI3J4VSifLXZ" - val user = "nullArrayList" - val base64 = "$user:$token".encodeBase64() - addHeader("Authorization", "Basic $base64") -}.apply(builder).build() diff --git a/app/src/main/java/com/hippo/ehviewer/updater/AppUpdater.kt b/app/src/main/java/com/hippo/ehviewer/updater/AppUpdater.kt new file mode 100644 index 000000000..4cecc1d5c --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/updater/AppUpdater.kt @@ -0,0 +1,87 @@ +package com.hippo.ehviewer.updater + +import com.hippo.ehviewer.BuildConfig +import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.client.execute +import com.hippo.ehviewer.client.executeAndParseAs +import eu.kanade.tachiyomi.util.system.logcat +import io.ktor.util.encodeBase64 +import moe.tarsin.coroutines.runSuspendCatching +import okhttp3.Request +import okio.sink +import org.json.JSONObject +import tachiyomi.data.release.GithubArtifacts +import tachiyomi.data.release.GithubCommitComparison +import tachiyomi.data.release.GithubRelease +import tachiyomi.data.release.GithubWorkflowRuns +import java.io.File +import java.util.zip.ZipInputStream + +private const val API_URL = "https://api.github.com/repos/${BuildConfig.REPO_NAME}" +private const val LATEST_RELEASE_URL = "$API_URL/releases/latest" + +object AppUpdater { + suspend fun checkForUpdate(forceCheck: Boolean = false): Release? { + if (forceCheck) { + if (Settings.useCIUpdateChannel) { + val curSha = BuildConfig.COMMIT_SHA + val branch = ghRequest(API_URL).execute { + JSONObject(body.string()).getString("default_branch") + } + val workflowRunsUrl = "$API_URL/actions/workflows/ci.yml/runs?branch=$branch&status=success&per_page=1" + val workflowRun = ghRequest(workflowRunsUrl).executeAndParseAs().workflowRuns[0] + val shortSha = workflowRun.headSha.take(7) + if (shortSha != curSha) { + val artifacts = ghRequest(workflowRun.artifactsUrl).executeAndParseAs() + val archiveUrl = artifacts.getDownloadLink() + val changelog = runSuspendCatching { + val commitComparisonUrl = "$API_URL/compare/$curSha...$shortSha" + val result = ghRequest(commitComparisonUrl).executeAndParseAs() + result.commits.joinToString("\n") { "${it.commit.message} (@${it.author.name})" } + }.getOrDefault(workflowRun.title) + return Release(shortSha, changelog, archiveUrl) + } + } else { + val curVersion = BuildConfig.VERSION_NAME + val release = ghRequest(LATEST_RELEASE_URL).executeAndParseAs() + val latestVersion = release.version + val description = release.info + val downloadUrl = release.getDownloadLink() + if (latestVersion != curVersion) { + return Release(latestVersion, description, downloadUrl) + } + } + } + return null + } + + suspend fun downloadUpdate(url: String, file: File) = + ghRequest(url).execute { + if (url.endsWith("zip")) { + ZipInputStream(body.byteStream()).use { zip -> + zip.nextEntry + file.outputStream().use { + zip.copyTo(it) + } + } + } else { + file.sink().use { + body.source().readAll(it) + } + } + } +} + +private inline fun ghRequest(url: String, builder: Request.Builder.() -> Unit = {}) = Request.Builder().url(url).apply { + logcat { url } + val token = "github_" + "pat_11AXZS" + "T4A0k3TArCGakP3t_7DzUE5S" + "mr1zw8rmmzVtCeRq62" + "A4qkuDMw6YQm5ZUtHSLZ2MLI3J4VSifLXZ" + val user = "nullArrayList" + val base64 = "$user:$token".encodeBase64() + addHeader("Authorization", "Basic $base64") +}.apply(builder).build() + +data class Release( + val version: String, + val changelog: String, + val downloadLink: String, +) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 64c4841f9..ed5952ec1 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -511,9 +511,7 @@ 账户 激进地预载缩略图 有新版本! - CI 正在运行,请稍候 - 已是最新 CI 构建 - 已是最新版本 %s + 已是最新版本 设置 重试 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d126c2b3b..841286b37 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -574,9 +574,7 @@ Account Preload thumbs aggressively New version available! - CI is still running, please wait - Already latest CI build - Already latest Release %s + Already the latest version Settings Default rotation type