Merge branch 'devel' into feature/nextgen
This commit is contained in:
@@ -3,14 +3,13 @@ package org.koitharu.kotatsu.core.model.parcelable
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.utils.ext.createList
|
||||
|
||||
class ParcelableMangaChapters(
|
||||
val chapters: List<MangaChapter>,
|
||||
) : Parcelable {
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
createList(parcel.readInt()) { parcel.readMangaChapter() }
|
||||
List(parcel.readInt()) { parcel.readMangaChapter() }
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
|
||||
@@ -3,14 +3,13 @@ package org.koitharu.kotatsu.core.model.parcelable
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.utils.ext.createList
|
||||
|
||||
class ParcelableMangaPages(
|
||||
val pages: List<MangaPage>,
|
||||
) : Parcelable {
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
createList(parcel.readInt()) { parcel.readMangaPage() }
|
||||
List(parcel.readInt()) { parcel.readMangaPage() }
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
|
||||
@@ -3,14 +3,14 @@ package org.koitharu.kotatsu.core.model.parcelable
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.utils.ext.createSet
|
||||
import org.koitharu.kotatsu.utils.ext.Set
|
||||
|
||||
class ParcelableMangaTags(
|
||||
val tags: Set<MangaTag>,
|
||||
) : Parcelable {
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
createSet(parcel.readInt()) { parcel.readMangaTag() }
|
||||
Set(parcel.readInt()) { parcel.readMangaTag() }
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import android.text.Html
|
||||
import coil.ComponentRegistry
|
||||
import coil.ImageLoader
|
||||
import coil.disk.DiskCache
|
||||
@@ -10,6 +11,7 @@ import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.core.parser.FaviconMapper
|
||||
import org.koitharu.kotatsu.local.data.CacheDir
|
||||
import org.koitharu.kotatsu.local.data.CbzFetcher
|
||||
import org.koitharu.kotatsu.utils.image.CoilImageGetter
|
||||
|
||||
val uiModule
|
||||
get() = module {
|
||||
@@ -40,4 +42,5 @@ val uiModule
|
||||
.build()
|
||||
).build()
|
||||
}
|
||||
factory<Html.ImageGetter> { CoilImageGetter(androidContext(), get()) }
|
||||
}
|
||||
@@ -8,6 +8,6 @@ val detailsModule
|
||||
get() = module {
|
||||
|
||||
viewModel { intent ->
|
||||
DetailsViewModel(intent.get(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||
DetailsViewModel(intent.get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import coil.size.Scale
|
||||
import coil.util.CoilUtils
|
||||
import com.google.android.material.chip.Chip
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
@@ -80,6 +81,7 @@ class DetailsFragment :
|
||||
viewModel.readingHistory.observe(viewLifecycleOwner, ::onHistoryChanged)
|
||||
viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged)
|
||||
viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged)
|
||||
viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged)
|
||||
addMenuProvider(DetailsMenuProvider())
|
||||
}
|
||||
|
||||
@@ -108,8 +110,6 @@ class DetailsFragment :
|
||||
textViewTitle.text = manga.title
|
||||
textViewSubtitle.textAndVisible = manga.altTitle
|
||||
textViewAuthor.textAndVisible = manga.author
|
||||
textViewDescription.text = manga.description?.parseAsHtml()?.takeUnless(Spanned::isBlank)
|
||||
?: getString(R.string.no_description)
|
||||
when (manga.state) {
|
||||
MangaState.FINISHED -> {
|
||||
textViewState.apply {
|
||||
@@ -172,6 +172,14 @@ class DetailsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDescriptionChanged(description: CharSequence?) {
|
||||
if (description.isNullOrBlank()) {
|
||||
binding.textViewDescription.setText(R.string.no_description)
|
||||
} else {
|
||||
binding.textViewDescription.text = description
|
||||
}
|
||||
}
|
||||
|
||||
private fun onHistoryChanged(history: MangaHistory?) {
|
||||
with(binding.buttonRead) {
|
||||
if (history == null) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.koitharu.kotatsu.details.ui
|
||||
|
||||
import android.text.Html
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.asLiveData
|
||||
@@ -43,6 +45,7 @@ class DetailsViewModel(
|
||||
private val bookmarksRepository: BookmarksRepository,
|
||||
private val settings: AppSettings,
|
||||
private val scrobbler: Scrobbler,
|
||||
private val imageGetter: Html.ImageGetter,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val delegate = MangaDetailsDelegate(
|
||||
@@ -79,7 +82,19 @@ class DetailsViewModel(
|
||||
|
||||
val bookmarks = delegate.manga.flatMapLatest {
|
||||
if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList())
|
||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
|
||||
|
||||
val description = delegate.manga
|
||||
.distinctUntilChangedBy { it?.description.orEmpty() }
|
||||
.transformLatest {
|
||||
val description = it?.description
|
||||
if (description.isNullOrEmpty()) {
|
||||
emit(null)
|
||||
} else {
|
||||
emit(description.parseAsHtml())
|
||||
emit(description.parseAsHtml(imageGetter = imageGetter))
|
||||
}
|
||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, null)
|
||||
|
||||
val onMangaRemoved = SingleLiveEvent<Manga>()
|
||||
val isScrobblingAvailable: Boolean
|
||||
|
||||
@@ -13,9 +13,9 @@ import java.io.InputStream
|
||||
class PagesCache(context: Context) {
|
||||
|
||||
private val cacheDir = context.externalCacheDir ?: context.cacheDir
|
||||
private val lruCache = DiskLruCache.create(
|
||||
cacheDir.subdir(CacheDir.PAGES.dir),
|
||||
FileSize.MEGABYTES.convert(200, FileSize.BYTES),
|
||||
private val lruCache = createDiskLruCacheSafe(
|
||||
dir = cacheDir.subdir(CacheDir.PAGES.dir),
|
||||
size = FileSize.MEGABYTES.convert(200, FileSize.BYTES),
|
||||
)
|
||||
|
||||
operator fun get(url: String): File? {
|
||||
@@ -60,4 +60,14 @@ class PagesCache(context: Context) {
|
||||
progress.value = (bytesCopied.toDouble() / contentLength.toDouble()).toFloat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDiskLruCacheSafe(dir: File, size: Long): DiskLruCache {
|
||||
return try {
|
||||
DiskLruCache.create(dir, size)
|
||||
} catch (e: Exception) {
|
||||
dir.deleteRecursively()
|
||||
dir.mkdir()
|
||||
DiskLruCache.create(dir, size)
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.scrobbling.data.ScrobblingEntity
|
||||
import org.koitharu.kotatsu.scrobbling.domain.model.*
|
||||
import org.koitharu.kotatsu.utils.ext.findKey
|
||||
import org.koitharu.kotatsu.utils.ext.findKeyByValue
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
|
||||
abstract class Scrobbler(
|
||||
@@ -59,7 +59,7 @@ abstract class Scrobbler(
|
||||
scrobbler = scrobblerService,
|
||||
mangaId = mangaId,
|
||||
targetId = targetId,
|
||||
status = statuses.findKey(status),
|
||||
status = statuses.findKeyByValue(status),
|
||||
chapter = chapter,
|
||||
comment = comment,
|
||||
rating = rating,
|
||||
|
||||
@@ -4,9 +4,9 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.core.net.toUri
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -23,9 +23,6 @@ import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.security.cert.CertificateEncodingException
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -74,7 +71,8 @@ class AppUpdateChecker(private val activity: ComponentActivity) {
|
||||
.setTitle(R.string.app_update_available)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.download) { _, _ ->
|
||||
activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(version.apkUrl)))
|
||||
val intent = Intent(Intent.ACTION_VIEW, version.apkUrl.toUri())
|
||||
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.open_in_browser)))
|
||||
}
|
||||
.setNegativeButton(R.string.close, null)
|
||||
.setCancelable(false)
|
||||
@@ -88,42 +86,23 @@ class AppUpdateChecker(private val activity: ComponentActivity) {
|
||||
private val PERIOD = TimeUnit.HOURS.toMillis(6)
|
||||
|
||||
fun isUpdateSupported(context: Context): Boolean {
|
||||
return getCertificateSHA1Fingerprint(context) == CERT_SHA1
|
||||
return BuildConfig.DEBUG || getCertificateSHA1Fingerprint(context) == CERT_SHA1
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
private fun getCertificateSHA1Fingerprint(context: Context): String? {
|
||||
val packageInfo = try {
|
||||
context.packageManager.getPackageInfo(
|
||||
context.packageName,
|
||||
PackageManager.GET_SIGNATURES
|
||||
)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTraceDebug()
|
||||
return null
|
||||
}
|
||||
val signatures = packageInfo?.signatures
|
||||
val cert: ByteArray = signatures?.firstOrNull()?.toByteArray() ?: return null
|
||||
private fun getCertificateSHA1Fingerprint(context: Context): String? = runCatching {
|
||||
val packageInfo = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES)
|
||||
val signatures = requireNotNull(packageInfo?.signatures)
|
||||
val cert: ByteArray = signatures.first().toByteArray()
|
||||
val input: InputStream = ByteArrayInputStream(cert)
|
||||
val c = try {
|
||||
val cf = CertificateFactory.getInstance("X509")
|
||||
cf.generateCertificate(input) as X509Certificate
|
||||
} catch (e: CertificateException) {
|
||||
e.printStackTraceDebug()
|
||||
return null
|
||||
}
|
||||
return try {
|
||||
val md: MessageDigest = MessageDigest.getInstance("SHA1")
|
||||
val publicKey: ByteArray = md.digest(c.encoded)
|
||||
publicKey.byte2HexFormatted()
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
e.printStackTraceDebug()
|
||||
null
|
||||
} catch (e: CertificateEncodingException) {
|
||||
e.printStackTraceDebug()
|
||||
null
|
||||
}
|
||||
}
|
||||
val cf = CertificateFactory.getInstance("X509")
|
||||
val c = cf.generateCertificate(input) as X509Certificate
|
||||
val md: MessageDigest = MessageDigest.getInstance("SHA1")
|
||||
val publicKey: ByteArray = md.digest(c.encoded)
|
||||
return publicKey.byte2HexFormatted()
|
||||
}.onFailure { error ->
|
||||
error.printStackTraceDebug()
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
@@ -3,25 +3,25 @@ package org.koitharu.kotatsu.settings
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.preference.Preference
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.serializableArgument
|
||||
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
|
||||
class SourceSettingsFragment : BasePreferenceFragment(0) {
|
||||
|
||||
private val source by serializableArgument<MangaSource>(EXTRA_SOURCE)
|
||||
private var repository: RemoteMangaRepository? = null
|
||||
private val exceptionResolver = ExceptionResolver(this)
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
@@ -63,6 +63,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
|
||||
|
||||
private fun loadUsername(preference: Preference) = viewLifecycleScope.launch {
|
||||
runCatching {
|
||||
preference.summary = null
|
||||
withContext(Dispatchers.Default) {
|
||||
requireNotNull(repository?.getAuthProvider()?.getUsername())
|
||||
}
|
||||
@@ -70,10 +71,28 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
|
||||
preference.title = getString(R.string.logged_in_as, username)
|
||||
}.onFailure { error ->
|
||||
preference.isEnabled = error is AuthRequiredException
|
||||
when {
|
||||
error is AuthRequiredException -> Unit
|
||||
ExceptionResolver.canResolve(error) -> {
|
||||
Snackbar.make(listView, error.getDisplayMessage(resources), Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(ExceptionResolver.getResolveStringId(error)) { resolveError(error) }
|
||||
.show()
|
||||
}
|
||||
else -> preference.summary = error.getDisplayMessage(resources)
|
||||
}
|
||||
error.printStackTraceDebug()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveError(error: Throwable): Unit {
|
||||
viewLifecycleScope.launch {
|
||||
if (exceptionResolver.resolve(error)) {
|
||||
val pref = findPreference<Preference>(KEY_AUTH) ?: return@launch
|
||||
loadUsername(pref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val KEY_AUTH = "auth"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.koitharu.kotatsu.settings.newsources
|
||||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.getLocaleTitle
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||
|
||||
class NewSourcesViewModel(
|
||||
private val settings: AppSettings,
|
||||
@@ -30,12 +32,14 @@ class NewSourcesViewModel(
|
||||
}
|
||||
|
||||
private fun buildList() {
|
||||
val locales = LocaleListCompat.getDefault().mapToSet { it.language }
|
||||
val hidden = settings.hiddenSources
|
||||
sources.value = initialList.map {
|
||||
val locale = it.locale
|
||||
SourceConfigItem.SourceItem(
|
||||
source = it,
|
||||
summary = it.getLocaleTitle(),
|
||||
isEnabled = it.name !in hidden,
|
||||
isEnabled = it.name !in hidden && (locale == null || locale in locales),
|
||||
isDraggable = false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,25 +18,20 @@ inline fun <T> MutableSet(size: Int, init: (index: Int) -> T): MutableSet<T> {
|
||||
return set
|
||||
}
|
||||
|
||||
inline fun <T> createSet(size: Int, init: (index: Int) -> T): Set<T> = when (size) {
|
||||
@Suppress("FunctionName")
|
||||
inline fun <T> Set(size: Int, init: (index: Int) -> T): Set<T> = when (size) {
|
||||
0 -> emptySet()
|
||||
1 -> Collections.singleton(init(0))
|
||||
else -> MutableSet(size, init)
|
||||
}
|
||||
|
||||
inline fun <T> createList(size: Int, init: (index: Int) -> T): List<T> = when (size) {
|
||||
0 -> emptyList()
|
||||
1 -> Collections.singletonList(init(0))
|
||||
else -> MutableList(size, init)
|
||||
}
|
||||
|
||||
fun <T> List<T>.asArrayList(): ArrayList<T> = if (this is ArrayList<*>) {
|
||||
this as ArrayList<T>
|
||||
} else {
|
||||
ArrayList(this)
|
||||
}
|
||||
|
||||
fun <K, V> Map<K, V>.findKey(value: V): K? {
|
||||
fun <K, V> Map<K, V>.findKeyByValue(value: V): K? {
|
||||
for ((k, v) in entries) {
|
||||
if (v == value) {
|
||||
return k
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import java.util.*
|
||||
|
||||
fun LocaleListCompat.getOrThrow(index: Int) = get(index) ?: throw kotlin.NoSuchElementException()
|
||||
|
||||
fun LocaleListCompat.toList(): List<Locale> = createList(size()) { i -> getOrThrow(i) }
|
||||
|
||||
operator fun LocaleListCompat.iterator() = object : Iterator<Locale> {
|
||||
private var index = 0
|
||||
override fun hasNext(): Boolean = index < size()
|
||||
override fun next(): Locale = getOrThrow(index++)
|
||||
}
|
||||
|
||||
inline fun <R, C : MutableCollection<in R>> LocaleListCompat.mapTo(
|
||||
destination: C,
|
||||
block: (Locale) -> R,
|
||||
): C {
|
||||
val len = size()
|
||||
for (i in 0 until len) {
|
||||
val item = get(i) ?: continue
|
||||
destination.add(block(item))
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
inline fun <T> LocaleListCompat.map(block: (Locale) -> T): List<T> {
|
||||
return mapTo(ArrayList(size()), block)
|
||||
}
|
||||
|
||||
inline fun <T> LocaleListCompat.mapToSet(block: (Locale) -> T): Set<T> {
|
||||
return mapTo(LinkedHashSet(size()), block)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import java.util.*
|
||||
|
||||
operator fun LocaleListCompat.iterator(): ListIterator<Locale> = LocaleListCompatIterator(this)
|
||||
|
||||
fun LocaleListCompat.toList(): List<Locale> = List(size()) { i -> getOrThrow(i) }
|
||||
|
||||
inline fun <T> LocaleListCompat.map(block: (Locale) -> T): List<T> {
|
||||
return List(size()) { i -> block(getOrThrow(i)) }
|
||||
}
|
||||
|
||||
inline fun <T> LocaleListCompat.mapToSet(block: (Locale) -> T): Set<T> {
|
||||
return Set(size()) { i -> block(getOrThrow(i)) }
|
||||
}
|
||||
|
||||
fun LocaleListCompat.getOrThrow(index: Int) = get(index) ?: throw NoSuchElementException()
|
||||
|
||||
private class LocaleListCompatIterator(private val list: LocaleListCompat) : ListIterator<Locale> {
|
||||
|
||||
private var index = 0
|
||||
|
||||
override fun hasNext() = index < list.size()
|
||||
|
||||
override fun hasPrevious() = index > 0
|
||||
|
||||
override fun next() = list.get(index++) ?: throw NoSuchElementException()
|
||||
|
||||
override fun nextIndex() = index
|
||||
|
||||
override fun previous() = list.get(--index) ?: throw NoSuchElementException()
|
||||
|
||||
override fun previousIndex() = index - 1
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.koitharu.kotatsu.utils.image
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.Html
|
||||
import coil.ImageLoader
|
||||
import coil.executeBlocking
|
||||
import coil.request.ImageRequest
|
||||
|
||||
class CoilImageGetter(
|
||||
private val context: Context,
|
||||
private val coil: ImageLoader,
|
||||
) : Html.ImageGetter {
|
||||
|
||||
override fun getDrawable(source: String?): Drawable? {
|
||||
return coil.executeBlocking(
|
||||
ImageRequest.Builder(context)
|
||||
.data(source)
|
||||
.allowHardware(false)
|
||||
.build()
|
||||
).drawable?.apply {
|
||||
setBounds(0, 0, intrinsicHeight, intrinsicHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user