mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Move GitHub Release/App Update logic to data (#9422)
* Move GitHub Release/App Update logic to data * Add tests for GetApplicationRelease * Review changes
This commit is contained in:
		@@ -20,6 +20,7 @@ import tachiyomi.data.category.CategoryRepositoryImpl
 | 
			
		||||
import tachiyomi.data.chapter.ChapterRepositoryImpl
 | 
			
		||||
import tachiyomi.data.history.HistoryRepositoryImpl
 | 
			
		||||
import tachiyomi.data.manga.MangaRepositoryImpl
 | 
			
		||||
import tachiyomi.data.release.ReleaseServiceImpl
 | 
			
		||||
import tachiyomi.data.source.SourceDataRepositoryImpl
 | 
			
		||||
import tachiyomi.data.source.SourceRepositoryImpl
 | 
			
		||||
import tachiyomi.data.track.TrackRepositoryImpl
 | 
			
		||||
@@ -56,6 +57,8 @@ import tachiyomi.domain.manga.interactor.NetworkToLocalManga
 | 
			
		||||
import tachiyomi.domain.manga.interactor.ResetViewerFlags
 | 
			
		||||
import tachiyomi.domain.manga.interactor.SetMangaChapterFlags
 | 
			
		||||
import tachiyomi.domain.manga.repository.MangaRepository
 | 
			
		||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
 | 
			
		||||
import tachiyomi.domain.release.service.ReleaseService
 | 
			
		||||
import tachiyomi.domain.source.interactor.GetRemoteManga
 | 
			
		||||
import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
 | 
			
		||||
import tachiyomi.domain.source.repository.SourceDataRepository
 | 
			
		||||
@@ -102,6 +105,9 @@ class DomainModule : InjektModule {
 | 
			
		||||
        addFactory { UpdateManga(get()) }
 | 
			
		||||
        addFactory { SetMangaCategories(get()) }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory<ReleaseService> { ReleaseServiceImpl(get(), get()) }
 | 
			
		||||
        addFactory { GetApplicationRelease(get(), get()) }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
 | 
			
		||||
        addFactory { DeleteTrack(get()) }
 | 
			
		||||
        addFactory { GetTracksPerManga(get()) }
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,6 @@ import eu.kanade.presentation.util.Screen
 | 
			
		||||
import eu.kanade.tachiyomi.BuildConfig
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.RELEASE_URL
 | 
			
		||||
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
 | 
			
		||||
import eu.kanade.tachiyomi.util.CrashLogUtil
 | 
			
		||||
@@ -43,6 +42,7 @@ import logcat.LogPriority
 | 
			
		||||
import tachiyomi.core.util.lang.withIOContext
 | 
			
		||||
import tachiyomi.core.util.lang.withUIContext
 | 
			
		||||
import tachiyomi.core.util.system.logcat
 | 
			
		||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
 | 
			
		||||
import tachiyomi.presentation.core.components.LinkIcon
 | 
			
		||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
@@ -186,16 +186,16 @@ object AboutScreen : Screen() {
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks version and shows a user prompt if an update is available.
 | 
			
		||||
     */
 | 
			
		||||
    private suspend fun checkVersion(context: Context, onAvailableUpdate: (AppUpdateResult.NewUpdate) -> Unit) {
 | 
			
		||||
    private suspend fun checkVersion(context: Context, onAvailableUpdate: (GetApplicationRelease.Result.NewUpdate) -> Unit) {
 | 
			
		||||
        val updateChecker = AppUpdateChecker()
 | 
			
		||||
        withUIContext {
 | 
			
		||||
            context.toast(R.string.update_check_look_for_updates)
 | 
			
		||||
            try {
 | 
			
		||||
                when (val result = withIOContext { updateChecker.checkForUpdate(context, isUserPrompt = true) }) {
 | 
			
		||||
                    is AppUpdateResult.NewUpdate -> {
 | 
			
		||||
                when (val result = withIOContext { updateChecker.checkForUpdate(context, forceCheck = true) }) {
 | 
			
		||||
                    is GetApplicationRelease.Result.NewUpdate -> {
 | 
			
		||||
                        onAvailableUpdate(result)
 | 
			
		||||
                    }
 | 
			
		||||
                    is AppUpdateResult.NoNewUpdate -> {
 | 
			
		||||
                    is GetApplicationRelease.Result.NoNewUpdate -> {
 | 
			
		||||
                        context.toast(R.string.update_check_no_new_updates)
 | 
			
		||||
                    }
 | 
			
		||||
                    else -> {}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,92 +2,37 @@ package eu.kanade.tachiyomi.data.updater
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import eu.kanade.tachiyomi.BuildConfig
 | 
			
		||||
import eu.kanade.tachiyomi.network.GET
 | 
			
		||||
import eu.kanade.tachiyomi.network.NetworkHelper
 | 
			
		||||
import eu.kanade.tachiyomi.network.awaitSuccess
 | 
			
		||||
import eu.kanade.tachiyomi.network.parseAs
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import tachiyomi.core.preference.Preference
 | 
			
		||||
import tachiyomi.core.preference.PreferenceStore
 | 
			
		||||
import tachiyomi.core.util.lang.withIOContext
 | 
			
		||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.util.Date
 | 
			
		||||
import kotlin.time.Duration.Companion.days
 | 
			
		||||
 | 
			
		||||
class AppUpdateChecker {
 | 
			
		||||
 | 
			
		||||
    private val networkService: NetworkHelper by injectLazy()
 | 
			
		||||
    private val preferenceStore: PreferenceStore by injectLazy()
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
 | 
			
		||||
    private val lastAppCheck: Preference<Long> by lazy {
 | 
			
		||||
        preferenceStore.getLong("last_app_check", 0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun checkForUpdate(context: Context, isUserPrompt: Boolean = false): AppUpdateResult {
 | 
			
		||||
        // Limit checks to once every 3 days at most
 | 
			
		||||
        if (isUserPrompt.not() && Date().time < lastAppCheck.get() + 3.days.inWholeMilliseconds) {
 | 
			
		||||
            return AppUpdateResult.NoNewUpdate
 | 
			
		||||
        }
 | 
			
		||||
    private val getApplicationRelease: GetApplicationRelease by injectLazy()
 | 
			
		||||
 | 
			
		||||
    suspend fun checkForUpdate(context: Context, forceCheck: Boolean = false): GetApplicationRelease.Result {
 | 
			
		||||
        return withIOContext {
 | 
			
		||||
            val result = with(json) {
 | 
			
		||||
                networkService.client
 | 
			
		||||
                    .newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases/latest"))
 | 
			
		||||
                    .awaitSuccess()
 | 
			
		||||
                    .parseAs<GithubRelease>()
 | 
			
		||||
                    .let {
 | 
			
		||||
                        lastAppCheck.set(Date().time)
 | 
			
		||||
 | 
			
		||||
                        // Check if latest version is different from current version
 | 
			
		||||
                        if (isNewVersion(it.version)) {
 | 
			
		||||
                            if (context.isInstalledFromFDroid()) {
 | 
			
		||||
                                AppUpdateResult.NewUpdateFdroidInstallation
 | 
			
		||||
                            } else {
 | 
			
		||||
                                AppUpdateResult.NewUpdate(it)
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            AppUpdateResult.NoNewUpdate
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            }
 | 
			
		||||
            val result = getApplicationRelease.await(
 | 
			
		||||
                GetApplicationRelease.Arguments(
 | 
			
		||||
                    BuildConfig.PREVIEW,
 | 
			
		||||
                    context.isInstalledFromFDroid(),
 | 
			
		||||
                    BuildConfig.COMMIT_COUNT.toInt(),
 | 
			
		||||
                    BuildConfig.VERSION_NAME,
 | 
			
		||||
                    GITHUB_REPO,
 | 
			
		||||
                    forceCheck,
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            when (result) {
 | 
			
		||||
                is AppUpdateResult.NewUpdate -> AppUpdateNotifier(context).promptUpdate(result.release)
 | 
			
		||||
                is AppUpdateResult.NewUpdateFdroidInstallation -> AppUpdateNotifier(context).promptFdroidUpdate()
 | 
			
		||||
                is GetApplicationRelease.Result.NewUpdate -> AppUpdateNotifier(context).promptUpdate(result.release)
 | 
			
		||||
                is GetApplicationRelease.Result.ThirdPartyInstallation -> AppUpdateNotifier(context).promptFdroidUpdate()
 | 
			
		||||
                else -> {}
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            result
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun isNewVersion(versionTag: String): Boolean {
 | 
			
		||||
        // Removes prefixes like "r" or "v"
 | 
			
		||||
        val newVersion = versionTag.replace("[^\\d.]".toRegex(), "")
 | 
			
		||||
 | 
			
		||||
        return if (BuildConfig.PREVIEW) {
 | 
			
		||||
            // Preview builds: based on releases in "tachiyomiorg/tachiyomi-preview" repo
 | 
			
		||||
            // tagged as something like "r1234"
 | 
			
		||||
            newVersion.toInt() > BuildConfig.COMMIT_COUNT.toInt()
 | 
			
		||||
        } else {
 | 
			
		||||
            // Release builds: based on releases in "tachiyomiorg/tachiyomi" repo
 | 
			
		||||
            // tagged as something like "v0.1.2"
 | 
			
		||||
            val oldVersion = BuildConfig.VERSION_NAME.replace("[^\\d.]".toRegex(), "")
 | 
			
		||||
 | 
			
		||||
            val newSemVer = newVersion.split(".").map { it.toInt() }
 | 
			
		||||
            val oldSemVer = oldVersion.split(".").map { it.toInt() }
 | 
			
		||||
 | 
			
		||||
            oldSemVer.mapIndexed { index, i ->
 | 
			
		||||
                if (newSemVer[index] > i) {
 | 
			
		||||
                    return true
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val GITHUB_REPO: String by lazy {
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver
 | 
			
		||||
import eu.kanade.tachiyomi.data.notification.Notifications
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.notify
 | 
			
		||||
import tachiyomi.domain.release.model.Release
 | 
			
		||||
 | 
			
		||||
internal class AppUpdateNotifier(private val context: Context) {
 | 
			
		||||
 | 
			
		||||
@@ -27,18 +28,22 @@ internal class AppUpdateNotifier(private val context: Context) {
 | 
			
		||||
        context.notify(id, build())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun cancel() {
 | 
			
		||||
        NotificationReceiver.dismissNotification(context, Notifications.ID_APP_UPDATER)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("LaunchActivityFromNotification")
 | 
			
		||||
    fun promptUpdate(release: GithubRelease) {
 | 
			
		||||
        val intent = Intent(context, AppUpdateService::class.java).apply {
 | 
			
		||||
    fun promptUpdate(release: Release) {
 | 
			
		||||
        val updateIntent = Intent(context, AppUpdateService::class.java).run {
 | 
			
		||||
            putExtra(AppUpdateService.EXTRA_DOWNLOAD_URL, release.getDownloadLink())
 | 
			
		||||
            putExtra(AppUpdateService.EXTRA_DOWNLOAD_TITLE, release.version)
 | 
			
		||||
            PendingIntent.getService(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
 | 
			
		||||
        }
 | 
			
		||||
        val updateIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
 | 
			
		||||
 | 
			
		||||
        val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).apply {
 | 
			
		||||
        val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run {
 | 
			
		||||
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
 | 
			
		||||
            PendingIntent.getActivity(context, release.hashCode(), this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
 | 
			
		||||
        }
 | 
			
		||||
        val releaseInfoIntent = PendingIntent.getActivity(context, release.hashCode(), releaseIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
 | 
			
		||||
 | 
			
		||||
        with(notificationBuilder) {
 | 
			
		||||
            setContentTitle(context.getString(R.string.update_check_notification_update_available))
 | 
			
		||||
@@ -55,7 +60,7 @@ internal class AppUpdateNotifier(private val context: Context) {
 | 
			
		||||
            addAction(
 | 
			
		||||
                R.drawable.ic_info_24dp,
 | 
			
		||||
                context.getString(R.string.whats_new),
 | 
			
		||||
                releaseInfoIntent,
 | 
			
		||||
                releaseIntent,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        notificationBuilder.show()
 | 
			
		||||
@@ -169,8 +174,4 @@ internal class AppUpdateNotifier(private val context: Context) {
 | 
			
		||||
        }
 | 
			
		||||
        notificationBuilder.show(Notifications.ID_APP_UPDATER)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun cancel() {
 | 
			
		||||
        NotificationReceiver.dismissNotification(context, Notifications.ID_APP_UPDATER)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.updater
 | 
			
		||||
 | 
			
		||||
sealed class AppUpdateResult {
 | 
			
		||||
    class NewUpdate(val release: GithubRelease) : AppUpdateResult()
 | 
			
		||||
    object NewUpdateFdroidInstallation : AppUpdateResult()
 | 
			
		||||
    object NoNewUpdate : AppUpdateResult()
 | 
			
		||||
}
 | 
			
		||||
@@ -20,13 +20,13 @@ import eu.kanade.tachiyomi.util.storage.saveTo
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.acquireWakeLock
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
 | 
			
		||||
import kotlinx.coroutines.CancellationException
 | 
			
		||||
import kotlinx.coroutines.Job
 | 
			
		||||
import logcat.LogPriority
 | 
			
		||||
import okhttp3.Call
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.SupervisorJob
 | 
			
		||||
import kotlinx.coroutines.cancel
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import okhttp3.internal.http2.ErrorCode
 | 
			
		||||
import okhttp3.internal.http2.StreamResetException
 | 
			
		||||
import tachiyomi.core.util.lang.launchIO
 | 
			
		||||
import tachiyomi.core.util.system.logcat
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.io.File
 | 
			
		||||
 | 
			
		||||
@@ -38,11 +38,10 @@ class AppUpdateService : Service() {
 | 
			
		||||
     * Wake lock that will be held until the service is destroyed.
 | 
			
		||||
     */
 | 
			
		||||
    private lateinit var wakeLock: PowerManager.WakeLock
 | 
			
		||||
 | 
			
		||||
    private lateinit var notifier: AppUpdateNotifier
 | 
			
		||||
 | 
			
		||||
    private var runningJob: Job? = null
 | 
			
		||||
    private var runningCall: Call? = null
 | 
			
		||||
    private val job = SupervisorJob()
 | 
			
		||||
    private val serviceScope = CoroutineScope(Dispatchers.IO + job)
 | 
			
		||||
 | 
			
		||||
    override fun onCreate() {
 | 
			
		||||
        notifier = AppUpdateNotifier(this)
 | 
			
		||||
@@ -62,11 +61,11 @@ class AppUpdateService : Service() {
 | 
			
		||||
        val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return START_NOT_STICKY
 | 
			
		||||
        val title = intent.getStringExtra(EXTRA_DOWNLOAD_TITLE) ?: getString(R.string.app_name)
 | 
			
		||||
 | 
			
		||||
        runningJob = launchIO {
 | 
			
		||||
        serviceScope.launch {
 | 
			
		||||
            downloadApk(title, url)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        runningJob?.invokeOnCompletion { stopSelf(startId) }
 | 
			
		||||
        job.invokeOnCompletion { stopSelf(startId) }
 | 
			
		||||
        return START_NOT_STICKY
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -80,8 +79,8 @@ class AppUpdateService : Service() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun destroyJob() {
 | 
			
		||||
        runningJob?.cancel()
 | 
			
		||||
        runningCall?.cancel()
 | 
			
		||||
        serviceScope.cancel()
 | 
			
		||||
        job.cancel()
 | 
			
		||||
        if (wakeLock.isHeld) {
 | 
			
		||||
            wakeLock.release()
 | 
			
		||||
        }
 | 
			
		||||
@@ -116,9 +115,8 @@ class AppUpdateService : Service() {
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            // Download the new update.
 | 
			
		||||
            val call = network.client.newCachelessCallWithProgress(GET(url), progressListener)
 | 
			
		||||
            runningCall = call
 | 
			
		||||
            val response = call.await()
 | 
			
		||||
            val response = network.client.newCachelessCallWithProgress(GET(url), progressListener)
 | 
			
		||||
                .await()
 | 
			
		||||
 | 
			
		||||
            // File where the apk will be saved.
 | 
			
		||||
            val apkFile = File(externalCacheDir, "update.apk")
 | 
			
		||||
@@ -131,10 +129,9 @@ class AppUpdateService : Service() {
 | 
			
		||||
            }
 | 
			
		||||
            notifier.promptInstall(apkFile.getUriCompat(this))
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            logcat(LogPriority.ERROR, e)
 | 
			
		||||
            if (e is CancellationException ||
 | 
			
		||||
            val shouldCancel = e is CancellationException ||
 | 
			
		||||
                (e is StreamResetException && e.errorCode == ErrorCode.CANCEL)
 | 
			
		||||
            ) {
 | 
			
		||||
            if (shouldCancel) {
 | 
			
		||||
                notifier.cancel()
 | 
			
		||||
            } else {
 | 
			
		||||
                notifier.onDownloadError(url)
 | 
			
		||||
@@ -165,11 +162,11 @@ class AppUpdateService : Service() {
 | 
			
		||||
        fun start(context: Context, url: String, title: String? = context.getString(R.string.app_name)) {
 | 
			
		||||
            if (isRunning(context)) return
 | 
			
		||||
 | 
			
		||||
            val intent = Intent(context, AppUpdateService::class.java).apply {
 | 
			
		||||
            Intent(context, AppUpdateService::class.java).apply {
 | 
			
		||||
                putExtra(EXTRA_DOWNLOAD_TITLE, title)
 | 
			
		||||
                putExtra(EXTRA_DOWNLOAD_URL, url)
 | 
			
		||||
                ContextCompat.startForegroundService(context, this)
 | 
			
		||||
            }
 | 
			
		||||
            ContextCompat.startForegroundService(context, intent)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
@@ -188,10 +185,10 @@ class AppUpdateService : Service() {
 | 
			
		||||
         * @return [PendingIntent]
 | 
			
		||||
         */
 | 
			
		||||
        internal fun downloadApkPendingService(context: Context, url: String): PendingIntent {
 | 
			
		||||
            val intent = Intent(context, AppUpdateService::class.java).apply {
 | 
			
		||||
            return Intent(context, AppUpdateService::class.java).run {
 | 
			
		||||
                putExtra(EXTRA_DOWNLOAD_URL, url)
 | 
			
		||||
                PendingIntent.getService(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
 | 
			
		||||
            }
 | 
			
		||||
            return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.updater
 | 
			
		||||
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import kotlinx.serialization.SerialName
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains information about the latest release from GitHub.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
data class GithubRelease(
 | 
			
		||||
    @SerialName("tag_name") val version: String,
 | 
			
		||||
    @SerialName("body") val info: String,
 | 
			
		||||
    @SerialName("html_url") val releaseLink: String,
 | 
			
		||||
    @SerialName("assets") private val assets: List<Assets>,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.downloadLink.contains("tachiyomi$apkVariant-") }?.downloadLink
 | 
			
		||||
            ?: assets[0].downloadLink
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Assets class containing download url.
 | 
			
		||||
     */
 | 
			
		||||
    @Serializable
 | 
			
		||||
    data class Assets(@SerialName("browser_download_url") val downloadLink: String)
 | 
			
		||||
}
 | 
			
		||||
@@ -70,7 +70,6 @@ import eu.kanade.tachiyomi.data.cache.ChapterCache
 | 
			
		||||
import eu.kanade.tachiyomi.data.download.DownloadCache
 | 
			
		||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.RELEASE_URL
 | 
			
		||||
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
 | 
			
		||||
@@ -97,6 +96,7 @@ import logcat.LogPriority
 | 
			
		||||
import tachiyomi.core.Constants
 | 
			
		||||
import tachiyomi.core.util.system.logcat
 | 
			
		||||
import tachiyomi.domain.library.service.LibraryPreferences
 | 
			
		||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
@@ -328,7 +328,7 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
            if (BuildConfig.INCLUDE_UPDATER) {
 | 
			
		||||
                try {
 | 
			
		||||
                    val result = AppUpdateChecker().checkForUpdate(context)
 | 
			
		||||
                    if (result is AppUpdateResult.NewUpdate) {
 | 
			
		||||
                    if (result is GetApplicationRelease.Result.NewUpdate) {
 | 
			
		||||
                        val updateScreen = NewUpdateScreen(
 | 
			
		||||
                            versionName = result.release.version,
 | 
			
		||||
                            changelogInfo = result.release.info,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user