diff --git a/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt b/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt index 310f2ae..a437213 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt @@ -42,7 +42,6 @@ class ManagerApplication : Application() { // Services modules(module { singleOf(::HttpService) - singleOf(::GithubService) singleOf(::AliucordGithubService) singleOf(::AliucordMavenService) }) diff --git a/app/src/main/kotlin/com/aliucord/manager/network/services/AliucordGithubService.kt b/app/src/main/kotlin/com/aliucord/manager/network/services/AliucordGithubService.kt index 3cfba69..10e6782 100644 --- a/app/src/main/kotlin/com/aliucord/manager/network/services/AliucordGithubService.kt +++ b/app/src/main/kotlin/com/aliucord/manager/network/services/AliucordGithubService.kt @@ -1,14 +1,14 @@ package com.aliucord.manager.network.services import com.aliucord.manager.network.models.BuildInfo +import com.aliucord.manager.network.models.GithubRelease import com.aliucord.manager.network.utils.ApiResponse import io.ktor.client.request.header import io.ktor.client.request.url import io.ktor.http.HttpHeaders class AliucordGithubService( - val github: GithubService, - val http: HttpService, + private val http: HttpService, ) { /** * Fetches the build data of Aliucord (excluding Aliuhook). @@ -22,7 +22,15 @@ class AliucordGithubService( } } - suspend fun getManagerReleases() = github.getReleases(ORG, MANAGER_REPO) + /** + * Fetches all the Manager releases with a 60s local cache. + */ + suspend fun getManagerReleases(): ApiResponse> { + return http.request { + url("https://api.github.com/repos/rushiiMachine/$MANAGER_REPO/releases") + header(HttpHeaders.CacheControl, "public, max-age=60, s-maxage=60") + } + } companion object { const val ORG = "Aliucord" diff --git a/app/src/main/kotlin/com/aliucord/manager/network/services/GithubService.kt b/app/src/main/kotlin/com/aliucord/manager/network/services/GithubService.kt deleted file mode 100644 index 9ca6141..0000000 --- a/app/src/main/kotlin/com/aliucord/manager/network/services/GithubService.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.aliucord.manager.network.services - -import com.aliucord.manager.network.models.GithubRelease -import com.aliucord.manager.network.utils.ApiResponse -import io.ktor.client.request.url -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -class GithubService( - private val http: HttpService, -) { - suspend fun getReleases(owner: String, repo: String): ApiResponse> { - return withContext(Dispatchers.IO) { - http.request { - url("https://api.github.com/repos/$owner/$repo/releases") - } - } - } -} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/widgets/updater/UpdaterViewModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/widgets/updater/UpdaterViewModel.kt index 7cca976..9b95745 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/widgets/updater/UpdaterViewModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/widgets/updater/UpdaterViewModel.kt @@ -1,17 +1,19 @@ package com.aliucord.manager.ui.widgets.updater import android.app.Application +import android.util.Log import androidx.compose.runtime.* import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.aliucord.manager.BuildConfig +import com.aliucord.manager.R import com.aliucord.manager.manager.InstallerManager import com.aliucord.manager.manager.InstallerSetting import com.aliucord.manager.manager.download.KtorDownloadManager import com.aliucord.manager.network.services.AliucordGithubService import com.aliucord.manager.network.utils.SemVer -import com.aliucord.manager.network.utils.getOrNull -import kotlinx.coroutines.Dispatchers +import com.aliucord.manager.network.utils.getOrThrow +import com.aliucord.manager.util.showToast import kotlinx.coroutines.launch class UpdaterViewModel( @@ -29,6 +31,17 @@ class UpdaterViewModel( private var targetApkUrl: String? = null + init { + viewModelScope.launch { + try { + fetchInfo() + } catch (t: Throwable) { + Log.e(BuildConfig.TAG, "Failed to check for updates!", t) + application.showToast(R.string.updater_fail) + } + } + } + fun dismissDialog() { showDialog = false } @@ -52,34 +65,45 @@ class UpdaterViewModel( } } - // This updates to the latest release based on the tag name - // It finds all releases that have an asset named aliucord-manager-[tagname].apk (this is in case the filename changes in the future) - // Then compares the semantic versioning of the tag name which should be in the v1.0.0 format - // Finds the latest and downloads/installs it - init { - viewModelScope.launch(Dispatchers.IO) { - val (version, asset) = github.getManagerReleases().getOrNull() - ?.mapNotNull { release -> - val version = SemVer.parseOrNull(release.tagName) - ?: return@mapNotNull null + /** + * This fetched the releases data from GitHub and populates the state if there is an update. + * + * It obtains all the releases that have an asset named `aliucord-manager-[tag].apk`, + * then finds the latest release based on the largest semantic version extracted from the tag name (`v1.0.0`), + * and populates the state to show to the user. + */ + private suspend fun fetchInfo() { + Log.d(BuildConfig.TAG, "Checking for updates...") - val asset = release.assets.find { it.name == "aliucord-manager-${release.tagName}.apk" } - ?: return@mapNotNull null + val currentVersion = SemVer.parseOrNull(BuildConfig.VERSION_NAME) + ?: throw Error("Failed to parse current app version") - version to asset - } - ?.maxByOrNull { it.first } - ?: return@launch + // Fetch releases from GitHub (60s local cache) + val releases = github.getManagerReleases().getOrThrow() - val currentVersion = SemVer.parseOrNull(BuildConfig.VERSION_NAME) - ?: throw Error("Failed to parse app version") + // Find the latest release + APK release asset + val (version, apkUrl) = releases + .mapNotNull { release -> + val version = SemVer.parseOrNull(release.tagName) + ?: return@mapNotNull null - if (currentVersion >= version) - return@launch + val asset = release.assets.find { it.name == "aliucord-manager-${release.tagName}.apk" } + ?: return@mapNotNull null - targetVersion = version.toString() - targetApkUrl = asset.browserDownloadUrl - showDialog = true + version to asset.browserDownloadUrl + } + .maxByOrNull { it.first } + ?: return + + // Check if currently installed version is greater + if (currentVersion >= version) { + Log.d(BuildConfig.TAG, "Already updated to latest version!") + return } + + targetVersion = version.toString() + targetApkUrl = apkUrl + showDialog = true + Log.d(BuildConfig.TAG, "Found an update! $targetVersion $targetApkUrl") } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5769f14..cf9fd84 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -149,6 +149,7 @@ A new update has been released for Aliucord Manager! It may be required in order to function properly. Would you like to update? Update to %1$s + Failed to check for updates! Download failed (Unknown) Download failed (Timeout)