From 9585f9a1a6432ede89c02c7874ecf35a845c0b41 Mon Sep 17 00:00:00 2001 From: Jays2Kings Date: Fri, 20 Mar 2020 19:22:39 -0700 Subject: [PATCH] Option to auto check for extension updates (#2680) * Option to auto check for extension updates * Addressing comments * Added foreground check for extensions * Added Extension Preference widget --- .../data/notification/NotificationReceiver.kt | 14 +++ .../data/notification/Notifications.kt | 11 ++- .../data/preference/PreferenceKeys.kt | 2 + .../data/preference/PreferencesHelper.kt | 6 ++ .../tachiyomi/extension/ExtensionManager.kt | 5 ++ .../tachiyomi/extension/ExtensionUpdateJob.kt | 86 +++++++++++++++++++ .../extension/api/ExtensionGithubApi.kt | 33 ++++++- .../ui/extension/ExtensionController.kt | 19 +++- .../kanade/tachiyomi/ui/main/MainActivity.kt | 57 ++++++++++-- .../tachiyomi/ui/more/MoreController.kt | 3 +- .../util/preference/PreferenceDSL.kt | 5 ++ .../widget/preference/ExtensionPreference.kt | 37 ++++++++ .../drawable/round_textview_background.xml | 9 ++ .../res/layout/preference_update_text.xml | 17 ++++ app/src/main/res/menu/extension_main.xml | 6 ++ app/src/main/res/values/strings.xml | 8 ++ 16 files changed, 308 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/widget/preference/ExtensionPreference.kt create mode 100644 app/src/main/res/drawable/round_textview_background.xml create mode 100644 app/src/main/res/layout/preference_update_text.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 9e6522d5a..8a6b7b98e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -437,5 +437,19 @@ class NotificationReceiver : BroadcastReceiver() { } return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } + + /** + * Returns [PendingIntent] that opens the extensions controller. + * + * @param context context of application + */ + internal fun openExtensionsPendingActivity(context: Context): PendingIntent { + val newIntent = + Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_EXTENSIONS) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + return PendingIntent.getActivity( + context, 0, newIntent, PendingIntent.FLAG_UPDATE_CURRENT + ) + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt index b59b40dbf..b9b2f98e1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt @@ -39,6 +39,12 @@ object Notifications { const val ID_NEW_CHAPTERS = -301 const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS" + /** + * Notification channel and ids used by the library updater. + */ + const val CHANNEL_UPDATES_TO_EXTS = "updates_ext_channel" + const val ID_UPDATES_TO_EXTS = -401 + /** * Creates the notification channels introduced in Android Oreo. * @@ -59,7 +65,10 @@ object Notifications { setShowBadge(false) }, NotificationChannel(CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters), - NotificationManager.IMPORTANCE_DEFAULT) + NotificationManager.IMPORTANCE_DEFAULT), + NotificationChannel(CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates), + NotificationManager.IMPORTANCE_DEFAULT + ) ) context.notificationManager.createNotificationChannels(channels) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 0f7ccd312..e43c2e957 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -107,6 +107,8 @@ object PreferenceKeys { const val automaticUpdates = "automatic_updates" + const val automaticExtUpdates = "automatic_ext_updates" + const val startScreen = "start_screen" const val useBiometricLock = "use_biometric_lock" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index f2b33f243..9782fe52a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -190,6 +190,12 @@ class PreferencesHelper(val context: Context) { fun automaticUpdates() = prefs.getBoolean(Keys.automaticUpdates, true) + fun automaticExtUpdates() = rxPrefs.getBoolean(Keys.automaticExtUpdates, false) + + fun extensionUpdatesCount() = rxPrefs.getInteger("ext_updates_count", 0) + + fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0) + fun hiddenCatalogues() = rxPrefs.getStringSet("hidden_catalogues", emptySet()) fun downloadNew() = rxPrefs.getBoolean(Keys.downloadNew, false) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index 9dbd347e5..dd41d986c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -162,6 +162,7 @@ class ExtensionManager( */ private fun updatedInstalledExtensionsStatuses(availableExtensions: List) { if (availableExtensions.isEmpty()) { + preferences.extensionUpdatesCount().set(0) return } @@ -186,6 +187,7 @@ class ExtensionManager( if (changed) { installedExtensions = mutInstalledExtensions } + preferences.extensionUpdatesCount().set(installedExtensions.count { it.hasUpdate }) } /** @@ -316,10 +318,12 @@ class ExtensionManager( override fun onExtensionInstalled(extension: Extension.Installed) { registerNewExtension(extension.withUpdateCheck()) + preferences.extensionUpdatesCount().set(installedExtensions.count { it.hasUpdate }) } override fun onExtensionUpdated(extension: Extension.Installed) { registerUpdatedExtension(extension.withUpdateCheck()) + preferences.extensionUpdatesCount().set(installedExtensions.count { it.hasUpdate }) } override fun onExtensionUntrusted(extension: Extension.Untrusted) { @@ -328,6 +332,7 @@ class ExtensionManager( override fun onPackageUninstalled(pkgName: String) { unregisterExtension(pkgName) + preferences.extensionUpdatesCount().set(installedExtensions.count { it.hasUpdate }) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt new file mode 100644 index 000000000..01866d848 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt @@ -0,0 +1,86 @@ +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.tachiyomi.R +import eu.kanade.tachiyomi.data.notification.NotificationReceiver +import eu.kanade.tachiyomi.data.notification.Notifications +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi +import eu.kanade.tachiyomi.util.system.notification +import java.util.concurrent.TimeUnit +import kotlinx.coroutines.coroutineScope +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +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) { + return@coroutineScope Result.failure() + } + if (pendingUpdates.isNotEmpty()) { + val names = pendingUpdates.map { it.name } + NotificationManagerCompat.from(context).apply { + notify(Notifications.ID_UPDATES_TO_EXTS, + context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) { + 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) + }) + } + } + Result.success() + } + + companion object { + const val TAG = "ExtensionUpdate" + + fun setupTask(context: Context, forceAutoUpdateJob: Boolean? = null) { + val preferences = Injekt.get() + val autoUpdateJob = forceAutoUpdateJob ?: preferences.automaticExtUpdates().getOrDefault() + if (autoUpdateJob) { + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + + val request = PeriodicWorkRequestBuilder( + 12, TimeUnit.HOURS, + 1, TimeUnit.HOURS) + .addTag(TAG) + .setConstraints(constraints) + .build() + + WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, 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 b4b0f1041..1223f2421 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 @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.extension.api +import android.content.Context import com.github.salomonbrys.kotson.fromJson import com.github.salomonbrys.kotson.get import com.github.salomonbrys.kotson.int @@ -7,6 +8,7 @@ import com.github.salomonbrys.kotson.string import com.google.gson.Gson import com.google.gson.JsonArray import eu.kanade.tachiyomi.extension.model.Extension +import eu.kanade.tachiyomi.extension.model.LoadResult import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.NetworkHelper @@ -23,13 +25,41 @@ internal class ExtensionGithubApi { private val gson: Gson by injectLazy() suspend fun findExtensions(): List { - val call = GET("$REPO_URL/index.json") + val call = GET(EXT_URL) return withContext(Dispatchers.IO) { parseResponse(network.client.newCall(call).await()) } } + suspend fun checkForUpdates(context: Context): List { + return withContext(Dispatchers.IO) { + val call = GET(EXT_URL) + val response = network.client.newCall(call).await() + + if (response.isSuccessful) { + val extensions = parseResponse(response) + val extensionsWithUpdate = mutableListOf() + + val installedExtensions = ExtensionLoader.loadExtensions(context) + .filterIsInstance() + .map { it.extension } + for (installedExt in installedExtensions) { + val pkgName = installedExt.pkgName + val availableExt = extensions.find { it.pkgName == pkgName } ?: continue + + val hasUpdate = availableExt.versionCode > installedExt.versionCode + if (hasUpdate) extensionsWithUpdate.add(installedExt) + } + + extensionsWithUpdate + } else { + response.close() + throw Exception("Failed to get extensions") + } + } + } + private fun parseResponse(response: Response): List { val text = response.body?.use { it.string() } ?: return emptyList() @@ -60,5 +90,6 @@ internal class ExtensionGithubApi { companion object { private const val REPO_URL = "https://raw.githubusercontent.com/inorichi/tachiyomi-extensions/repo" + private const val EXT_URL = "$REPO_URL/index.json" } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt index 9794e4e19..ad216e20b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt @@ -17,11 +17,15 @@ import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.IFlexible import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction -import kotlinx.android.synthetic.main.extension_controller.ext_recycler -import kotlinx.android.synthetic.main.extension_controller.ext_swipe_refresh +import kotlinx.android.synthetic.main.extension_controller.* +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get /** * Controller to manage the catalogues available in the app. @@ -86,6 +90,13 @@ open class ExtensionController : NucleusController(), .popChangeHandler(SettingsExtensionsFadeChangeHandler()) .pushChangeHandler(FadeChangeHandler())) } + R.id.action_auto_check -> { + item.isChecked = !item.isChecked + val preferences: PreferencesHelper = Injekt.get() + preferences.automaticExtUpdates().set(item.isChecked) + ExtensionUpdateJob.setupTask(activity!!, item.isChecked) + } + else -> return super.onOptionsItemSelected(item) } return super.onOptionsItemSelected(item) } @@ -138,6 +149,10 @@ open class ExtensionController : NucleusController(), // Fixes problem with the overflow icon showing up in lieu of search searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() }) + + val autoItem = menu.findItem(R.id.action_auto_check) + val preferences: PreferencesHelper = Injekt.get() + autoItem.isChecked = preferences.automaticExtUpdates().getOrDefault() } override fun onItemClick(view: View, position: Int): Boolean { 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 d2613223d..aed87bafb 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 @@ -13,6 +13,9 @@ import com.bluelinelabs.conductor.RouterTransaction import eu.kanade.tachiyomi.Migrations import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.notification.NotificationReceiver +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController @@ -23,16 +26,20 @@ import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.catalogue.CatalogueController import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController import eu.kanade.tachiyomi.ui.download.DownloadController +import eu.kanade.tachiyomi.ui.extension.ExtensionController 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.recent.history.HistoryController import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController -import kotlinx.android.synthetic.main.main_activity.appbar -import kotlinx.android.synthetic.main.main_activity.bottom_nav -import kotlinx.android.synthetic.main.main_activity.drawer -import kotlinx.android.synthetic.main.main_activity.tabs -import kotlinx.android.synthetic.main.main_activity.toolbar +import java.util.Date +import java.util.concurrent.TimeUnit +import kotlinx.android.synthetic.main.main_activity.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import timber.log.Timber +import uy.kohesive.injekt.injectLazy class MainActivity : BaseActivity() { @@ -133,6 +140,10 @@ class MainActivity : BaseActivity() { ChangelogDialogController().showDialog(router) } } + preferences.extensionUpdatesCount().asObservable().subscribe { + setExtensionsBadge() + } + setExtensionsBadge() } override fun onNewIntent(intent: Intent) { @@ -141,6 +152,37 @@ class MainActivity : BaseActivity() { } } + private fun setExtensionsBadge() { + val updates = preferences.extensionUpdatesCount().getOrDefault() + if (updates > 0) { + val badge = bottom_nav.getOrCreateBadge(R.id.nav_more) + badge.number = updates + } else { + bottom_nav.removeBadge(R.id.nav_more) + } + } + + override fun onResume() { + super.onResume() + getExtensionUpdates() + } + + private fun getExtensionUpdates() { + if (Date().time >= preferences.lastExtCheck().getOrDefault() + + TimeUnit.HOURS.toMillis(2)) { + GlobalScope.launch(Dispatchers.IO) { + val preferences: PreferencesHelper by injectLazy() + try { + val pendingUpdates = ExtensionGithubApi().checkForUpdates(this@MainActivity) + preferences.extensionUpdatesCount().set(pendingUpdates.size) + preferences.lastExtCheck().set(Date().time) + } catch (e: java.lang.Exception) { + Timber.e(e) + } + } + } + } + private fun handleIntentAction(intent: Intent): Boolean { val notificationId = intent.getIntExtra("notificationId", -1) if (notificationId > -1) { @@ -152,6 +194,10 @@ class MainActivity : BaseActivity() { SHORTCUT_RECENTLY_UPDATED -> setSelectedDrawerItem(R.id.nav_updates) SHORTCUT_RECENTLY_READ -> setSelectedDrawerItem(R.id.nav_history) SHORTCUT_CATALOGUES -> setSelectedDrawerItem(R.id.nav_catalogues) + SHORTCUT_EXTENSIONS -> { + setSelectedDrawerItem(R.id.nav_more) + router.pushController(ExtensionController().withFadeTransaction()) + } SHORTCUT_MANGA -> { val extras = intent.extras ?: return false setSelectedDrawerItem(R.id.nav_library) @@ -267,6 +313,7 @@ class MainActivity : BaseActivity() { const val SHORTCUT_CATALOGUES = "eu.kanade.tachiyomi.SHOW_CATALOGUES" const val SHORTCUT_DOWNLOADS = "eu.kanade.tachiyomi.SHOW_DOWNLOADS" const val SHORTCUT_MANGA = "eu.kanade.tachiyomi.SHOW_MANGA" + const val SHORTCUT_EXTENSIONS = "eu.kanade.tachiyomi.EXTENSIONS" const val INTENT_SEARCH = "eu.kanade.tachiyomi.SEARCH" const val INTENT_SEARCH_QUERY = "query" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt index 4530917df..17403a071 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/MoreController.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.ui.extension.ExtensionController import eu.kanade.tachiyomi.ui.migration.MigrationController import eu.kanade.tachiyomi.ui.setting.SettingsController import eu.kanade.tachiyomi.ui.setting.SettingsMainController +import eu.kanade.tachiyomi.util.preference.extensionPreference import eu.kanade.tachiyomi.util.preference.iconRes import eu.kanade.tachiyomi.util.preference.iconTint import eu.kanade.tachiyomi.util.preference.onClick @@ -25,7 +26,7 @@ class MoreController : SettingsController(), RootController { val tintColor = context.getResourceColor(R.attr.colorAccent) - preference { + extensionPreference { titleRes = R.string.label_extensions iconRes = R.drawable.ic_extension_24dp iconTint = tintColor diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceDSL.kt b/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceDSL.kt index 03ead952b..f9b7a62e9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceDSL.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/preference/PreferenceDSL.kt @@ -13,6 +13,7 @@ import androidx.preference.PreferenceManager import androidx.preference.PreferenceScreen import androidx.preference.SwitchPreferenceCompat import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat +import eu.kanade.tachiyomi.widget.preference.ExtensionPreference import eu.kanade.tachiyomi.widget.preference.IntListPreference import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory @@ -56,6 +57,10 @@ inline fun PreferenceGroup.multiSelectListPreference(block: (@DSL MultiSelectLis return initThenAdd(MultiSelectListPreference(context), block).also(::initDialog) } +inline fun PreferenceGroup.extensionPreference(block: (@DSL Preference).() -> Unit): ExtensionPreference { + return initThenAdd(ExtensionPreference(context), block) +} + inline fun PreferenceScreen.preferenceCategory(block: (@DSL PreferenceCategory).() -> Unit): PreferenceCategory { return addThenInit(PreferenceCategory(context), block) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ExtensionPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ExtensionPreference.kt new file mode 100644 index 000000000..4602b72cc --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ExtensionPreference.kt @@ -0,0 +1,37 @@ +package eu.kanade.tachiyomi.widget.preference + +import android.content.Context +import android.util.AttributeSet +import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.util.view.gone +import eu.kanade.tachiyomi.util.view.visible +import kotlinx.android.synthetic.main.preference_update_text.view.* +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class ExtensionPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + Preference(context, attrs) { + + init { + widgetLayoutResource = R.layout.preference_update_text + } + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + + val extUpdateText = holder.itemView.textView + + val updates = Injekt.get().extensionUpdatesCount().getOrDefault() + if (updates > 0) { + extUpdateText.text = updates.toString() + extUpdateText.visible() + } else { + extUpdateText.text = null + extUpdateText.gone() + } + } +} diff --git a/app/src/main/res/drawable/round_textview_background.xml b/app/src/main/res/drawable/round_textview_background.xml new file mode 100644 index 000000000..deb60b367 --- /dev/null +++ b/app/src/main/res/drawable/round_textview_background.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/preference_update_text.xml b/app/src/main/res/layout/preference_update_text.xml new file mode 100644 index 000000000..3baa6286e --- /dev/null +++ b/app/src/main/res/layout/preference_update_text.xml @@ -0,0 +1,17 @@ + + \ No newline at end of file diff --git a/app/src/main/res/menu/extension_main.xml b/app/src/main/res/menu/extension_main.xml index 578441c5c..f0b98861e 100644 --- a/app/src/main/res/menu/extension_main.xml +++ b/app/src/main/res/menu/extension_main.xml @@ -16,4 +16,10 @@ app:iconTint="?attr/colorOnPrimary" app:showAsAction="ifRoom" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c70386270..e1e2848b3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -211,6 +211,7 @@ Version: %1$s Language: %1$s No preferences to edit for this extension + Auto-check for updates Fullscreen @@ -566,6 +567,12 @@ Download error Update available + + + Extension update available + %d extension updates available + + Backdrop image of manga Cover of manga @@ -594,5 +601,6 @@ Library Downloader Chapter updates + Extension Updates