Skip to content

Commit

Permalink
landscapist glide to coil
Browse files Browse the repository at this point in the history
  • Loading branch information
Pluu committed Nov 7, 2024
1 parent cf12b9d commit f5c9180
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.PreloadTarget
import com.bumptech.glide.request.target.Target
import coil.imageLoader
import coil.request.ImageRequest
import coil.size.Size
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

fun Drawable.toLoaderBitmap(): Bitmap? {
return when (this) {
Expand All @@ -23,52 +25,24 @@ suspend fun preLoadImage(
context: Context,
imageUrl: String
): LoadedState = suspendCancellableCoroutine { cont ->
val requestManager = Glide.with(context)
val target = PreloadTarget.obtain<Drawable>(
requestManager,
PreloadTarget.SIZE_ORIGINAL,
PreloadTarget.SIZE_ORIGINAL
)

requestManager
.load(imageUrl.glideUrl())
.addListener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
if (cont.isCompleted) {
return false
}
cont.resume(
LoadedState.Error(e ?: IllegalStateException("Unknown Exception"))
) { _, _, _ ->
requestManager.clear(target)
}
return false
}

override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (cont.isCompleted) {
return false
}
cont.resume(
LoadedState.Success(resource)
) { _, _, _ ->
requestManager.clear(target)
}
return false
}
})
.into(target)
CoroutineScope(Dispatchers.IO).launch(
CoroutineExceptionHandler { _, t ->
cont.resume(LoadedState.Error(t))
}
) {
val request = ImageRequest.Builder(context)
.data(imageUrl)
.headers(userAgentHeader)
.size(Size.ORIGINAL)
.allowHardware(false) // Disable hardware bitmaps.
.build()
val drawable = context.imageLoader.execute(request).drawable
if (drawable != null) {
cont.resume(LoadedState.Success(drawable))
} else {
cont.resume(LoadedState.Error(IllegalStateException("Unknown Exception")))
}
}
}

sealed class LoadedState {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.pluu.webtoon.utils

import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.LazyHeaders
import okhttp3.Headers

const val userAgent =
"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"

fun String.glideUrl(): GlideUrl = GlideUrl(
this, LazyHeaders.Builder()
.addHeader("User-Agent", userAgent)
.build()
)
val userAgentHeader = Headers.Builder()
.set("User-Agent", userAgent)
.build()
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.pluu.webtoon.utils

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import coil.request.ImageRequest
import com.pluu.webtoon.ui.compose.theme.themeRed
import com.pluu.webtoon.ui_common.R
import com.skydoves.landscapist.ImageOptions
import com.skydoves.landscapist.coil.CoilImage
import com.skydoves.landscapist.coil.CoilImageState

@Composable
fun ToonImage(
imageUrl: () -> String,
modifier: Modifier = Modifier,
imageOptions: ImageOptions = ImageOptions(
contentScale = ContentScale.Crop,
alignment = Alignment.Center
),
onImageStateChanged: (CoilImageState) -> Unit = {},
previewPlaceholder: Painter? = null,
loading: @Composable (BoxScope.(imageState: CoilImageState.Loading) -> Unit)? = {
CircularProgressIndicator(
modifier = Modifier
.matchParentSize()
.wrapContentSize(),
color = themeRed
)
},
success: @Composable (BoxScope.(imageState: CoilImageState.Success, painter: Painter) -> Unit)? = null,
failure: @Composable (BoxScope.(imageState: CoilImageState.Failure) -> Unit)? = {
Image(
painter = painterResource(R.drawable.ic_sentiment_very_dissatisfied_48),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
contentDescription = null
)
}
) {
val context = LocalContext.current
CoilImage(
imageRequest = {
ImageRequest.Builder(context)
.data(imageUrl.invoke())
.headers(userAgentHeader)
.crossfade(true)
.build()
},
modifier = modifier,
imageOptions = imageOptions,
onImageStateChanged = onImageStateChanged,
previewPlaceholder = previewPlaceholder,
loading = loading,
success = success,
failure = failure
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ import androidx.compose.ui.unit.dp
import com.pluu.webtoon.model.DetailView
import com.pluu.webtoon.ui.compose.theme.themeRed
import com.pluu.webtoon.ui_common.R
import com.pluu.webtoon.utils.glideUrl
import com.skydoves.landscapist.glide.GlideImage
import com.skydoves.landscapist.glide.GlideImageState
import com.pluu.webtoon.utils.ToonImage
import com.skydoves.landscapist.coil.CoilImageState

@Composable
internal fun DetailContentUi(
Expand Down Expand Up @@ -67,8 +66,8 @@ private fun AdjustDetailImage(
modifier: Modifier = Modifier,
onSuccess: (DetailView, Size) -> Unit
) {
GlideImage(
imageModel = { item.url.glideUrl() },
ToonImage(
imageUrl = { item.url },
modifier = modifier,
loading = {
CircularProgressIndicator(
Expand All @@ -84,7 +83,7 @@ private fun AdjustDetailImage(
)
},
onImageStateChanged = {
if (it is GlideImageState.Success) {
if (it is CoilImageState.Success) {
val bitmap = it.imageBitmap!!
onSuccess(item, Size(bitmap.width.toFloat(), bitmap.height.toFloat()))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.pluu.webtoon.episode.ui.compose

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
Expand All @@ -9,18 +8,14 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
Expand All @@ -36,10 +31,7 @@ import com.pluu.webtoon.episode.R
import com.pluu.webtoon.episode.compose.ImageInCircle
import com.pluu.webtoon.model.EpisodeInfo
import com.pluu.webtoon.ui.compose.theme.AppTheme
import com.pluu.webtoon.ui.compose.theme.themeRed
import com.pluu.webtoon.utils.glideUrl
import com.skydoves.landscapist.ImageOptions
import com.skydoves.landscapist.glide.GlideImage
import com.pluu.webtoon.utils.ToonImage

@Composable
internal fun EpisodeItemUi(
Expand All @@ -48,6 +40,7 @@ internal fun EpisodeItemUi(
isRead: Boolean,
onClicked: (EpisodeInfo) -> Unit
) {
val context = LocalContext.current
Card(
modifier = modifier
.fillMaxWidth()
Expand All @@ -56,29 +49,10 @@ internal fun EpisodeItemUi(
.clickable { onClicked(item) }
) {
Box {
GlideImage(
imageModel = { item.image.glideUrl() },
ToonImage(
imageUrl = { item.image },
modifier = Modifier.fillMaxSize(),
imageOptions = ImageOptions(
contentScale = ContentScale.Crop,
alignment = Alignment.Center
),
previewPlaceholder = painterResource(id = com.pluu.compose.R.drawable.ic_baseline_android_24),
loading = {
CircularProgressIndicator(
modifier = Modifier
.matchParentSize()
.wrapContentSize(),
color = themeRed
)
},
failure = {
Image(
painter = painterResource(com.pluu.webtoon.ui_common.R.drawable.ic_sentiment_very_dissatisfied_48),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
contentDescription = null
)
}
previewPlaceholder = painterResource(id = com.pluu.compose.R.drawable.ic_baseline_android_24)
)
EpisodeItemUiOverlayUi(item = item, isRead = isRead)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -23,7 +21,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
Expand All @@ -41,10 +38,8 @@ import com.pluu.webtoon.model.ToonInfo
import com.pluu.webtoon.model.ToonInfoWithFavorite
import com.pluu.webtoon.ui.compose.theme.AppTheme
import com.pluu.webtoon.ui.compose.theme.themeRed
import com.pluu.webtoon.utils.glideUrl
import com.pluu.webtoon.utils.ToonImage
import com.pluu.webtoon.weekly.R
import com.skydoves.landscapist.ImageOptions
import com.skydoves.landscapist.glide.GlideImage

@Composable
internal fun WeeklyItemUi(
Expand All @@ -62,31 +57,12 @@ internal fun WeeklyItemUi(
.clickable { onClicked(item) }
) {
Box(modifier = Modifier.fillMaxSize()) {
GlideImage(
imageModel = {
item.image.glideUrl()
},
ToonImage(
imageUrl = { item.image },
modifier = Modifier.fillMaxSize(),
imageOptions = ImageOptions(
contentScale = ContentScale.Crop,
alignment = Alignment.Center
),
previewPlaceholder = painterResource(id = com.pluu.compose.R.drawable.ic_baseline_android_24),
loading = {
CircularProgressIndicator(
modifier = Modifier
.matchParentSize()
.wrapContentSize(),
color = themeRed
)
},
failure = {
Image(
modifier = Modifier.align(Alignment.Center),
painter = painterResource(com.pluu.webtoon.ui_common.R.drawable.ic_sentiment_very_dissatisfied_48),
contentDescription = null
)
}
previewPlaceholder = painterResource(
id = com.pluu.compose.R.drawable.ic_baseline_android_24
)
)
WeeklyItemOverlayUi(
item = item,
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ kotlin-coroutine-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-
kotlin-coroutine-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlin-coroutine" }
kotlin-serialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"
## etc
landscapist = "com.github.skydoves:landscapist-glide:2.4.2"
landscapist = "com.github.skydoves:landscapist-coil:2.4.2"
jsoup = "org.jsoup:jsoup:1.18.1"
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-loggingInterceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
Expand Down

0 comments on commit f5c9180

Please # to comment.