Fix shortcuts
parent
abc4ab92a9
commit
c132f1d5c4
@ -0,0 +1,87 @@
|
||||
package org.koitharu.kotatsu.core.os
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.media.ThumbnailUtils
|
||||
import android.os.Build
|
||||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import coil.ImageLoader
|
||||
import coil.request.ImageRequest
|
||||
import coil.size.PixelSize
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.utils.ext.requireBitmap
|
||||
|
||||
class ShortcutsRepository(
|
||||
private val context: Context,
|
||||
private val coil: ImageLoader,
|
||||
private val historyRepository: HistoryRepository,
|
||||
private val mangaRepository: MangaDataRepository
|
||||
) {
|
||||
|
||||
private val iconSize by lazy {
|
||||
getIconSize(context)
|
||||
}
|
||||
|
||||
suspend fun updateShortcuts() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return
|
||||
val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager
|
||||
val shortcuts = historyRepository.getList(0, manager.maxShortcutCountPerActivity)
|
||||
.map { buildShortcutInfo(it).build().toShortcutInfo() }
|
||||
manager.dynamicShortcuts = shortcuts
|
||||
}
|
||||
|
||||
suspend fun requestPinShortcut(manga: Manga): Boolean {
|
||||
return ShortcutManagerCompat.requestPinShortcut(
|
||||
context,
|
||||
buildShortcutInfo(manga).build(),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun buildShortcutInfo(manga: Manga): ShortcutInfoCompat.Builder {
|
||||
val icon = runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
val bmp = coil.execute(
|
||||
ImageRequest.Builder(context)
|
||||
.data(manga.coverUrl)
|
||||
.size(iconSize)
|
||||
.build()
|
||||
).requireBitmap()
|
||||
ThumbnailUtils.extractThumbnail(bmp, iconSize.width, iconSize.height, 0)
|
||||
}
|
||||
}.fold(
|
||||
onSuccess = { IconCompat.createWithAdaptiveBitmap(it) },
|
||||
onFailure = { IconCompat.createWithResource(context, R.drawable.ic_shortcut_default) }
|
||||
)
|
||||
mangaRepository.storeManga(manga)
|
||||
return ShortcutInfoCompat.Builder(context, manga.id.toString())
|
||||
.setShortLabel(manga.title)
|
||||
.setLongLabel(manga.title)
|
||||
.setIcon(icon)
|
||||
.setIntent(
|
||||
ReaderActivity.newIntent(context, manga.id, null)
|
||||
.setAction(ReaderActivity.ACTION_MANGA_READ)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getIconSize(context: Context): PixelSize {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
(context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager).let {
|
||||
PixelSize(it.iconMaxWidth, it.iconMaxHeight)
|
||||
}
|
||||
} else {
|
||||
(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).launcherLargeIconSize.let {
|
||||
PixelSize(it, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,114 +0,0 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.media.ThumbnailUtils
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import coil.ImageLoader
|
||||
import coil.request.ImageRequest
|
||||
import coil.size.PixelSize
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.utils.ext.requireBitmap
|
||||
import org.koitharu.kotatsu.utils.ext.safe
|
||||
|
||||
class MangaShortcut(private val manga: Manga) : KoinComponent {
|
||||
|
||||
private val shortcutId = manga.id.toString()
|
||||
private val coil by inject<ImageLoader>()
|
||||
private val mangaRepository by inject<MangaDataRepository>()
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
suspend fun addAppShortcut(context: Context) {
|
||||
val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager
|
||||
val limit = manager.maxShortcutCountPerActivity
|
||||
val builder = buildShortcutInfo(context, manga)
|
||||
val shortcuts = manager.dynamicShortcuts
|
||||
for (shortcut in shortcuts) {
|
||||
if (shortcut.id == shortcutId) {
|
||||
builder.setRank(shortcut.rank + 1)
|
||||
manager.updateShortcuts(listOf(builder.build().toShortcutInfo()))
|
||||
return
|
||||
}
|
||||
}
|
||||
builder.setRank(1)
|
||||
if (shortcuts.isNotEmpty() && shortcuts.size >= limit) {
|
||||
manager.removeDynamicShortcuts(listOf(shortcuts.minByOrNull { it.rank }!!.id))
|
||||
}
|
||||
manager.addDynamicShortcuts(listOf(builder.build().toShortcutInfo()))
|
||||
}
|
||||
|
||||
suspend fun requestPinShortcut(context: Context): Boolean {
|
||||
return ShortcutManagerCompat.requestPinShortcut(
|
||||
context,
|
||||
buildShortcutInfo(context, manga).build(),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
fun removeAppShortcut(context: Context) {
|
||||
val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager
|
||||
manager.removeDynamicShortcuts(listOf(shortcutId))
|
||||
}
|
||||
|
||||
private suspend fun buildShortcutInfo(
|
||||
context: Context,
|
||||
manga: Manga
|
||||
): ShortcutInfoCompat.Builder {
|
||||
val icon = safe {
|
||||
val size = getIconSize(context)
|
||||
withContext(Dispatchers.IO) {
|
||||
val bmp = coil.execute(
|
||||
ImageRequest.Builder(context)
|
||||
.data(manga.coverUrl)
|
||||
.build()
|
||||
).requireBitmap()
|
||||
ThumbnailUtils.extractThumbnail(bmp, size.width, size.height, 0)
|
||||
}
|
||||
}
|
||||
mangaRepository.storeManga(manga)
|
||||
return ShortcutInfoCompat.Builder(context, manga.id.toString())
|
||||
.setShortLabel(manga.title)
|
||||
.setLongLabel(manga.title)
|
||||
.setIcon(icon?.let {
|
||||
IconCompat.createWithAdaptiveBitmap(it)
|
||||
} ?: IconCompat.createWithResource(context, R.drawable.ic_shortcut_default))
|
||||
.setIntent(
|
||||
ReaderActivity.newIntent(context, manga.id, null)
|
||||
.setAction(ReaderActivity.ACTION_MANGA_READ)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getIconSize(context: Context): PixelSize {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
(context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager).let {
|
||||
PixelSize(it.iconMaxWidth, it.iconMaxHeight)
|
||||
}
|
||||
} else {
|
||||
(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).launcherLargeIconSize.let {
|
||||
PixelSize(it, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
fun clearAppShortcuts(context: Context) {
|
||||
val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager
|
||||
manager.removeAllDynamicShortcuts()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue