fix(image): Coil 2 대응 BlurTransformation 구현을 추가한다

This commit is contained in:
2026-04-20 11:46:38 +09:00
parent 272cd502be
commit b589329398
3 changed files with 148 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
package kr.co.vividnext.sodalive.common.image
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.Config.ARGB_8888
import android.graphics.Paint
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import androidx.annotation.RequiresApi
import androidx.core.graphics.applyCanvas
import coil.size.Size
import coil.transform.Transformation
/**
* Coil 2.x 환경에서 기존 blur 호출부를 유지하기 위한 Android blur transformation이다.
*/
@RequiresApi(18)
class BlurTransformation @JvmOverloads constructor(
private val context: Context,
private val radius: Float = DEFAULT_RADIUS,
private val sampling: Float = DEFAULT_SAMPLING
) : Transformation {
init {
require(radius in 0.0f..25.0f) { "radius must be in [0, 25]." }
require(sampling > 0f) { "sampling must be > 0." }
}
override val cacheKey: String = "${BlurTransformation::class.java.name}-$radius-$sampling"
@Suppress("DEPRECATION")
override suspend fun transform(input: Bitmap, size: Size): Bitmap {
val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
val scaledWidth = (input.width / sampling).toInt().coerceAtLeast(1)
val scaledHeight = (input.height / sampling).toInt().coerceAtLeast(1)
val output = Bitmap.createBitmap(scaledWidth, scaledHeight, input.config ?: ARGB_8888)
output.applyCanvas {
scale(1f / sampling, 1f / sampling)
drawBitmap(input, 0f, 0f, paint)
}
var renderScript: RenderScript? = null
var inputAllocation: Allocation? = null
var outputAllocation: Allocation? = null
var blurScript: ScriptIntrinsicBlur? = null
try {
renderScript = RenderScript.create(context)
inputAllocation = Allocation.createFromBitmap(
renderScript,
output,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT
)
outputAllocation = Allocation.createTyped(renderScript, inputAllocation.type)
blurScript = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript))
blurScript.setRadius(radius)
blurScript.setInput(inputAllocation)
blurScript.forEach(outputAllocation)
outputAllocation.copyTo(output)
} finally {
blurScript?.destroy()
inputAllocation?.destroy()
outputAllocation?.destroy()
renderScript?.destroy()
}
return output
}
private companion object {
private const val DEFAULT_RADIUS = 10f
private const val DEFAULT_SAMPLING = 1f
}
}

View File

@@ -0,0 +1,35 @@
package kr.co.vividnext.sodalive.common.image
import android.content.Context
import io.mockk.mockk
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Test
class BlurTransformationTest {
@Test
fun `cacheKey includes radius and sampling`() {
val transformation = BlurTransformation(
context = mockk<Context>(relaxed = true),
radius = 25f,
sampling = 2.5f
)
assertEquals(
"kr.co.vividnext.sodalive.common.image.BlurTransformation-25.0-2.5",
transformation.cacheKey
)
}
@Test
fun `constructor rejects radius above max`() {
assertThrows(IllegalArgumentException::class.java) {
BlurTransformation(
context = mockk<Context>(relaxed = true),
radius = 26f,
sampling = 2.5f
)
}
}
}

View File

@@ -0,0 +1,34 @@
# 20260420 BlurTransformation 오류 수정
## 작업 체크리스트
- [x] `BlurTransformation` 컴파일 오류의 실제 원인을 의존성 해석 기준으로 확정한다.
QA: `dependencyInsight` 결과에서 어떤 경로가 `io.coil-kt:coil`을 2.x로 올리는지 확인되어야 한다.
- [x] 최소 수정 방향을 정하고 실패 재현 경로를 확보한다.
QA: `:app:compileDebugKotlin` 또는 관련 단위 테스트가 수정 전 실패해야 한다.
- [x] Coil 2.x 환경에서 사용할 수 있는 로컬 `BlurTransformation` 호환 구현을 추가한다.
QA: 기존 호출부 시그니처 `(context, 25f, 2.5f)`를 유지한 채 컴파일 가능해야 한다.
- [x] `BlurTransformation` 사용처 import를 최소 범위로 교체한다.
QA: 기존 blur 사용 화면만 수정되고, 다른 Coil transform 사용처는 변경되지 않아야 한다.
- [x] 관련 테스트/컴파일 검증을 수행하고 결과를 기록한다.
QA: 관련 단위 테스트와 `:app:compileDebugKotlin` 결과를 문서 하단에 남겨야 한다.
## 검증 기록
- 2026-04-20
- 무엇: `BlurTransformation` unresolved 오류의 원인을 `Daro -> Moloco -> coil-compose:2.2.2` 경로로 확정하고, Coil 2.x에서 사용할 로컬 `BlurTransformation` 호환 구현을 추가했다.
- 왜: `so.daro:daro-a:1.5.3` 추가 후 Moloco SDK가 `io.coil-kt:coil-compose:2.2.2`를 끌어오면서 앱의 `io.coil-kt:coil:1.4.0`이 2.2.2로 승격됐고, Coil 2에서 제거된 `coil.transform.BlurTransformation`만 컴파일 오류가 발생했기 때문이다.
- 어떻게:
- 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/common/image/BlurTransformation.kt`
- 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/audio_content/series/detail/SeriesDetailActivity.kt`
- 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/chat/original/detail/OriginalWorkDetailActivity.kt`
- 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt`
- 수정 파일: `app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/creator_community/CreatorCommunityAdapter.kt`
- 추가 파일: `app/src/test/java/kr/co/vividnext/sodalive/common/image/BlurTransformationTest.kt`
- 실행 명령: `./gradlew :app:dependencyInsight --configuration debugRuntimeClasspath --dependency io.coil-kt:coil`
- 결과: `so.daro:daro-a:1.5.3 -> com.google.ads.mediation:moloco -> com.moloco.sdk:moloco-sdk:4.1.1 -> io.coil-kt:coil-compose:2.2.2 -> io.coil-kt:coil:2.2.2` 경로를 확인했다.
- 실행 명령: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.common.image.BlurTransformationTest"`
- 결과: 수정 전에는 main source의 `BlurTransformation` unresolved로 실패했고, 호환 구현 추가 후 테스트 포함 `BUILD SUCCESSFUL`로 통과했다.
- 실행 명령: `./gradlew :app:compileDebugKotlin`
- 결과: `BUILD SUCCESSFUL`
- 실행 명령: `./gradlew :app:assembleDebug`
- 결과: `BUILD SUCCESSFUL`
- 진단 도구: Kotlin(`.kt`)용 LSP 서버 미구성으로 `lsp_diagnostics` 실행 불가 확인