Check for app and extension update on every cold start (#3658)
This commit is contained in:
@@ -19,6 +19,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Detect Shizuku with permission check ([@Small-Ku](https://github.com/Small-Ku)) ([#3565](https://github.com/mihonapp/mihon/pull/3565))
|
- Detect Shizuku with permission check ([@Small-Ku](https://github.com/Small-Ku)) ([#3565](https://github.com/mihonapp/mihon/pull/3565))
|
||||||
|
- Check for app and extension update on every cold start ([@AntsyLich](https://github.com/AntsyLich)) ([#3658](https://github.com/mihonapp/mihon/pull/3658))
|
||||||
|
|
||||||
### Improved
|
### Improved
|
||||||
- Library search ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#3554](https://github.com/mihonapp/mihon/pull/3554))
|
- Library search ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#3554](https://github.com/mihonapp/mihon/pull/3554))
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class DomainModule : InjektModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addSingletonFactory<ReleaseService> { ReleaseServiceImpl(get(), get()) }
|
addSingletonFactory<ReleaseService> { ReleaseServiceImpl(get(), get()) }
|
||||||
addFactory { GetApplicationRelease(get(), get()) }
|
addFactory { GetApplicationRelease(get()) }
|
||||||
|
|
||||||
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
||||||
addFactory { TrackChapter(get(), get(), get(), get()) }
|
addFactory { TrackChapter(get(), get(), get(), get()) }
|
||||||
|
|||||||
@@ -1,53 +1,28 @@
|
|||||||
package eu.kanade.tachiyomi.extension.api
|
package eu.kanade.tachiyomi.extension.api
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.model.LoadResult
|
import eu.kanade.tachiyomi.extension.model.LoadResult
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||||
import mihon.domain.extension.interactor.UpdateExtensionStores
|
import mihon.domain.extension.interactor.UpdateExtensionStores
|
||||||
import mihon.domain.extension.repository.ExtensionStoreRepository
|
import mihon.domain.extension.repository.ExtensionStoreRepository
|
||||||
import tachiyomi.core.common.preference.Preference
|
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
|
||||||
import tachiyomi.core.common.util.lang.withIOContext
|
import tachiyomi.core.common.util.lang.withIOContext
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.time.Instant
|
|
||||||
import kotlin.time.Duration.Companion.days
|
|
||||||
|
|
||||||
internal class ExtensionApi {
|
internal class ExtensionApi {
|
||||||
|
|
||||||
private val repository: ExtensionStoreRepository by injectLazy()
|
private val repository: ExtensionStoreRepository by injectLazy()
|
||||||
|
|
||||||
private val preferenceStore: PreferenceStore by injectLazy()
|
|
||||||
private val updateExtensionStores: UpdateExtensionStores by injectLazy()
|
private val updateExtensionStores: UpdateExtensionStores by injectLazy()
|
||||||
private val extensionManager: ExtensionManager by injectLazy()
|
|
||||||
|
|
||||||
private val lastExtCheck: Preference<Long> by lazy {
|
|
||||||
preferenceStore.getLong(Preference.appStateKey("last_ext_check"), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun findExtensions(): List<Extension.Available> {
|
suspend fun findExtensions(): List<Extension.Available> {
|
||||||
return withIOContext { repository.fetchExtensions() }
|
return withIOContext { repository.fetchExtensions() }
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun checkForUpdates(
|
suspend fun checkForUpdates(context: Context) {
|
||||||
context: Context,
|
|
||||||
fromAvailableExtensionList: Boolean = false,
|
|
||||||
): List<Extension.Installed>? {
|
|
||||||
// Limit checks to once a day at most
|
|
||||||
if (!fromAvailableExtensionList &&
|
|
||||||
Instant.now().toEpochMilli() < lastExtCheck.get() + 1.days.inWholeMilliseconds
|
|
||||||
) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
updateExtensionStores()
|
updateExtensionStores()
|
||||||
|
|
||||||
val extensions = if (fromAvailableExtensionList) {
|
val extensions = findExtensions()
|
||||||
extensionManager.availableExtensionsFlow.value
|
|
||||||
} else {
|
|
||||||
findExtensions().also { lastExtCheck.set(Instant.now().toEpochMilli()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val installedExtensions = ExtensionLoader.loadExtensions(context)
|
val installedExtensions = ExtensionLoader.loadExtensions(context)
|
||||||
.filterIsInstance<LoadResult.Success>()
|
.filterIsInstance<LoadResult.Success>()
|
||||||
@@ -68,7 +43,5 @@ internal class ExtensionApi {
|
|||||||
if (extensionsWithUpdate.isNotEmpty()) {
|
if (extensionsWithUpdate.isNotEmpty()) {
|
||||||
ExtensionUpdateNotifier(context).promptUpdates(extensionsWithUpdate.map { it.name })
|
ExtensionUpdateNotifier(context).promptUpdates(extensionsWithUpdate.map { it.name })
|
||||||
}
|
}
|
||||||
|
|
||||||
return extensionsWithUpdate
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,14 @@
|
|||||||
package tachiyomi.domain.release.interactor
|
package tachiyomi.domain.release.interactor
|
||||||
|
|
||||||
import tachiyomi.core.common.preference.Preference
|
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
|
||||||
import tachiyomi.domain.release.model.Release
|
import tachiyomi.domain.release.model.Release
|
||||||
import tachiyomi.domain.release.service.ReleaseService
|
import tachiyomi.domain.release.service.ReleaseService
|
||||||
import java.time.Instant
|
|
||||||
import java.time.temporal.ChronoUnit
|
|
||||||
|
|
||||||
class GetApplicationRelease(
|
class GetApplicationRelease(
|
||||||
private val service: ReleaseService,
|
private val service: ReleaseService,
|
||||||
private val preferenceStore: PreferenceStore,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val lastChecked: Preference<Long> by lazy {
|
|
||||||
preferenceStore.getLong(Preference.appStateKey("last_app_check"), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun await(arguments: Arguments): Result {
|
suspend fun await(arguments: Arguments): Result {
|
||||||
val now = Instant.now()
|
|
||||||
|
|
||||||
// Limit checks to once every 3 days at most
|
|
||||||
val nextCheckTime = Instant.ofEpochMilli(lastChecked.get()).plus(3, ChronoUnit.DAYS)
|
|
||||||
if (!arguments.forceCheck && now.isBefore(nextCheckTime)) {
|
|
||||||
return Result.NoNewUpdate
|
|
||||||
}
|
|
||||||
|
|
||||||
val release = service.latest(arguments) ?: return Result.NoNewUpdate
|
val release = service.latest(arguments) ?: return Result.NoNewUpdate
|
||||||
|
|
||||||
lastChecked.set(now.toEpochMilli())
|
|
||||||
|
|
||||||
// Check if latest version is different from current version
|
// Check if latest version is different from current version
|
||||||
val isNewVersion = isNewVersion(
|
val isNewVersion = isNewVersion(
|
||||||
arguments.isPreview,
|
arguments.isPreview,
|
||||||
|
|||||||
+1
-47
@@ -2,39 +2,27 @@ package tachiyomi.domain.release.interactor
|
|||||||
|
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import tachiyomi.core.common.preference.Preference
|
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
|
||||||
import tachiyomi.domain.release.model.Release
|
import tachiyomi.domain.release.model.Release
|
||||||
import tachiyomi.domain.release.service.ReleaseService
|
import tachiyomi.domain.release.service.ReleaseService
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
class GetApplicationReleaseTest {
|
class GetApplicationReleaseTest {
|
||||||
|
|
||||||
private lateinit var getApplicationRelease: GetApplicationRelease
|
private lateinit var getApplicationRelease: GetApplicationRelease
|
||||||
private lateinit var releaseService: ReleaseService
|
private lateinit var releaseService: ReleaseService
|
||||||
private lateinit var preference: Preference<Long>
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun beforeEach() {
|
fun beforeEach() {
|
||||||
val preferenceStore = mockk<PreferenceStore>()
|
|
||||||
preference = mockk()
|
|
||||||
every { preferenceStore.getLong(any(), any()) } returns preference
|
|
||||||
releaseService = mockk()
|
releaseService = mockk()
|
||||||
|
|
||||||
getApplicationRelease = GetApplicationRelease(releaseService, preferenceStore)
|
getApplicationRelease = GetApplicationRelease(releaseService)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `When has update but is preview expect new update`() = runTest {
|
fun `When has update but is preview expect new update`() = runTest {
|
||||||
every { preference.get() } returns 0
|
|
||||||
every { preference.set(any()) }.answers { }
|
|
||||||
|
|
||||||
val release = Release(
|
val release = Release(
|
||||||
"r2000",
|
"r2000",
|
||||||
"info",
|
"info",
|
||||||
@@ -61,9 +49,6 @@ class GetApplicationReleaseTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `When has update expect new update`() = runTest {
|
fun `When has update expect new update`() = runTest {
|
||||||
every { preference.get() } returns 0
|
|
||||||
every { preference.set(any()) }.answers { }
|
|
||||||
|
|
||||||
val release = Release(
|
val release = Release(
|
||||||
"v2.0.0",
|
"v2.0.0",
|
||||||
"info",
|
"info",
|
||||||
@@ -90,9 +75,6 @@ class GetApplicationReleaseTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `When has no update expect no new update`() = runTest {
|
fun `When has no update expect no new update`() = runTest {
|
||||||
every { preference.get() } returns 0
|
|
||||||
every { preference.set(any()) }.answers { }
|
|
||||||
|
|
||||||
val release = Release(
|
val release = Release(
|
||||||
"v1.0.0",
|
"v1.0.0",
|
||||||
"info",
|
"info",
|
||||||
@@ -114,32 +96,4 @@ class GetApplicationReleaseTest {
|
|||||||
|
|
||||||
result shouldBe GetApplicationRelease.Result.NoNewUpdate
|
result shouldBe GetApplicationRelease.Result.NoNewUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `When now is before three days expect no new update`() = runTest {
|
|
||||||
every { preference.get() } returns Instant.now().toEpochMilli()
|
|
||||||
every { preference.set(any()) }.answers { }
|
|
||||||
|
|
||||||
val release = Release(
|
|
||||||
"v1.0.0",
|
|
||||||
"info",
|
|
||||||
"http://example.com/release_link",
|
|
||||||
"http://example.com/release_link.apk",
|
|
||||||
)
|
|
||||||
|
|
||||||
coEvery { releaseService.latest(any()) } returns release
|
|
||||||
|
|
||||||
val result = getApplicationRelease.await(
|
|
||||||
GetApplicationRelease.Arguments(
|
|
||||||
isFoss = false,
|
|
||||||
isPreview = false,
|
|
||||||
commitCount = 0,
|
|
||||||
versionName = "v2.0.0",
|
|
||||||
repository = "test",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
coVerify(exactly = 0) { releaseService.latest(any()) }
|
|
||||||
result shouldBe GetApplicationRelease.Result.NoNewUpdate
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user