mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Add in-app app update check
This commit is contained in:
		@@ -269,6 +269,7 @@ class PreferencesHelper(val context: Context) {
 | 
			
		||||
 | 
			
		||||
    fun extensionUpdatesCount() = flowPrefs.getInt("ext_updates_count", 0)
 | 
			
		||||
 | 
			
		||||
    fun lastAppCheck() = flowPrefs.getLong("last_app_check", 0)
 | 
			
		||||
    fun lastExtCheck() = flowPrefs.getLong("last_ext_check", 0)
 | 
			
		||||
 | 
			
		||||
    fun searchPinnedSourcesOnly() = prefs.getBoolean(Keys.searchPinnedSourcesOnly, false)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,19 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.updater
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.BuildConfig
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.network.GET
 | 
			
		||||
import eu.kanade.tachiyomi.network.NetworkHelper
 | 
			
		||||
import eu.kanade.tachiyomi.network.await
 | 
			
		||||
import eu.kanade.tachiyomi.network.parseAs
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.withIOContext
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.util.Date
 | 
			
		||||
 | 
			
		||||
class GithubUpdateChecker {
 | 
			
		||||
class AppUpdateChecker {
 | 
			
		||||
 | 
			
		||||
    private val networkService: NetworkHelper by injectLazy()
 | 
			
		||||
    private val preferences: PreferencesHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    private val repo: String by lazy {
 | 
			
		||||
        if (BuildConfig.DEBUG) {
 | 
			
		||||
@@ -20,18 +23,20 @@ class GithubUpdateChecker {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun checkForUpdate(): GithubUpdateResult {
 | 
			
		||||
    suspend fun checkForUpdate(): AppUpdateResult {
 | 
			
		||||
        return withIOContext {
 | 
			
		||||
            networkService.client
 | 
			
		||||
                .newCall(GET("https://api.github.com/repos/$repo/releases/latest"))
 | 
			
		||||
                .await()
 | 
			
		||||
                .parseAs<GithubRelease>()
 | 
			
		||||
                .let {
 | 
			
		||||
                    preferences.lastAppCheck().set(Date().time)
 | 
			
		||||
 | 
			
		||||
                    // Check if latest version is different from current version
 | 
			
		||||
                    if (isNewVersion(it.version)) {
 | 
			
		||||
                        GithubUpdateResult.NewUpdate(it)
 | 
			
		||||
                        AppUpdateResult.NewUpdate(it)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        GithubUpdateResult.NoNewUpdate
 | 
			
		||||
                        AppUpdateResult.NoNewUpdate
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.updater
 | 
			
		||||
 | 
			
		||||
sealed class AppUpdateResult {
 | 
			
		||||
    class NewUpdate(val release: GithubRelease) : AppUpdateResult()
 | 
			
		||||
    object NoNewUpdate : AppUpdateResult()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.updater
 | 
			
		||||
 | 
			
		||||
sealed class GithubUpdateResult {
 | 
			
		||||
    class NewUpdate(val release: GithubRelease) : GithubUpdateResult()
 | 
			
		||||
    object NoNewUpdate : GithubUpdateResult()
 | 
			
		||||
}
 | 
			
		||||
@@ -16,9 +16,9 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
 | 
			
		||||
 | 
			
		||||
    override fun doWork() = runBlocking {
 | 
			
		||||
        try {
 | 
			
		||||
            val result = GithubUpdateChecker().checkForUpdate()
 | 
			
		||||
            val result = AppUpdateChecker().checkForUpdate()
 | 
			
		||||
 | 
			
		||||
            if (result is GithubUpdateResult.NewUpdate) {
 | 
			
		||||
            if (result is AppUpdateResult.NewUpdate) {
 | 
			
		||||
                UpdaterNotifier(context).promptUpdate(result.release.getDownloadLink())
 | 
			
		||||
            }
 | 
			
		||||
            Result.success()
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,8 @@ import eu.kanade.tachiyomi.Migrations
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.MainActivityBinding
 | 
			
		||||
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseViewBindingActivity
 | 
			
		||||
@@ -52,6 +54,7 @@ import eu.kanade.tachiyomi.ui.download.DownloadController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.library.LibraryController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.more.MoreController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.more.NewUpdateDialogController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
 | 
			
		||||
@@ -334,19 +337,32 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
 | 
			
		||||
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
        super.onResume()
 | 
			
		||||
        getExtensionUpdates()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setExtensionsBadge() {
 | 
			
		||||
        val updates = preferences.extensionUpdatesCount().get()
 | 
			
		||||
        if (updates > 0) {
 | 
			
		||||
            nav.getOrCreateBadge(R.id.nav_browse).number = updates
 | 
			
		||||
        } else {
 | 
			
		||||
            nav.removeBadge(R.id.nav_browse)
 | 
			
		||||
        checkForExtensionUpdates()
 | 
			
		||||
        if (BuildConfig.INCLUDE_UPDATER) {
 | 
			
		||||
            checkForAppUpdates()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getExtensionUpdates() {
 | 
			
		||||
    private fun checkForAppUpdates() {
 | 
			
		||||
        // Limit checks to once a day at most
 | 
			
		||||
        if (Date().time < preferences.lastAppCheck().get() + TimeUnit.DAYS.toMillis(1)) {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        lifecycleScope.launchIO {
 | 
			
		||||
            try {
 | 
			
		||||
                val result = AppUpdateChecker().checkForUpdate()
 | 
			
		||||
                if (result is AppUpdateResult.NewUpdate) {
 | 
			
		||||
                    NewUpdateDialogController(result).showDialog(router)
 | 
			
		||||
                }
 | 
			
		||||
            } catch (e: Exception) {
 | 
			
		||||
                Timber.e(e)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun checkForExtensionUpdates() {
 | 
			
		||||
        // Limit checks to once a day at most
 | 
			
		||||
        if (Date().time < preferences.lastExtCheck().get() + TimeUnit.DAYS.toMillis(1)) {
 | 
			
		||||
            return
 | 
			
		||||
@@ -362,6 +378,15 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setExtensionsBadge() {
 | 
			
		||||
        val updates = preferences.extensionUpdatesCount().get()
 | 
			
		||||
        if (updates > 0) {
 | 
			
		||||
            nav.getOrCreateBadge(R.id.nav_browse).number = updates
 | 
			
		||||
        } else {
 | 
			
		||||
            nav.removeBadge(R.id.nav_browse)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun handleIntentAction(intent: Intent): Boolean {
 | 
			
		||||
        val notificationId = intent.getIntExtra("notificationId", -1)
 | 
			
		||||
        if (notificationId > -1) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,10 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.more
 | 
			
		||||
 | 
			
		||||
import android.app.Dialog
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.core.os.bundleOf
 | 
			
		||||
import androidx.preference.PreferenceScreen
 | 
			
		||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
 | 
			
		||||
import eu.kanade.tachiyomi.BuildConfig
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.GithubUpdateResult
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.UpdaterService
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 | 
			
		||||
@@ -33,12 +27,10 @@ import java.util.TimeZone
 | 
			
		||||
 | 
			
		||||
class AboutController : SettingsController(), NoToolbarElevationController {
 | 
			
		||||
 | 
			
		||||
    private val updateChecker by lazy { GithubUpdateChecker() }
 | 
			
		||||
    private val updateChecker by lazy { AppUpdateChecker() }
 | 
			
		||||
 | 
			
		||||
    private val dateFormat: DateFormat = preferences.dateFormat()
 | 
			
		||||
 | 
			
		||||
    private val isUpdaterEnabled = BuildConfig.INCLUDE_UPDATER
 | 
			
		||||
 | 
			
		||||
    override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
 | 
			
		||||
        titleRes = R.string.pref_category_about
 | 
			
		||||
 | 
			
		||||
@@ -60,7 +52,7 @@ class AboutController : SettingsController(), NoToolbarElevationController {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (isUpdaterEnabled) {
 | 
			
		||||
        if (BuildConfig.INCLUDE_UPDATER) {
 | 
			
		||||
            preference {
 | 
			
		||||
                key = "pref_about_check_for_updates"
 | 
			
		||||
                titleRes = R.string.check_for_updates
 | 
			
		||||
@@ -103,14 +95,10 @@ class AboutController : SettingsController(), NoToolbarElevationController {
 | 
			
		||||
        launchNow {
 | 
			
		||||
            try {
 | 
			
		||||
                when (val result = updateChecker.checkForUpdate()) {
 | 
			
		||||
                    is GithubUpdateResult.NewUpdate -> {
 | 
			
		||||
                        val body = result.release.info
 | 
			
		||||
                        val url = result.release.getDownloadLink()
 | 
			
		||||
 | 
			
		||||
                        // Create confirmation window
 | 
			
		||||
                        NewUpdateDialogController(body, url).showDialog(router)
 | 
			
		||||
                    is AppUpdateResult.NewUpdate -> {
 | 
			
		||||
                        NewUpdateDialogController(result).showDialog(router)
 | 
			
		||||
                    }
 | 
			
		||||
                    is GithubUpdateResult.NoNewUpdate -> {
 | 
			
		||||
                    is AppUpdateResult.NoNewUpdate -> {
 | 
			
		||||
                        activity?.toast(R.string.update_check_no_new_updates)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -121,34 +109,6 @@ class AboutController : SettingsController(), NoToolbarElevationController {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {
 | 
			
		||||
 | 
			
		||||
        constructor(body: String, url: String) : this(
 | 
			
		||||
            bundleOf(BODY_KEY to body, URL_KEY to url)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        override fun onCreateDialog(savedViewState: Bundle?): Dialog {
 | 
			
		||||
            return MaterialAlertDialogBuilder(activity!!)
 | 
			
		||||
                .setTitle(R.string.update_check_notification_update_available)
 | 
			
		||||
                .setMessage(args.getString(BODY_KEY) ?: "")
 | 
			
		||||
                .setPositiveButton(R.string.update_check_confirm) { _, _ ->
 | 
			
		||||
                    val appContext = applicationContext
 | 
			
		||||
                    if (appContext != null) {
 | 
			
		||||
                        // Start download
 | 
			
		||||
                        val url = args.getString(URL_KEY) ?: ""
 | 
			
		||||
                        UpdaterService.start(appContext, url)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .setNegativeButton(R.string.update_check_ignore, null)
 | 
			
		||||
                .create()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private companion object {
 | 
			
		||||
            const val BODY_KEY = "NewUpdateDialogController.body"
 | 
			
		||||
            const val URL_KEY = "NewUpdateDialogController.key"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getFormattedBuildTime(): String {
 | 
			
		||||
        return try {
 | 
			
		||||
            val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.more
 | 
			
		||||
 | 
			
		||||
import android.app.Dialog
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.core.os.bundleOf
 | 
			
		||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
 | 
			
		||||
import eu.kanade.tachiyomi.data.updater.UpdaterService
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
 | 
			
		||||
 | 
			
		||||
class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {
 | 
			
		||||
 | 
			
		||||
    constructor(update: AppUpdateResult.NewUpdate) : this(
 | 
			
		||||
        bundleOf(BODY_KEY to update.release.info, URL_KEY to update.release.getDownloadLink())
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override fun onCreateDialog(savedViewState: Bundle?): Dialog {
 | 
			
		||||
        return MaterialAlertDialogBuilder(activity!!)
 | 
			
		||||
            .setTitle(R.string.update_check_notification_update_available)
 | 
			
		||||
            .setMessage(args.getString(BODY_KEY) ?: "")
 | 
			
		||||
            .setPositiveButton(R.string.update_check_confirm) { _, _ ->
 | 
			
		||||
                val appContext = applicationContext
 | 
			
		||||
                if (appContext != null) {
 | 
			
		||||
                    // Start download
 | 
			
		||||
                    val url = args.getString(URL_KEY) ?: ""
 | 
			
		||||
                    UpdaterService.start(appContext, url)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .setNegativeButton(R.string.update_check_ignore, null)
 | 
			
		||||
            .create()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private companion object {
 | 
			
		||||
        const val BODY_KEY = "NewUpdateDialogController.body"
 | 
			
		||||
        const val URL_KEY = "NewUpdateDialogController.key"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user