From 56bf5219f3939f45c62240b16dae46af9af665fe Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Sat, 25 Jan 2025 00:35:11 -0800 Subject: [PATCH] feat(Home): Aliucord installation up-to-date check --- .../manager/ui/screens/home/HomeModel.kt | 45 +++++++++++++++++-- .../manager/ui/screens/home/InstallData.kt | 2 +- .../home/components/InstalledItemCard.kt | 2 +- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt index 4d5d268c..c6e5a1de 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt @@ -2,6 +2,7 @@ package com.aliucord.manager.ui.screens.home import android.app.Application import android.content.Intent +import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.net.ConnectivityManager import android.provider.Settings @@ -18,15 +19,22 @@ import cafe.adriel.voyager.core.model.screenModelScope import com.aliucord.manager.BuildConfig import com.aliucord.manager.R import com.aliucord.manager.domain.repository.GithubRepository +import com.aliucord.manager.network.dto.BuildInfo import com.aliucord.manager.network.utils.fold +import com.aliucord.manager.patcher.InstallMetadata import com.aliucord.manager.ui.util.DiscordVersion import com.aliucord.manager.util.launchBlock import com.aliucord.manager.util.showToast +import com.github.diamondminer88.zip.ZipReader import kotlinx.collections.immutable.toImmutableList +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream class HomeModel( private val application: Application, private val github: GithubRepository, + private val json: Json, ) : ScreenModel { var supportedVersion by mutableStateOf<DiscordVersion>(DiscordVersion.None) private set @@ -34,6 +42,8 @@ class HomeModel( var installations by mutableStateOf<InstallsState>(InstallsState.Fetching) private set + private var remoteDataJson: BuildInfo? = null + init { // fetchInstallations() is called from UI fetchSupportedVersion() @@ -115,13 +125,10 @@ class HomeModel( val versionName = it.versionName ?: return@mapNotNull null val applicationInfo = it.applicationInfo ?: return@mapNotNull null - val baseVersion = it.applicationInfo?.metaData?.getInt("aliucordBaseVersion") - val isBaseUpdated = /* TODO: remote data json instead */ baseVersion == 0 - InstallData( name = packageManager.getApplicationLabel(applicationInfo).toString(), packageName = it.packageName, - baseUpdated = isBaseUpdated, + isUpToDate = isInstallationUpToDate(it), icon = packageManager .getApplicationIcon(applicationInfo) .toBitmap() @@ -163,4 +170,34 @@ class HomeModel( } ) } + + private fun isInstallationUpToDate(pkg: PackageInfo): Boolean { + // `longVersionCode` is unnecessary since Discord doesn't use `versionCodeMajor` + @Suppress("DEPRECATION") + val versionCode = pkg.versionCode + + // Check if the base APK version is a mismatch + val supportedVersion = (supportedVersion as? DiscordVersion.Existing) ?: return true + if (supportedVersion.rawCode != versionCode) return false + + // Try to parse install metadata. If none present, install was made via legacy installer. + val apkPath = pkg.applicationInfo?.publicSourceDir ?: return false + val installMetadata = try { + val metadataFile = ZipReader(apkPath).use { it.openEntry("aliucord.json")?.read() } + ?: return false + + @OptIn(ExperimentalSerializationApi::class) + json.decodeFromStream<InstallMetadata>(metadataFile.inputStream()) + } catch (t: Throwable) { + Log.w(BuildConfig.TAG, "Failed to parse Aliucord install metadata from package ${pkg.packageName}", t) + return false + } + + // Check that all the installation components are up-to-date + val remoteBuildData = remoteDataJson ?: return true + + // TODO: check for aliuhook version too once aliuhook starts using semver + return remoteBuildData.injectorVersion > installMetadata.injectorVersion || + remoteBuildData.patchesVersion > installMetadata.patchesVersion + } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/InstallData.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/InstallData.kt index 2fd30896..633e55bc 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/InstallData.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/InstallData.kt @@ -10,5 +10,5 @@ data class InstallData( val packageName: String, val version: DiscordVersion, val icon: BitmapPainter, - val baseUpdated: Boolean, + val isUpToDate: Boolean, ) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/InstalledItemCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/InstalledItemCard.kt index 98798c5b..42ca84aa 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/InstalledItemCard.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/InstalledItemCard.kt @@ -111,7 +111,7 @@ fun InstalledItemCard( onClick = onOpenInfo, ) - if (data.baseUpdated) { + if (data.isUpToDate) { SegmentedButton( icon = painterResource(R.drawable.ic_launch), text = stringResource(R.string.action_launch),