更新界面
This commit is contained in:
+1
-1
@@ -120,7 +120,7 @@ android {
|
|||||||
manifestPlaceholders.put("app_name", "@string/app_name")
|
manifestPlaceholders.put("app_name", "@string/app_name")
|
||||||
|
|
||||||
//applicationIdSuffix '.debug'
|
//applicationIdSuffix '.debug'
|
||||||
versionNameSuffix "_debug-${getGitCommitHash()}"
|
versionNameSuffix "_debug+${getGitCommitHash()}"
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'cronet-proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'cronet-proguard-rules.pro'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,9 @@ data class AppReleaseInfo(
|
|||||||
val note: String,
|
val note: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val downloadUrl: String,
|
val downloadUrl: String,
|
||||||
val assetUrl: String
|
val assetUrl: String,
|
||||||
) {
|
val versionName: String
|
||||||
val versionName: String = Regex("""legado_app_([\d.]+)\.apk""")
|
)
|
||||||
.find(name)
|
|
||||||
?.groupValues?.get(1)
|
|
||||||
?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class AppVariant {
|
enum class AppVariant {
|
||||||
OFFICIAL,
|
OFFICIAL,
|
||||||
@@ -43,11 +39,14 @@ data class GithubRelease(
|
|||||||
val createdAt: String?
|
val createdAt: String?
|
||||||
) {
|
) {
|
||||||
fun gitReleaseToAppReleaseInfo(): List<AppReleaseInfo> {
|
fun gitReleaseToAppReleaseInfo(): List<AppReleaseInfo> {
|
||||||
|
val version = tagName // 直接用 release 的 tag_name 作为版本号
|
||||||
assets ?: throw NoStackTraceException("获取新版本出错")
|
assets ?: throw NoStackTraceException("获取新版本出错")
|
||||||
|
|
||||||
return assets
|
return assets
|
||||||
.filter { it.isValid }
|
.filter { it.isValid }
|
||||||
.map { it.assetToAppReleaseInfo(isPreRelease, body) }
|
.map { it.assetToAppReleaseInfo(isPreRelease, body, version) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -69,17 +68,21 @@ data class Asset(
|
|||||||
val isValid: Boolean
|
val isValid: Boolean
|
||||||
get() = (contentType == "application/vnd.android.package-archive") && (state == "uploaded")
|
get() = (contentType == "application/vnd.android.package-archive") && (state == "uploaded")
|
||||||
|
|
||||||
fun assetToAppReleaseInfo(preRelease: Boolean, note: String): AppReleaseInfo {
|
fun assetToAppReleaseInfo(preRelease: Boolean, note: String, version: String): AppReleaseInfo {
|
||||||
val instant = Instant.parse(createdAt)
|
val instant = Instant.parse(createdAt)
|
||||||
val timestamp: Long = instant.toEpochMilli()
|
val timestamp: Long = instant.toEpochMilli()
|
||||||
|
|
||||||
val appVariant = if (preRelease) {
|
val appVariant = if (preRelease) AppVariant.BETA_RELEASE else AppVariant.OFFICIAL
|
||||||
AppVariant.BETA_RELEASE
|
|
||||||
} else {
|
|
||||||
AppVariant.OFFICIAL
|
|
||||||
}
|
|
||||||
|
|
||||||
return AppReleaseInfo(appVariant, timestamp, note, name, apkUrl, url)
|
return AppReleaseInfo(
|
||||||
|
appVariant = appVariant,
|
||||||
|
createdAt = timestamp,
|
||||||
|
note = note,
|
||||||
|
name = name,
|
||||||
|
downloadUrl = apkUrl,
|
||||||
|
assetUrl = url,
|
||||||
|
versionName = version // 直接传入 tagName
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,16 +29,10 @@ object AppUpdateGitHub : AppUpdate.AppUpdateInterface {
|
|||||||
"https://api.github.com/repos/HapeLee/legado-with-MD3/releases/latest"
|
"https://api.github.com/repos/HapeLee/legado-with-MD3/releases/latest"
|
||||||
}
|
}
|
||||||
|
|
||||||
val res = okHttpClient.newCallResponse {
|
val res = okHttpClient.newCallResponse { url(lastReleaseUrl) }
|
||||||
url(lastReleaseUrl)
|
if (!res.isSuccessful) throw NoStackTraceException("获取新版本出错(${res.code})")
|
||||||
}
|
|
||||||
if (!res.isSuccessful) {
|
|
||||||
throw NoStackTraceException("获取新版本出错(${res.code})")
|
|
||||||
}
|
|
||||||
val body = res.body.text()
|
val body = res.body.text()
|
||||||
if (body.isBlank()) {
|
if (body.isBlank()) throw NoStackTraceException("获取新版本出错")
|
||||||
throw NoStackTraceException("获取新版本出错")
|
|
||||||
}
|
|
||||||
|
|
||||||
return if (checkVariant.isBeta()) {
|
return if (checkVariant.isBeta()) {
|
||||||
val releases = GSON.fromJsonArray<GithubRelease>(body)
|
val releases = GSON.fromJsonArray<GithubRelease>(body)
|
||||||
@@ -60,11 +54,16 @@ object AppUpdateGitHub : AppUpdate.AppUpdateInterface {
|
|||||||
override fun check(scope: CoroutineScope): Coroutine<AppUpdate.UpdateInfo> {
|
override fun check(scope: CoroutineScope): Coroutine<AppUpdate.UpdateInfo> {
|
||||||
return Coroutine.async(scope) {
|
return Coroutine.async(scope) {
|
||||||
val currentVersion = AppConst.appInfo.versionName
|
val currentVersion = AppConst.appInfo.versionName
|
||||||
|
|
||||||
val releases = getLatestRelease()
|
val releases = getLatestRelease()
|
||||||
.filter { it.appVariant == checkVariant }
|
.filter { it.appVariant == checkVariant }
|
||||||
|
|
||||||
val latest = releases.firstOrNull { it.versionName.versionCompare(currentVersion) > 0 }
|
val latest = releases.firstOrNull { r ->
|
||||||
|
try {
|
||||||
|
r.versionName.versionCompare(currentVersion) > 0
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
return@async AppUpdate.UpdateInfo(
|
return@async AppUpdate.UpdateInfo(
|
||||||
@@ -79,35 +78,57 @@ object AppUpdateGitHub : AppUpdate.AppUpdateInterface {
|
|||||||
}.timeout(10000)
|
}.timeout(10000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.versionCompare(other: String): Int {
|
private data class SemVer(
|
||||||
val regex = Regex("""(\d+)|(\D+)""")
|
val major: Int,
|
||||||
val thisParts = regex.findAll(this).map { it.value }.toList()
|
val minor: Int,
|
||||||
val otherParts = regex.findAll(other).map { it.value }.toList()
|
val patch: Int,
|
||||||
val maxLength = maxOf(thisParts.size, otherParts.size)
|
val preRelease: String? = null
|
||||||
|
) : Comparable<SemVer> {
|
||||||
|
override fun compareTo(other: SemVer): Int {
|
||||||
|
if (major != other.major) return major - other.major
|
||||||
|
if (minor != other.minor) return minor - other.minor
|
||||||
|
if (patch != other.patch) return patch - other.patch
|
||||||
|
|
||||||
for (i in 0 until maxLength) {
|
if (preRelease == null && other.preRelease != null) return 1
|
||||||
val a = thisParts.getOrNull(i)
|
if (preRelease != null && other.preRelease == null) return -1
|
||||||
val b = otherParts.getOrNull(i)
|
if (preRelease == null && other.preRelease == null) return 0
|
||||||
|
|
||||||
if (a == null) return -1
|
val aParts = preRelease!!.split(".")
|
||||||
if (b == null) return 1
|
val bParts = other.preRelease!!.split(".")
|
||||||
|
val maxLen = maxOf(aParts.size, bParts.size)
|
||||||
|
|
||||||
val isANum = a.all { it.isDigit() }
|
for (i in 0 until maxLen) {
|
||||||
val isBNum = b.all { it.isDigit() }
|
val a = aParts.getOrNull(i)
|
||||||
|
val b = bParts.getOrNull(i)
|
||||||
|
if (a == null) return -1
|
||||||
|
if (b == null) return 1
|
||||||
|
|
||||||
if (isANum && a.length > 1 && a.startsWith("0")) return -1
|
val isANum = a.all { it.isDigit() }
|
||||||
if (isBNum && b.length > 1 && b.startsWith("0")) return 1
|
val isBNum = b.all { it.isDigit() }
|
||||||
|
if (isANum && isBNum) {
|
||||||
val cmp = if (isANum && isBNum) {
|
val cmp = a.toInt().compareTo(b.toInt())
|
||||||
a.toInt() - b.toInt()
|
if (cmp != 0) return cmp
|
||||||
} else {
|
} else {
|
||||||
a.compareTo(b)
|
val cmp = a.compareTo(b)
|
||||||
|
if (cmp != 0) return cmp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
if (cmp != 0) return cmp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
companion object {
|
||||||
|
fun parse(version: String): SemVer {
|
||||||
|
val regex = Regex("""(\d+)\.(\d+)\.(\d+)(?:-([\w.]+))?""")
|
||||||
|
val match = regex.matchEntire(version)
|
||||||
|
?: throw IllegalArgumentException("Invalid version: $version")
|
||||||
|
val (maj, min, pat, pre) = match.destructured
|
||||||
|
return SemVer(maj.toInt(), min.toInt(), pat.toInt(), pre.ifBlank { null })
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.versionCompare(other: String): Int {
|
||||||
|
return SemVer.parse(this).compareTo(SemVer.parse(other))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,16 @@
|
|||||||
app:entries="@array/language"
|
app:entries="@array/language"
|
||||||
app:entryValues="@array/language_value" />
|
app:entryValues="@array/language_value" />
|
||||||
|
|
||||||
|
<io.legato.kazusa.lib.prefs.NameListPreference
|
||||||
|
android:defaultValue="official_version"
|
||||||
|
android:key="updateToVariant"
|
||||||
|
android:summary="@string/update_to_variant_summary"
|
||||||
|
android:title="@string/update_to_variant_title"
|
||||||
|
app:allowDividerAbove="false"
|
||||||
|
app:allowDividerBelow="false"
|
||||||
|
app:entries="@array/default_app_variant"
|
||||||
|
app:entryValues="@array/default_app_variant_value" />
|
||||||
|
|
||||||
<io.legato.kazusa.lib.prefs.PreferenceCategory
|
<io.legato.kazusa.lib.prefs.PreferenceCategory
|
||||||
android:title="@string/main_activity"
|
android:title="@string/main_activity"
|
||||||
app:allowDividerAbove="false"
|
app:allowDividerAbove="false"
|
||||||
@@ -151,16 +161,6 @@
|
|||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:layout="@layout/view_preference_category">
|
app:layout="@layout/view_preference_category">
|
||||||
|
|
||||||
<io.legato.kazusa.lib.prefs.NameListPreference
|
|
||||||
android:defaultValue="official_version"
|
|
||||||
android:key="updateToVariant"
|
|
||||||
android:summary="@string/update_to_variant_summary"
|
|
||||||
android:title="@string/update_to_variant_title"
|
|
||||||
app:allowDividerAbove="false"
|
|
||||||
app:allowDividerBelow="false"
|
|
||||||
app:entries="@array/default_app_variant"
|
|
||||||
app:entryValues="@array/default_app_variant_value" />
|
|
||||||
|
|
||||||
<io.legato.kazusa.lib.prefs.SwitchPreference
|
<io.legato.kazusa.lib.prefs.SwitchPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="sharedElementEnterTransitionEnable"
|
android:key="sharedElementEnterTransitionEnable"
|
||||||
|
|||||||
Reference in New Issue
Block a user