Use coroutines for updater

This commit is contained in:
arkon 2020-02-09 22:24:56 -05:00
parent 340829bb71
commit 6a95ff56df
9 changed files with 67 additions and 81 deletions

View file

@ -110,16 +110,16 @@ dependencies {
// Android support library
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.multidex:multidex:2.0.1'
// UI library
implementation 'com.google.android.material:material:1.1.0'
standardImplementation 'com.google.firebase:firebase-core:17.2.2'
// ReactiveX
@ -221,7 +221,7 @@ dependencies {
implementation "com.jakewharton.rxbinding:rxbinding-recyclerview-v7-kotlin:$rxbindings_version"
// Tests
testImplementation 'junit:junit:4.12'
testImplementation 'junit:junit:4.13'
testImplementation 'org.assertj:assertj-core:1.7.1'
testImplementation 'org.mockito:mockito-core:1.10.19'

View file

@ -53,12 +53,11 @@ class TrackSearch : Track {
result = 31 * result + media_id
return result
}
companion object {
companion object {
fun create(serviceId: Int): TrackSearch = TrackSearch().apply {
sync_id = serviceId
}
}
}
}

View file

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.updater
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.data.updater.devrepo.DevRepoUpdateChecker
import eu.kanade.tachiyomi.data.updater.github.GithubUpdateChecker
import rx.Observable
abstract class UpdateChecker {
@ -20,6 +19,6 @@ abstract class UpdateChecker {
/**
* Returns observable containing release information
*/
abstract fun checkForUpdate(): Observable<UpdateResult>
abstract suspend fun checkForUpdate(): UpdateResult
}

View file

@ -9,36 +9,37 @@ import com.evernote.android.job.JobRequest
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.system.notificationManager
import kotlinx.coroutines.runBlocking
class UpdaterJob : Job() {
override fun onRunJob(params: Params): Result {
return UpdateChecker.getUpdateChecker()
.checkForUpdate()
.map { result ->
if (result is UpdateResult.NewUpdate<*>) {
val url = result.release.downloadLink
return runBlocking {
try {
val result = UpdateChecker.getUpdateChecker().checkForUpdate()
val intent = Intent(context, UpdaterService::class.java).apply {
putExtra(UpdaterService.EXTRA_DOWNLOAD_URL, url)
}
if (result is UpdateResult.NewUpdate<*>) {
val url = result.release.downloadLink
NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON).update {
setContentTitle(context.getString(R.string.app_name))
setContentText(context.getString(R.string.update_check_notification_update_available))
setSmallIcon(android.R.drawable.stat_sys_download_done)
// Download action
addAction(android.R.drawable.stat_sys_download_done,
context.getString(R.string.action_download),
PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))
}
val intent = Intent(context, UpdaterService::class.java).apply {
putExtra(UpdaterService.EXTRA_DOWNLOAD_URL, url)
}
NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON).update {
setContentTitle(context.getString(R.string.app_name))
setContentText(context.getString(R.string.update_check_notification_update_available))
setSmallIcon(android.R.drawable.stat_sys_download_done)
// Download action
addAction(android.R.drawable.stat_sys_download_done,
context.getString(R.string.action_download),
PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))
}
Result.SUCCESS
}
.onErrorReturn { Result.FAILURE }
// Sadly, the task needs to be synchronous.
.toBlocking()
.single()
Result.SUCCESS
} catch (e: Exception) {
Result.FAILURE
}
}
}
fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) {

View file

@ -5,9 +5,8 @@ import eu.kanade.tachiyomi.data.updater.UpdateChecker
import eu.kanade.tachiyomi.data.updater.UpdateResult
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.asObservable
import eu.kanade.tachiyomi.network.await
import okhttp3.OkHttpClient
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -23,18 +22,17 @@ class DevRepoUpdateChecker : UpdateChecker() {
Regex("tachiyomi-r(\\d+).apk")
}
override fun checkForUpdate(): Observable<UpdateResult> {
return client.newCall(GET(DevRepoRelease.LATEST_URL)).asObservable()
.map { response ->
// Get latest repo version number from header in format "Location: tachiyomi-r1512.apk"
val latestVersionNumber: String = versionRegex.find(response.header("Location")!!)!!.groupValues[1]
override suspend fun checkForUpdate(): UpdateResult {
val response = client.newCall(GET(DevRepoRelease.LATEST_URL)).await(assertSuccess = false)
if (latestVersionNumber.toInt() > BuildConfig.COMMIT_COUNT.toInt()) {
DevRepoUpdateResult.NewUpdate(DevRepoRelease("v$latestVersionNumber"))
} else {
DevRepoUpdateResult.NoNewUpdate()
}
}
// Get latest repo version number from header in format "Location: tachiyomi-r1512.apk"
val latestVersionNumber: String = versionRegex.find(response.header("Location")!!)!!.groupValues[1]
return if (latestVersionNumber.toInt() > BuildConfig.COMMIT_COUNT.toInt()) {
DevRepoUpdateResult.NewUpdate(DevRepoRelease("v$latestVersionNumber"))
} else {
DevRepoUpdateResult.NoNewUpdate()
}
}
}

View file

@ -5,7 +5,6 @@ import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -28,6 +27,6 @@ interface GithubService {
}
@GET("/repos/inorichi/tachiyomi/releases/latest")
fun getLatestVersion(): Observable<GithubRelease>
suspend fun getLatestVersion(): GithubRelease
}

View file

@ -3,22 +3,21 @@ package eu.kanade.tachiyomi.data.updater.github
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.data.updater.UpdateChecker
import eu.kanade.tachiyomi.data.updater.UpdateResult
import rx.Observable
class GithubUpdateChecker : UpdateChecker() {
private val service: GithubService = GithubService.create()
override fun checkForUpdate(): Observable<UpdateResult> {
return service.getLatestVersion().map { release ->
val newVersion = release.version.replace("[^\\d.]".toRegex(), "")
override suspend fun checkForUpdate(): UpdateResult {
val release = service.getLatestVersion()
// Check if latest version is different from current version
if (newVersion != BuildConfig.VERSION_NAME) {
GithubUpdateResult.NewUpdate(release)
} else {
GithubUpdateResult.NoNewUpdate()
}
val newVersion = release.version.replace("[^\\d.]".toRegex(), "")
// Check if latest version is different from current version
return if (newVersion != BuildConfig.VERSION_NAME) {
GithubUpdateResult.NewUpdate(release)
} else {
GithubUpdateResult.NoNewUpdate()
}
}

View file

@ -48,11 +48,11 @@ fun Call.asObservable(): Observable<Response> {
}
// Based on https://github.com/gildor/kotlin-coroutines-okhttp
suspend fun Call.await(): Response {
suspend fun Call.await(assertSuccess: Boolean = false): Response {
return suspendCancellableCoroutine { continuation ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (!response.isSuccessful) {
if (assertSuccess && !response.isSuccessful) {
continuation.resumeWithException(Exception("HTTP error ${response.code}"))
return
}

View file

@ -4,7 +4,6 @@ import android.app.Dialog
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.preference.PreferenceScreen
import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.BuildConfig
@ -17,12 +16,11 @@ import eu.kanade.tachiyomi.data.updater.UpdaterJob
import eu.kanade.tachiyomi.data.updater.UpdaterService
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.main.ChangelogDialogController
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.lang.toTimestampString
import eu.kanade.tachiyomi.util.preference.*
import eu.kanade.tachiyomi.util.system.toast
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
import java.text.DateFormat
@ -43,11 +41,6 @@ class SettingsAboutController : SettingsController() {
private val dateFormat: DateFormat = userPreferences.dateFormat().getOrDefault()
/**
* The subscribtion service of the obtained release object
*/
private var releaseSubscription: Subscription? = null
private val isUpdaterEnabled = BuildConfig.INCLUDE_UPDATER
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
@ -118,12 +111,6 @@ class SettingsAboutController : SettingsController() {
}
}
override fun onDestroyView(view: View) {
super.onDestroyView(view)
releaseSubscription?.unsubscribe()
releaseSubscription = null
}
/**
* Checks version and shows a user prompt if an update is available.
*/
@ -131,11 +118,11 @@ class SettingsAboutController : SettingsController() {
if (activity == null) return
activity?.toast(R.string.update_check_look_for_updates)
releaseSubscription?.unsubscribe()
releaseSubscription = updateChecker.checkForUpdate()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ result ->
launchIO {
try {
val result = updateChecker.checkForUpdate()
launchUI {
when (result) {
is UpdateResult.NewUpdate<*> -> {
val body = result.release.info
@ -148,10 +135,14 @@ class SettingsAboutController : SettingsController() {
activity?.toast(R.string.update_check_no_new_updates)
}
}
}, { error ->
}
} catch (error: Exception) {
launchUI {
activity?.toast(error.message)
Timber.e(error)
})
}
}
}
}
class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {