mirror of
https://github.com/mihonapp/mihon.git
synced 2025-10-09 12:59:34 +02:00
Tweak the app updater logic and add FOSS build support (#1843)
This commit is contained in:
@@ -123,7 +123,7 @@ object AboutScreen : Screen() {
|
|||||||
versionName = result.release.version,
|
versionName = result.release.version,
|
||||||
changelogInfo = result.release.info,
|
changelogInfo = result.release.info,
|
||||||
releaseLink = result.release.releaseLink,
|
releaseLink = result.release.releaseLink,
|
||||||
downloadLink = result.release.getDownloadLink(),
|
downloadLink = result.release.downloadLink,
|
||||||
)
|
)
|
||||||
navigator.push(updateScreen)
|
navigator.push(updateScreen)
|
||||||
},
|
},
|
||||||
|
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.updater
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
|
import eu.kanade.tachiyomi.util.system.isFossBuildType
|
||||||
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
|
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
|
||||||
import tachiyomi.core.common.util.lang.withIOContext
|
import tachiyomi.core.common.util.lang.withIOContext
|
||||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
|
import tachiyomi.domain.release.interactor.GetApplicationRelease
|
||||||
@@ -20,6 +21,7 @@ class AppUpdateChecker {
|
|||||||
return withIOContext {
|
return withIOContext {
|
||||||
val result = getApplicationRelease.await(
|
val result = getApplicationRelease.await(
|
||||||
GetApplicationRelease.Arguments(
|
GetApplicationRelease.Arguments(
|
||||||
|
isFossBuildType,
|
||||||
isPreviewBuildType,
|
isPreviewBuildType,
|
||||||
BuildConfig.COMMIT_COUNT.toInt(),
|
BuildConfig.COMMIT_COUNT.toInt(),
|
||||||
BuildConfig.VERSION_NAME,
|
BuildConfig.VERSION_NAME,
|
||||||
|
@@ -38,7 +38,7 @@ internal class AppUpdateNotifier(private val context: Context) {
|
|||||||
fun promptUpdate(release: Release) {
|
fun promptUpdate(release: Release) {
|
||||||
val updateIntent = NotificationReceiver.downloadAppUpdatePendingBroadcast(
|
val updateIntent = NotificationReceiver.downloadAppUpdatePendingBroadcast(
|
||||||
context,
|
context,
|
||||||
release.getDownloadLink(),
|
release.downloadLink,
|
||||||
release.version,
|
release.version,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -312,7 +312,7 @@ class MainActivity : BaseActivity() {
|
|||||||
versionName = result.release.version,
|
versionName = result.release.version,
|
||||||
changelogInfo = result.release.info,
|
changelogInfo = result.release.info,
|
||||||
releaseLink = result.release.releaseLink,
|
releaseLink = result.release.releaseLink,
|
||||||
downloadLink = result.release.getDownloadLink(),
|
downloadLink = result.release.downloadLink,
|
||||||
)
|
)
|
||||||
navigator.push(updateScreen)
|
navigator.push(updateScreen)
|
||||||
}
|
}
|
||||||
|
@@ -18,3 +18,6 @@ val isPreviewBuildType: Boolean
|
|||||||
|
|
||||||
val isReleaseBuildType: Boolean
|
val isReleaseBuildType: Boolean
|
||||||
inline get() = BuildConfig.BUILD_TYPE == "release"
|
inline get() = BuildConfig.BUILD_TYPE == "release"
|
||||||
|
|
||||||
|
val isFossBuildType: Boolean
|
||||||
|
inline get() = BuildConfig.BUILD_TYPE == "foss"
|
||||||
|
@@ -2,47 +2,28 @@ package tachiyomi.data.release
|
|||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import tachiyomi.domain.release.model.Release
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains information about the latest release from GitHub.
|
* Contains information about the latest release from GitHub.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GithubRelease(
|
data class GithubRelease(
|
||||||
@SerialName("tag_name") val version: String,
|
@SerialName("tag_name")
|
||||||
@SerialName("body") val info: String,
|
val version: String,
|
||||||
@SerialName("html_url") val releaseLink: String,
|
@SerialName("body")
|
||||||
@SerialName("assets") val assets: List<GitHubAssets>,
|
val info: String,
|
||||||
|
@SerialName("html_url")
|
||||||
|
val releaseLink: String,
|
||||||
|
@SerialName("assets")
|
||||||
|
val assets: List<GitHubAsset>,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assets class containing download url.
|
* Asset class containing asset name and download url.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GitHubAssets(@SerialName("browser_download_url") val downloadLink: String)
|
data class GitHubAsset(
|
||||||
|
val name: String,
|
||||||
/**
|
@SerialName("browser_download_url")
|
||||||
* Regular expression that matches a mention to a valid GitHub username, like it's
|
val downloadLink: String,
|
||||||
* done in GitHub Flavored Markdown. It follows these constraints:
|
)
|
||||||
*
|
|
||||||
* - Alphanumeric with single hyphens (no consecutive hyphens)
|
|
||||||
* - Cannot begin or end with a hyphen
|
|
||||||
* - Max length of 39 characters
|
|
||||||
*
|
|
||||||
* Reference: https://stackoverflow.com/a/30281147
|
|
||||||
*/
|
|
||||||
val gitHubUsernameMentionRegex =
|
|
||||||
"""\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))""".toRegex(
|
|
||||||
RegexOption.IGNORE_CASE,
|
|
||||||
)
|
|
||||||
|
|
||||||
val releaseMapper: (GithubRelease) -> Release = {
|
|
||||||
Release(
|
|
||||||
it.version,
|
|
||||||
it.info.replace(gitHubUsernameMentionRegex) { mention ->
|
|
||||||
"[${mention.value}](https://github.com/${mention.value.substring(1)})"
|
|
||||||
},
|
|
||||||
it.releaseLink,
|
|
||||||
it.assets.map(GitHubAssets::downloadLink),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
package tachiyomi.data.release
|
package tachiyomi.data.release
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import tachiyomi.domain.release.interactor.GetApplicationRelease
|
||||||
import tachiyomi.domain.release.model.Release
|
import tachiyomi.domain.release.model.Release
|
||||||
import tachiyomi.domain.release.service.ReleaseService
|
import tachiyomi.domain.release.service.ReleaseService
|
||||||
|
|
||||||
@@ -13,13 +15,53 @@ class ReleaseServiceImpl(
|
|||||||
private val json: Json,
|
private val json: Json,
|
||||||
) : ReleaseService {
|
) : ReleaseService {
|
||||||
|
|
||||||
override suspend fun latest(repository: String): Release {
|
override suspend fun latest(arguments: GetApplicationRelease.Arguments): Release? {
|
||||||
return with(json) {
|
val release = with(json) {
|
||||||
networkService.client
|
networkService.client
|
||||||
.newCall(GET("https://api.github.com/repos/$repository/releases/latest"))
|
.newCall(GET("https://api.github.com/repos/${arguments.repository}/releases/latest"))
|
||||||
.awaitSuccess()
|
.awaitSuccess()
|
||||||
.parseAs<GithubRelease>()
|
.parseAs<GithubRelease>()
|
||||||
.let(releaseMapper)
|
}
|
||||||
|
|
||||||
|
val downloadLink = getDownloadLink(release = release, isFoss = arguments.isFoss) ?: return null
|
||||||
|
|
||||||
|
return Release(
|
||||||
|
version = release.version,
|
||||||
|
info = release.info.replace(gitHubUsernameMentionRegex) { mention ->
|
||||||
|
"[${mention.value}](https://github.com/${mention.value.substring(1)})"
|
||||||
|
},
|
||||||
|
releaseLink = release.releaseLink,
|
||||||
|
downloadLink = downloadLink,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDownloadLink(release: GithubRelease, isFoss: Boolean): String? {
|
||||||
|
val map = release.assets.associate { asset ->
|
||||||
|
BUILD_TYPES.find { "-$it" in asset.name } to asset.downloadLink
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (!isFoss) {
|
||||||
|
map[Build.SUPPORTED_ABIS[0]] ?: map[null]
|
||||||
|
} else {
|
||||||
|
map[FOSS]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val FOSS = "foss"
|
||||||
|
private val BUILD_TYPES = listOf(FOSS, "arm64-v8a", "armeabi-v7a", "x86_64", "x86")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regular expression that matches a mention to a valid GitHub username, like it's
|
||||||
|
* done in GitHub Flavored Markdown. It follows these constraints:
|
||||||
|
*
|
||||||
|
* - Alphanumeric with single hyphens (no consecutive hyphens)
|
||||||
|
* - Cannot begin or end with a hyphen
|
||||||
|
* - Max length of 39 characters
|
||||||
|
*
|
||||||
|
* Reference: https://stackoverflow.com/a/30281147
|
||||||
|
*/
|
||||||
|
private val gitHubUsernameMentionRegex = """\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))"""
|
||||||
|
.toRegex(RegexOption.IGNORE_CASE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ class GetApplicationRelease(
|
|||||||
return Result.NoNewUpdate
|
return Result.NoNewUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
val release = service.latest(arguments.repository)
|
val release = service.latest(arguments) ?: return Result.NoNewUpdate
|
||||||
|
|
||||||
lastChecked.set(now.toEpochMilli())
|
lastChecked.set(now.toEpochMilli())
|
||||||
|
|
||||||
@@ -73,6 +73,7 @@ class GetApplicationRelease(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class Arguments(
|
data class Arguments(
|
||||||
|
val isFoss: Boolean,
|
||||||
val isPreview: Boolean,
|
val isPreview: Boolean,
|
||||||
val commitCount: Int,
|
val commitCount: Int,
|
||||||
val versionName: String,
|
val versionName: String,
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
package tachiyomi.domain.release.model
|
package tachiyomi.domain.release.model
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains information about the latest release.
|
* Contains information about the latest release.
|
||||||
*/
|
*/
|
||||||
@@ -9,27 +7,5 @@ data class Release(
|
|||||||
val version: String,
|
val version: String,
|
||||||
val info: String,
|
val info: String,
|
||||||
val releaseLink: String,
|
val releaseLink: String,
|
||||||
private val assets: List<String>,
|
val downloadLink: String,
|
||||||
) {
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Get download link of latest release from the assets.
|
|
||||||
* @return download link of latest release.
|
|
||||||
*/
|
|
||||||
fun getDownloadLink(): String {
|
|
||||||
val apkVariant = when (Build.SUPPORTED_ABIS[0]) {
|
|
||||||
"arm64-v8a" -> "-arm64-v8a"
|
|
||||||
"armeabi-v7a" -> "-armeabi-v7a"
|
|
||||||
"x86" -> "-x86"
|
|
||||||
"x86_64" -> "-x86_64"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return assets.find { it.contains("mihon$apkVariant-") } ?: assets[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assets class containing download url.
|
|
||||||
*/
|
|
||||||
data class Assets(val downloadLink: String)
|
|
||||||
}
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
package tachiyomi.domain.release.service
|
package tachiyomi.domain.release.service
|
||||||
|
|
||||||
|
import tachiyomi.domain.release.interactor.GetApplicationRelease
|
||||||
import tachiyomi.domain.release.model.Release
|
import tachiyomi.domain.release.model.Release
|
||||||
|
|
||||||
interface ReleaseService {
|
interface ReleaseService {
|
||||||
|
|
||||||
suspend fun latest(repository: String): Release
|
suspend fun latest(arguments: GetApplicationRelease.Arguments): Release?
|
||||||
}
|
}
|
||||||
|
@@ -16,9 +16,9 @@ import java.time.Instant
|
|||||||
|
|
||||||
class GetApplicationReleaseTest {
|
class GetApplicationReleaseTest {
|
||||||
|
|
||||||
lateinit var getApplicationRelease: GetApplicationRelease
|
private lateinit var getApplicationRelease: GetApplicationRelease
|
||||||
lateinit var releaseService: ReleaseService
|
private lateinit var releaseService: ReleaseService
|
||||||
lateinit var preference: Preference<Long>
|
private lateinit var preference: Preference<Long>
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun beforeEach() {
|
fun beforeEach() {
|
||||||
@@ -39,13 +39,14 @@ class GetApplicationReleaseTest {
|
|||||||
"r2000",
|
"r2000",
|
||||||
"info",
|
"info",
|
||||||
"http://example.com/release_link",
|
"http://example.com/release_link",
|
||||||
listOf("http://example.com/assets"),
|
"http://example.com/release_link.apk",
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { releaseService.latest(any()) } returns release
|
coEvery { releaseService.latest(any()) } returns release
|
||||||
|
|
||||||
val result = getApplicationRelease.await(
|
val result = getApplicationRelease.await(
|
||||||
GetApplicationRelease.Arguments(
|
GetApplicationRelease.Arguments(
|
||||||
|
isFoss = false,
|
||||||
isPreview = true,
|
isPreview = true,
|
||||||
commitCount = 1000,
|
commitCount = 1000,
|
||||||
versionName = "",
|
versionName = "",
|
||||||
@@ -67,13 +68,14 @@ class GetApplicationReleaseTest {
|
|||||||
"v2.0.0",
|
"v2.0.0",
|
||||||
"info",
|
"info",
|
||||||
"http://example.com/release_link",
|
"http://example.com/release_link",
|
||||||
listOf("http://example.com/assets"),
|
"http://example.com/release_link.apk",
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { releaseService.latest(any()) } returns release
|
coEvery { releaseService.latest(any()) } returns release
|
||||||
|
|
||||||
val result = getApplicationRelease.await(
|
val result = getApplicationRelease.await(
|
||||||
GetApplicationRelease.Arguments(
|
GetApplicationRelease.Arguments(
|
||||||
|
isFoss = false,
|
||||||
isPreview = false,
|
isPreview = false,
|
||||||
commitCount = 0,
|
commitCount = 0,
|
||||||
versionName = "v1.0.0",
|
versionName = "v1.0.0",
|
||||||
@@ -95,13 +97,14 @@ class GetApplicationReleaseTest {
|
|||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"info",
|
"info",
|
||||||
"http://example.com/release_link",
|
"http://example.com/release_link",
|
||||||
listOf("http://example.com/assets"),
|
"http://example.com/release_link.apk",
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { releaseService.latest(any()) } returns release
|
coEvery { releaseService.latest(any()) } returns release
|
||||||
|
|
||||||
val result = getApplicationRelease.await(
|
val result = getApplicationRelease.await(
|
||||||
GetApplicationRelease.Arguments(
|
GetApplicationRelease.Arguments(
|
||||||
|
isFoss = false,
|
||||||
isPreview = false,
|
isPreview = false,
|
||||||
commitCount = 0,
|
commitCount = 0,
|
||||||
versionName = "v2.0.0",
|
versionName = "v2.0.0",
|
||||||
@@ -121,13 +124,14 @@ class GetApplicationReleaseTest {
|
|||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"info",
|
"info",
|
||||||
"http://example.com/release_link",
|
"http://example.com/release_link",
|
||||||
listOf("http://example.com/assets"),
|
"http://example.com/release_link.apk",
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { releaseService.latest(any()) } returns release
|
coEvery { releaseService.latest(any()) } returns release
|
||||||
|
|
||||||
val result = getApplicationRelease.await(
|
val result = getApplicationRelease.await(
|
||||||
GetApplicationRelease.Arguments(
|
GetApplicationRelease.Arguments(
|
||||||
|
isFoss = false,
|
||||||
isPreview = false,
|
isPreview = false,
|
||||||
commitCount = 0,
|
commitCount = 0,
|
||||||
versionName = "v2.0.0",
|
versionName = "v2.0.0",
|
||||||
|
Reference in New Issue
Block a user