diff --git a/app/src/main/java/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt b/app/src/main/java/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt index c7eb5bbf9..eefe100a7 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/os/ShortcutsUpdater.kt @@ -2,10 +2,12 @@ package org.koitharu.kotatsu.core.os import android.app.ActivityManager import android.content.Context +import android.content.SharedPreferences import android.content.pm.ShortcutManager import android.media.ThumbnailUtils import android.os.Build import android.util.Size +import androidx.annotation.RequiresApi import androidx.annotation.VisibleForTesting import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat @@ -22,6 +24,7 @@ import kotlinx.coroutines.launch import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.domain.MangaDataRepository import org.koitharu.kotatsu.core.db.TABLE_HISTORY +import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.reader.ui.ReaderActivity @@ -35,13 +38,18 @@ class ShortcutsUpdater @Inject constructor( private val coil: ImageLoader, private val historyRepository: HistoryRepository, private val mangaRepository: MangaDataRepository, -) : InvalidationTracker.Observer(TABLE_HISTORY) { + private val settings: AppSettings, +) : InvalidationTracker.Observer(TABLE_HISTORY), SharedPreferences.OnSharedPreferenceChangeListener { private val iconSize by lazy { getIconSize(context) } private var shortcutsUpdateJob: Job? = null - override fun onInvalidated(tables: MutableSet) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) { + init { + settings.subscribe(this) + } + + override fun onInvalidated(tables: Set) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1 || !settings.isDynamicShortcutsEnabled) { return } val prevJob = shortcutsUpdateJob @@ -51,6 +59,16 @@ class ShortcutsUpdater @Inject constructor( } } + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && key == AppSettings.KEY_SHORTCUTS) { + if (settings.isDynamicShortcutsEnabled) { + onInvalidated(emptySet()) + } else { + clearShortcuts() + } + } + } + suspend fun requestPinShortcut(manga: Manga): Boolean { return ShortcutManagerCompat.requestPinShortcut( context, @@ -64,6 +82,15 @@ class ShortcutsUpdater @Inject constructor( return shortcutsUpdateJob?.join() != null } + fun isDynamicShortcutsAvailable(): Boolean { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) { + return false + } + val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager + return manager.maxShortcutCountPerActivity > 0 + } + + @RequiresApi(Build.VERSION_CODES.N_MR1) private suspend fun updateShortcutsImpl() = runCatching { val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager val shortcuts = historyRepository.getList(0, manager.maxShortcutCountPerActivity) @@ -74,6 +101,15 @@ class ShortcutsUpdater @Inject constructor( it.printStackTraceDebug() } + @RequiresApi(Build.VERSION_CODES.N_MR1) + private fun clearShortcuts() { + val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager + try { + manager.removeAllDynamicShortcuts() + } catch (_: IllegalStateException) { + } + } + private suspend fun buildShortcutInfo(manga: Manga): ShortcutInfoCompat.Builder { val icon = runCatching { val bmp = coil.execute( diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 17fbf1078..55139e2f3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -134,6 +134,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { val isExitConfirmationEnabled: Boolean get() = prefs.getBoolean(KEY_EXIT_CONFIRM, false) + val isDynamicShortcutsEnabled: Boolean + get() = prefs.getBoolean(KEY_SHORTCUTS, true) + var sourcesOrder: List get() = prefs.getString(KEY_SOURCES_ORDER, null) ?.split('|') @@ -317,6 +320,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { const val KEY_INCOGNITO_MODE = "incognito" const val KEY_SYNC = "sync" const val KEY_READER_BAR = "reader_bar" + const val KEY_SHORTCUTS = "dynamic_shortcuts" // About const val KEY_APP_UPDATE = "app_update" diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt index 038e07edf..4389c39a6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.launch import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.network.AndroidCookieJar +import org.koitharu.kotatsu.core.os.ShortcutsUpdater import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.LocalStorageManager @@ -41,8 +42,13 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach @Inject lateinit var cookieJar: AndroidCookieJar + @Inject + lateinit var shortcutsUpdater: ShortcutsUpdater + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_history) + findPreference(AppSettings.KEY_SHORTCUTS)?.isVisible = + shortcutsUpdater.isDynamicShortcutsAvailable() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2a9515dcc..105caaee3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -377,4 +377,6 @@ Import will start soon Feed Error details:<br><tt>%1$s</tt><br><br>1. Try to <a href="%2$s">open manga in a web browser</a> to ensure it is available on its source<br>2. If it is available, send an error report to the developers. + Show recent manga shortcuts + Make recent manga available by long pressing on application icon diff --git a/app/src/main/res/xml/pref_history.xml b/app/src/main/res/xml/pref_history.xml index 59dddad36..439694206 100644 --- a/app/src/main/res/xml/pref_history.xml +++ b/app/src/main/res/xml/pref_history.xml @@ -13,6 +13,12 @@ android:summary="@string/exclude_nsfw_from_history_summary" android:title="@string/exclude_nsfw_from_history" /> + + - \ No newline at end of file +