mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor: Rewrite "new version checker"
This commit is contained in:
parent
d7d75f1642
commit
ec37c0f87d
3 changed files with 138 additions and 59 deletions
102
app/src/main/java/dev/yokai/domain/base/models/Version.kt
Normal file
102
app/src/main/java/dev/yokai/domain/base/models/Version.kt
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package dev.yokai.domain.base.models
|
||||||
|
|
||||||
|
data class Version(
|
||||||
|
val type: Type,
|
||||||
|
val stage: Stage,
|
||||||
|
val major: Int,
|
||||||
|
val minor: Int = 0,
|
||||||
|
val patch: Int = 0,
|
||||||
|
val hotfix: Int = 0,
|
||||||
|
val build: Int = 0
|
||||||
|
) {
|
||||||
|
operator fun compareTo(other: Version): Int {
|
||||||
|
if (type == Type.DEBUG) {
|
||||||
|
throw IllegalStateException("Checking debug version is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != other.type) {
|
||||||
|
throw IllegalArgumentException("Can't compare two different version type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
major > other.major ||
|
||||||
|
minor > other.minor ||
|
||||||
|
patch > other.patch ||
|
||||||
|
hotfix > other.hotfix ||
|
||||||
|
build > other.build ||
|
||||||
|
stage.weight > other.stage.weight
|
||||||
|
-> 1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "$major.$minor.$patch" + (if (hotfix > 0) ".$hotfix" else "") + (if (build > 0) "-${type.prefix}$build" else "")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun parse(string: String): Version {
|
||||||
|
var type = when {
|
||||||
|
string.startsWith("r") -> Type.NIGHTLY
|
||||||
|
string.startsWith("d") -> Type.DEBUG
|
||||||
|
else -> Type.STABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
val split = string.split("-")
|
||||||
|
var stage = Stage.RELEASE
|
||||||
|
val stageCandidate = split.getOrNull(1)
|
||||||
|
if (stageCandidate != null) {
|
||||||
|
when {
|
||||||
|
stageCandidate.startsWith("r", true) -> type = Type.NIGHTLY
|
||||||
|
stageCandidate.startsWith("d", true) -> type = Type.DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == Type.STABLE)
|
||||||
|
stage = when {
|
||||||
|
stageCandidate.startsWith("b", true) -> Stage.BETA
|
||||||
|
stageCandidate.startsWith("a", true) -> Stage.ALPHA
|
||||||
|
else -> Stage.RELEASE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val cleanBuild = stageCandidate
|
||||||
|
?.replace("[^\\d.-]".toRegex(), "") // remove the prefix
|
||||||
|
?.toInt()
|
||||||
|
val candidate = split.first()
|
||||||
|
.replace("[^\\d.-]".toRegex(), "") // remove the prefix
|
||||||
|
.split(".").map { it.toInt() }
|
||||||
|
|
||||||
|
if (candidate.size == 1 && type == Type.NIGHTLY)
|
||||||
|
return Version(
|
||||||
|
type,
|
||||||
|
stage,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
candidate[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
return Version(
|
||||||
|
type,
|
||||||
|
stage,
|
||||||
|
candidate.getOrNull(0) ?: 0,
|
||||||
|
candidate.getOrNull(1) ?: 0,
|
||||||
|
candidate.getOrNull(2) ?: 0,
|
||||||
|
candidate.getOrNull(3) ?: 0,
|
||||||
|
cleanBuild ?: 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Stage(val weight: Int) {
|
||||||
|
RELEASE(3),
|
||||||
|
BETA(2),
|
||||||
|
ALPHA(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Type(val prefix: String) {
|
||||||
|
STABLE("v"),
|
||||||
|
NIGHTLY("r"),
|
||||||
|
DEBUG("d"),
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.updater
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import dev.yokai.domain.base.models.Version
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
@ -14,8 +15,8 @@ import eu.kanade.tachiyomi.util.system.withIOContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.Date
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.*
|
||||||
|
|
||||||
class AppUpdateChecker(
|
class AppUpdateChecker(
|
||||||
private val json: Json = Injekt.get(),
|
private val json: Json = Injekt.get(),
|
||||||
|
@ -87,45 +88,12 @@ class AppUpdateChecker(
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
fun isNewVersion(versionTag: String, currentVersion: String = BuildConfig.VERSION_NAME, isNightly: Boolean = BuildConfig.NIGHTLY): Boolean {
|
fun isNewVersion(newVersion: String, currentVersion: String = BuildConfig.VERSION_NAME): Boolean =
|
||||||
// Removes prefixes like "r" or "v"
|
try {
|
||||||
val newVersion = versionTag.replace("[^\\d.-]".toRegex(), "")
|
Version.parse(newVersion) > Version.parse(currentVersion)
|
||||||
val oldVersion = currentVersion.replace("[^\\d.-]".toRegex(), "")
|
} catch (e: IllegalArgumentException) {
|
||||||
val newPreReleaseVer = newVersion.split("-")
|
|
||||||
val oldPreReleaseVer = oldVersion.split("-")
|
|
||||||
val newSemVer = newPreReleaseVer.first().split(".").map { it.toInt() }
|
|
||||||
val isNewVersionNightly = newSemVer.size == 1 || (newPreReleaseVer.size > 1 && newPreReleaseVer[1].startsWith("r"))
|
|
||||||
val oldSemVer = oldPreReleaseVer.first().split(".").map { it.toInt() }
|
|
||||||
|
|
||||||
oldSemVer.mapIndexed { index, i ->
|
|
||||||
if (!isNewVersionNightly && !isNightly && newSemVer.getOrElse(index) { i } > i) {
|
|
||||||
return true
|
|
||||||
} else if (newSemVer.getOrElse(index) { i } < i) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For cases of extreme patch versions (new: 1.2.3.1 vs old: 1.2.3, return true)
|
|
||||||
return if (newSemVer.size > oldSemVer.size && !isNewVersionNightly && !isNightly) {
|
|
||||||
true
|
|
||||||
} else if (newSemVer.size < oldSemVer.size && !isNewVersionNightly) {
|
|
||||||
false
|
false
|
||||||
} else {
|
|
||||||
// If the version numbers match, check the beta versions
|
|
||||||
val newPreVersion =
|
|
||||||
newPreReleaseVer.getOrNull(if (newPreReleaseVer.size > 1) 1 else 0)?.replace("[^\\d.-]".toRegex(), "")?.toIntOrNull()
|
|
||||||
val oldPreVersion =
|
|
||||||
oldPreReleaseVer.getOrNull(1)?.replace("[^\\d.-]".toRegex(), "")?.toIntOrNull()
|
|
||||||
when {
|
|
||||||
// For prod, don't bother with betas (current: 1.2.3 vs new: 1.2.3-b1)
|
|
||||||
oldPreVersion == null && !isNightly -> false
|
|
||||||
// For betas, always use prod builds (current: 1.2.3-b1 vs new: 1.2.3)
|
|
||||||
// For nightly, don't use prod builds
|
|
||||||
newPreVersion == null -> !isNightly
|
|
||||||
// For nightly, higher beta ver is newer (current: 1.2.3-b1 vs new: 1.2.3-b2 or r2)
|
|
||||||
else -> (oldPreVersion ?: 0) < newPreVersion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val RELEASE_TAG: String by lazy {
|
val RELEASE_TAG: String by lazy {
|
||||||
|
|
|
@ -4,7 +4,8 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.junit.jupiter.api.Assertions.*
|
import org.junit.jupiter.api.Assertions.assertFalse
|
||||||
|
import org.junit.jupiter.api.Assertions.assertTrue
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
@ -22,55 +23,63 @@ class AppUpdateCheckerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Check new nightly version (Tachi format)`() {
|
fun `Check new nightly version (Tachi format)`() {
|
||||||
assertTrue(isNewVersion("1.2.3-r2", "1.2.3-r1", true)) // tachi format
|
assertTrue(isNewVersion("1.2.3-r2", "1.2.3-r1")) // tachi format
|
||||||
assertTrue(isNewVersion("1.2.4-r1", "1.2.3", true)) // Unlikely to happened, but we should try anyway
|
assertFalse(isNewVersion("1.2.4-r1", "1.2.3")) // Unlikely to happened, but we should try anyway
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Check new nightly version (Yokai format)`() {
|
fun `Check new nightly version (Yokai format)`() {
|
||||||
assertTrue(isNewVersion("r2", "1.2.3-r1", true)) // yokai format
|
assertTrue(isNewVersion("r2", "1.2.3-r1")) // yokai format
|
||||||
|
assertFalse(isNewVersion("r1", "1.2.3")) // Unlikely to happened, but we should try anyway
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Nightly shouldn't get Prod build`() {
|
fun `Nightly shouldn't get Prod build`() {
|
||||||
assertFalse(isNewVersion("1.2.3", "1.2.3-r2", true))
|
assertFalse(isNewVersion("1.2.3", "1.2.3-r2"))
|
||||||
assertFalse(isNewVersion("1.2.4", "1.2.3-r2", true))
|
assertFalse(isNewVersion("1.2.4", "1.2.3-r2"))
|
||||||
assertFalse(isNewVersion("1.2.4", "1.2.3", true))
|
assertFalse(isNewVersion("1.2.4", "1.2.3-r0"))
|
||||||
assertFalse(isNewVersion("1.2.4.1", "1.2.4-r2", true))
|
assertFalse(isNewVersion("1.2.4.1", "1.2.4-r2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Check new beta version`() {
|
||||||
|
assertFalse(isNewVersion("1.2.3-b1", "1.2.3-b2"))
|
||||||
|
assertTrue(isNewVersion("1.2.3-b3", "1.2.3-b2"))
|
||||||
|
assertTrue(isNewVersion("1.2.4-b1", "1.2.3-b1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Beta should get Prod build`() {
|
fun `Beta should get Prod build`() {
|
||||||
assertTrue(isNewVersion("1.2.4", "1.2.3-r2", false))
|
assertTrue(isNewVersion("1.2.4", "1.2.3-b2"))
|
||||||
assertTrue(isNewVersion("1.2.3", "1.2.3-r2", false))
|
assertTrue(isNewVersion("1.2.3", "1.2.3-b2"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Prod should get latest Prod build`() {
|
fun `Prod should get latest Prod build`() {
|
||||||
assertTrue(isNewVersion("1.2.4", "1.2.3", false))
|
assertTrue(isNewVersion("1.2.4", "1.2.3"))
|
||||||
assertTrue(isNewVersion("1.2.4.1", "1.2.4", false))
|
assertTrue(isNewVersion("1.2.4.1", "1.2.4"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Prod should get latest Prod build (Check for Betas)`() {
|
fun `Prod should get latest Prod build (Check for Betas)`() {
|
||||||
assertTrue(isNewVersion("1.2.4-r1", "1.2.3", false))
|
assertTrue(isNewVersion("1.2.4-b1", "1.2.3"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Prod shouldn't get nightly build (Check for Betas)`() {
|
fun `Prod shouldn't get nightly build (Check for Betas)`() {
|
||||||
assertFalse(isNewVersion("r1", "1.2.3", false))
|
assertFalse(isNewVersion("r1", "1.2.3"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Latest version check`() {
|
fun `Latest version check`() {
|
||||||
assertFalse(isNewVersion("1.2.3", "1.2.3", false))
|
assertFalse(isNewVersion("1.2.3", "1.2.3"))
|
||||||
assertFalse(isNewVersion("1.2.3-r1", "1.2.3-r1", false))
|
assertFalse(isNewVersion("1.2.3-r1", "1.2.3-r1"))
|
||||||
|
|
||||||
assertFalse(isNewVersion("1.2.3-r1", "1.2.3-r1", true))
|
assertFalse(isNewVersion("1.2.3-r1", "1.2.3-r1"))
|
||||||
assertFalse(isNewVersion("r1", "1.2.4-r1", true))
|
assertFalse(isNewVersion("r1", "1.2.4-r1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isNewVersion(newVersion: String, currentVersion: String, isNightly: Boolean): Boolean {
|
private fun isNewVersion(newVersion: String, currentVersion: String): Boolean {
|
||||||
return appUpdateChecker.isNewVersion(newVersion, currentVersion, isNightly)
|
return appUpdateChecker.isNewVersion(newVersion, currentVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue