diff --git a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt index bf9ec8ec3..b669309fb 100644 --- a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt @@ -16,8 +16,6 @@ class BasePreferences( fun incognitoMode() = preferenceStore.getBoolean("incognito_mode", false) - fun automaticExtUpdates() = preferenceStore.getBoolean("automatic_ext_updates", true) - fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore) fun acraEnabled() = preferenceStore.getBoolean("acra.enable", isPreviewBuildType || isReleaseBuildType) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt index 773a896c0..01fb87e7e 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt @@ -7,11 +7,9 @@ import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.fragment.app.FragmentActivity -import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.more.settings.Preference import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -27,21 +25,7 @@ object SettingsBrowseScreen : SearchableSettings { override fun getPreferences(): List { val context = LocalContext.current val sourcePreferences = remember { Injekt.get() } - val preferences = remember { Injekt.get() } return listOf( - Preference.PreferenceGroup( - title = stringResource(R.string.label_extensions), - preferenceItems = listOf( - Preference.PreferenceItem.SwitchPreference( - pref = preferences.automaticExtUpdates(), - title = stringResource(R.string.pref_enable_automatic_extension_updates), - onValueChanged = { - ExtensionUpdateJob.setupTask(context, it) - true - }, - ), - ), - ), Preference.PreferenceGroup( title = stringResource(R.string.label_sources), preferenceItems = listOf( diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 21d5c5b73..2f3e3d502 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED import eu.kanade.tachiyomi.data.preference.PreferenceValues import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE import eu.kanade.tachiyomi.ui.reader.setting.OrientationType @@ -55,7 +54,6 @@ object Migrations { lastVersionCode.set(BuildConfig.VERSION_CODE) // Always set up background tasks to ensure they're running - ExtensionUpdateJob.setupTask(context) LibraryUpdateJob.setupTask(context) BackupCreatorJob.setupTask(context) @@ -100,9 +98,6 @@ object Migrations { // Restore jobs after migrating from Evernote's job scheduler to WorkManager. LibraryUpdateJob.setupTask(context) BackupCreatorJob.setupTask(context) - - // New extension update check job - ExtensionUpdateJob.setupTask(context) } if (oldVersion < 44) { // Reset sorting preference if using removed sort by source @@ -333,7 +328,12 @@ object Migrations { LibraryUpdateJob.setupTask(context) } if (oldVersion < 97) { + // Removed background jobs WorkManager.getInstance(context).cancelAllWorkByTag("UpdateChecker") + WorkManager.getInstance(context).cancelAllWorkByTag("ExtensionUpdate") + prefs.edit { + remove("automatic_ext_updates") + } } return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt deleted file mode 100644 index dfd4b55c4..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt +++ /dev/null @@ -1,94 +0,0 @@ -package eu.kanade.tachiyomi.extension - -import android.content.Context -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationManagerCompat -import androidx.work.Constraints -import androidx.work.CoroutineWorker -import androidx.work.ExistingPeriodicWorkPolicy -import androidx.work.NetworkType -import androidx.work.PeriodicWorkRequestBuilder -import androidx.work.WorkManager -import androidx.work.WorkerParameters -import eu.kanade.domain.base.BasePreferences -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.notification.NotificationReceiver -import eu.kanade.tachiyomi.data.notification.Notifications -import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi -import eu.kanade.tachiyomi.util.system.notification -import kotlinx.coroutines.coroutineScope -import logcat.LogPriority -import tachiyomi.core.util.system.logcat -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.util.concurrent.TimeUnit - -class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParameters) : - CoroutineWorker(context, workerParams) { - - override suspend fun doWork(): Result = coroutineScope { - val pendingUpdates = try { - ExtensionGithubApi().checkForUpdates(context) - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) - return@coroutineScope Result.failure() - } - - if (!pendingUpdates.isNullOrEmpty()) { - createUpdateNotification(pendingUpdates.map { it.name }) - } - - Result.success() - } - - private fun createUpdateNotification(names: List) { - NotificationManagerCompat.from(context).apply { - notify( - Notifications.ID_UPDATES_TO_EXTS, - context.notification(Notifications.CHANNEL_EXTENSIONS_UPDATE) { - setContentTitle( - context.resources.getQuantityString( - R.plurals.update_check_notification_ext_updates, - names.size, - names.size, - ), - ) - val extNames = names.joinToString(", ") - setContentText(extNames) - setStyle(NotificationCompat.BigTextStyle().bigText(extNames)) - setSmallIcon(R.drawable.ic_extension_24dp) - setContentIntent(NotificationReceiver.openExtensionsPendingActivity(context)) - setAutoCancel(true) - }, - ) - } - } - - companion object { - private const val TAG = "ExtensionUpdate" - - fun setupTask(context: Context, forceAutoUpdateJob: Boolean? = null) { - val preferences = Injekt.get() - val autoUpdateJob = forceAutoUpdateJob ?: preferences.automaticExtUpdates().get() - if (autoUpdateJob) { - val constraints = Constraints( - requiredNetworkType = NetworkType.CONNECTED, - ) - - val request = PeriodicWorkRequestBuilder( - 2, - TimeUnit.DAYS, - 3, - TimeUnit.HOURS, - ) - .addTag(TAG) - .setConstraints(constraints) - .build() - - WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.UPDATE, request) - } else { - WorkManager.getInstance(context).cancelAllWorkByTag(TAG) - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index d83d53bfa..99017344b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt @@ -18,7 +18,7 @@ import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.system.logcat import uy.kohesive.injekt.injectLazy import java.util.Date -import java.util.concurrent.TimeUnit +import kotlin.time.Duration.Companion.days internal class ExtensionGithubApi { @@ -69,7 +69,7 @@ internal class ExtensionGithubApi { suspend fun checkForUpdates(context: Context, fromAvailableExtensionList: Boolean = false): List? { // Limit checks to once a day at most - if (fromAvailableExtensionList.not() && Date().time < lastExtCheck.get() + TimeUnit.DAYS.toMillis(1)) { + if (!fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) { return null } @@ -95,6 +95,10 @@ internal class ExtensionGithubApi { } } + if (extensionsWithUpdate.isNotEmpty()) { + ExtensionUpdateNotifier(context).promptUpdates(extensionsWithUpdate.map { it.name }) + } + return extensionsWithUpdate } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionUpdateNotifier.kt new file mode 100644 index 000000000..e63b72832 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionUpdateNotifier.kt @@ -0,0 +1,42 @@ +package eu.kanade.tachiyomi.extension.api + +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.notification.NotificationReceiver +import eu.kanade.tachiyomi.data.notification.Notifications +import eu.kanade.tachiyomi.util.system.notification + +class ExtensionUpdateNotifier(private val context: Context) { + + fun promptUpdates(names: List) { + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + return + } + + NotificationManagerCompat.from(context).apply { + notify( + Notifications.ID_UPDATES_TO_EXTS, + context.notification(Notifications.CHANNEL_EXTENSIONS_UPDATE) { + setContentTitle( + context.resources.getQuantityString( + R.plurals.update_check_notification_ext_updates, + names.size, + names.size, + ), + ) + val extNames = names.joinToString(", ") + setContentText(extNames) + setStyle(NotificationCompat.BigTextStyle().bigText(extNames)) + setSmallIcon(R.drawable.ic_extension_24dp) + setContentIntent(NotificationReceiver.openExtensionsPendingActivity(context)) + setAutoCancel(true) + }, + ) + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index dd81afa57..a361d7aee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -71,6 +71,7 @@ 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 import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen @@ -256,7 +257,7 @@ class MainActivity : BaseActivity() { .launchIn(this) } - CheckForUpdate() + CheckForUpdates() } var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) } @@ -320,11 +321,12 @@ class MainActivity : BaseActivity() { } @Composable - private fun CheckForUpdate() { + private fun CheckForUpdates() { val context = LocalContext.current val navigator = LocalNavigator.currentOrThrow + + // App updates LaunchedEffect(Unit) { - // App updates if (BuildConfig.INCLUDE_UPDATER) { try { val result = AppUpdateChecker().checkForUpdate(context) @@ -342,6 +344,15 @@ class MainActivity : BaseActivity() { } } } + + // Extensions updates + LaunchedEffect(Unit) { + try { + ExtensionGithubApi().checkForUpdates(context) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + } + } } /** diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 9c61e0ea7..ebb9ad96c 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -456,7 +456,6 @@ Track - Check for extension updates Only search pinned sources in global search Hide entries already in library