From 17ee60d7438c6dffbfc8f8ce25fe9fd25a90f58c Mon Sep 17 00:00:00 2001 From: DatLag Date: Wed, 13 Dec 2023 02:03:54 +0100 Subject: [PATCH] fix theme loading on android and simplified cover image --- .../shared/module/PlatformModule.android.kt | 3 +- .../shared/ui/theme/SchemeTheme.android.kt | 5 -- .../burningseries/shared/ui/custom/Cover.kt | 62 +++++++++++++++++++ .../initial/home/component/EpisodeItem.kt | 25 +++----- .../initial/home/component/SeriesItem.kt | 25 +++----- .../ui/screen/initial/series/SeriesScreen.kt | 33 +++------- .../shared/ui/theme/SchemeTheme.kt | 47 ++------------ .../shared/ui/theme/image/PainterImage.kt | 37 ----------- gradle/libs.versions.toml | 2 +- 9 files changed, 92 insertions(+), 147 deletions(-) create mode 100644 app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/Cover.kt delete mode 100644 app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/image/PainterImage.kt diff --git a/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/module/PlatformModule.android.kt b/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/module/PlatformModule.android.kt index 8836cbff..ccbdd51d 100644 --- a/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/module/PlatformModule.android.kt +++ b/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/module/PlatformModule.android.kt @@ -3,7 +3,6 @@ package dev.datlag.burningseries.shared.module import android.content.Context import android.os.Build import coil3.ImageLoader -import coil3.PlatformContext import coil3.annotation.ExperimentalCoilApi import coil3.decode.GifDecoder import coil3.decode.ImageDecoderDecoder @@ -11,6 +10,7 @@ import coil3.decode.SvgDecoder import coil3.disk.DiskCache import coil3.fetch.NetworkFetcher import coil3.memory.MemoryCache +import coil3.request.allowHardware import coil3.request.crossfade import dev.datlag.burningseries.database.DriverFactory import dev.datlag.burningseries.shared.Sekret @@ -97,6 +97,7 @@ actual object PlatformModule { .maxSizeBytes(512L * 1024 * 1024) // 512MB .build() } + .allowHardware(false) .crossfade(true) .build() } diff --git a/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.android.kt b/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.android.kt index d7619fdb..0017353d 100644 --- a/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.android.kt +++ b/app/shared/src/androidMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.android.kt @@ -2,11 +2,6 @@ package dev.datlag.burningseries.shared.ui.theme import androidx.compose.material3.ColorScheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.graphics.toPixelMap -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection -import dev.datlag.burningseries.shared.ui.theme.image.PainterImage @Composable actual fun SchemeThemeSystemProvider( diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/Cover.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/Cover.kt new file mode 100644 index 00000000..689dfb89 --- /dev/null +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/custom/Cover.kt @@ -0,0 +1,62 @@ +package dev.datlag.burningseries.shared.ui.custom + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.NoPhotography +import androidx.compose.material3.LocalContentColor +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.layout.ContentScale +import coil3.ImageLoader +import coil3.PlatformContext +import coil3.compose.AsyncImage +import coil3.compose.AsyncImagePainter +import coil3.request.ImageRequest +import dev.datlag.burningseries.shared.LocalDI +import org.kodein.di.instance + +@Composable +fun Cover( + key: String?, + data: Any?, + contentDescription: String?, + contentScale: ContentScale = ContentScale.FillWidth, + modifier: Modifier = Modifier, + errorPainter: Painter = rememberVectorPainter(Icons.Default.NoPhotography), + errorColorFilter: ColorFilter? = ColorFilter.tint(LocalContentColor.current), + errorScale: ContentScale = ContentScale.Inside, + onSuccess: (AsyncImagePainter.State.Success) -> Unit = {} +) { + val platformContext: PlatformContext by LocalDI.current.instance() + val imageLoader: ImageLoader by LocalDI.current.instance() + var scale by remember { mutableStateOf(contentScale) } + var filter by remember { mutableStateOf(null) } + + AsyncImage( + model = ImageRequest.Builder(platformContext) + .data(data) + .placeholderMemoryCacheKey(key) + .build(), + error = errorPainter, + imageLoader = imageLoader, + contentDescription = contentDescription, + contentScale = scale, + modifier = modifier, + onLoading = { + scale = contentScale + filter = null + }, + onError = { + scale = errorScale + filter = errorColorFilter + }, + onSuccess = { + scale = contentScale + filter = null + onSuccess(it) + }, + colorFilter = filter + ) +} \ No newline at end of file diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/EpisodeItem.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/EpisodeItem.kt index d9455b97..f671da35 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/EpisodeItem.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/EpisodeItem.kt @@ -10,23 +10,18 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import coil3.ImageLoader -import coil3.PlatformContext -import coil3.compose.AsyncImage -import coil3.request.ImageRequest import dev.datlag.burningseries.model.BSUtil import dev.datlag.burningseries.model.Home -import dev.datlag.burningseries.shared.LocalDI import dev.datlag.burningseries.shared.common.bounceClick import dev.datlag.burningseries.shared.common.focusScale import dev.datlag.burningseries.shared.common.onClick import dev.datlag.burningseries.shared.ui.custom.AutoSizeText import dev.datlag.burningseries.shared.ui.custom.CountryImage -import org.kodein.di.instance +import dev.datlag.burningseries.shared.ui.custom.Cover @OptIn(ExperimentalFoundationApi::class) @Composable @@ -42,21 +37,15 @@ fun LazyGridItemScope.EpisodeItem(episode: Home.Episode, onclick: () -> Unit) { Surface( shape = CardDefaults.elevatedShape ) { - val platformContext: PlatformContext by LocalDI.current.instance() - val imageLoader: ImageLoader by LocalDI.current.instance() - - AsyncImage( - model = ImageRequest.Builder(platformContext) - .data(episode.coverHref?.let { BSUtil.getBurningSeriesLink(it) }) - .placeholderMemoryCacheKey(episode.coverHref) - .build(), - imageLoader = imageLoader, + Cover( + key = episode.coverHref, + data = episode.coverHref?.let { BSUtil.getBurningSeriesLink(it) }, contentDescription = episode.bestTitle, - contentScale = ContentScale.FillWidth, modifier = Modifier .aspectRatio(1F, true) .clip(CardDefaults.elevatedShape) - .background(MaterialTheme.colorScheme.tertiaryContainer) + .background(MaterialTheme.colorScheme.tertiaryContainer), + errorColorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onTertiaryContainer) ) } Column( diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/SeriesItem.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/SeriesItem.kt index 5c750a1a..26279ab0 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/SeriesItem.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/home/component/SeriesItem.kt @@ -9,21 +9,16 @@ import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import coil3.ImageLoader -import coil3.PlatformContext -import coil3.compose.AsyncImage -import coil3.request.ImageRequest import dev.datlag.burningseries.database.common.bestTitle import dev.datlag.burningseries.model.BSUtil import dev.datlag.burningseries.model.Home -import dev.datlag.burningseries.shared.LocalDI import dev.datlag.burningseries.shared.common.bounceClick import dev.datlag.burningseries.shared.common.focusScale import dev.datlag.burningseries.shared.common.onClick -import org.kodein.di.instance +import dev.datlag.burningseries.shared.ui.custom.Cover import dev.datlag.burningseries.database.Series as DBSeries @OptIn(ExperimentalFoundationApi::class) @@ -72,21 +67,15 @@ private fun SeriesItem(title: String, coverHref: String?, modifier: Modifier = M Surface( shape = CardDefaults.elevatedShape ) { - val platformContext: PlatformContext by LocalDI.current.instance() - val imageLoader: ImageLoader by LocalDI.current.instance() - - AsyncImage( - model = ImageRequest.Builder(platformContext) - .data(coverHref?.let { BSUtil.getBurningSeriesLink(it) }) - .placeholderMemoryCacheKey(coverHref) - .build(), - imageLoader = imageLoader, + Cover( + key = coverHref, + data = coverHref?.let { BSUtil.getBurningSeriesLink(it) }, contentDescription = title, - contentScale = ContentScale.FillWidth, modifier = Modifier .aspectRatio(1F, true) .clip(CardDefaults.elevatedShape) - .background(MaterialTheme.colorScheme.tertiaryContainer) + .background(MaterialTheme.colorScheme.tertiaryContainer), + errorColorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onTertiaryContainer) ) } Column( diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreen.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreen.kt index d2db821f..71c234d8 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreen.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/screen/initial/series/SeriesScreen.kt @@ -20,23 +20,18 @@ 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.layout.ContentScale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import coil3.ImageLoader -import coil3.PlatformContext -import coil3.compose.AsyncImage -import coil3.request.ImageRequest import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState import dev.datlag.burningseries.database.Episode import dev.datlag.burningseries.model.BSUtil import dev.datlag.burningseries.model.Series import dev.datlag.burningseries.model.state.SeriesState -import dev.datlag.burningseries.shared.LocalDI import dev.datlag.burningseries.shared.SharedRes import dev.datlag.burningseries.shared.common.diagonalShape import dev.datlag.burningseries.shared.common.lifecycle.collectAsStateWithLifecycle import dev.datlag.burningseries.shared.other.StateSaver +import dev.datlag.burningseries.shared.ui.custom.Cover import dev.datlag.burningseries.shared.ui.custom.DefaultCollapsingToolbar import dev.datlag.burningseries.shared.ui.custom.VerticalScrollbar import dev.datlag.burningseries.shared.ui.custom.rememberScrollbarAdapter @@ -48,7 +43,6 @@ import dev.datlag.burningseries.shared.ui.screen.initial.series.component.Season import dev.datlag.burningseries.shared.ui.theme.SchemeTheme import dev.datlag.burningseries.shared.ui.theme.shape.DiagonalShape import dev.icerock.moko.resources.compose.stringResource -import org.kodein.di.instance import kotlin.math.abs @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) @@ -94,18 +88,12 @@ private fun CompactScreen(component: SeriesComponent) { DefaultCollapsingToolbar( expandedBody = { state -> - val platformContext: PlatformContext by LocalDI.current.instance() - val imageLoader: ImageLoader by LocalDI.current.instance() val scope = rememberCoroutineScope() - AsyncImage( - model = ImageRequest.Builder(platformContext) - .data(coverHref?.let { BSUtil.getBurningSeriesLink(it) }) - .placeholderMemoryCacheKey(coverHref) - .build(), - imageLoader = imageLoader, + Cover( + key = coverHref, + data = coverHref?.let { BSUtil.getBurningSeriesLink(it) }, contentDescription = title, - contentScale = ContentScale.FillWidth, modifier = Modifier .fillMaxWidth() .defaultMinSize(minHeight = 320.dp) @@ -115,7 +103,6 @@ private fun CompactScreen(component: SeriesComponent) { SchemeTheme.update(commonHref, success.painter, scope) } ) - Text( text = title, modifier = Modifier.road(Alignment.TopStart, Alignment.BottomStart).padding(16.dp).background( @@ -318,8 +305,6 @@ private fun DefaultScreen(component: SeriesComponent) { modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - val platformContext: PlatformContext by LocalDI.current.instance() - val imageLoader: ImageLoader by LocalDI.current.instance() val scope = rememberCoroutineScope() Column( @@ -384,14 +369,10 @@ private fun DefaultScreen(component: SeriesComponent) { ) } - AsyncImage( - model = ImageRequest.Builder(platformContext) - .data(coverHref?.let { BSUtil.getBurningSeriesLink(it) }) - .placeholderMemoryCacheKey(coverHref) - .build(), - imageLoader = imageLoader, + Cover( + key = coverHref, + data = coverHref?.let { BSUtil.getBurningSeriesLink(it) }, contentDescription = title, - contentScale = ContentScale.FillWidth, modifier = Modifier .width(200.dp) .clip(MaterialTheme.shapes.medium) diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.kt index 75807220..cdeae412 100644 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.kt +++ b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/SchemeTheme.kt @@ -7,29 +7,19 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.LayoutDirection -import androidx.palette.graphics.Palette import com.kmpalette.DominantColorState -import com.kmpalette.loader.ImageBitmapLoader -import com.kmpalette.rememberDominantColorState +import com.kmpalette.rememberPainterDominantColorState import com.materialkolor.AnimatedDynamicMaterialTheme import dev.datlag.burningseries.shared.LocalDarkMode import dev.datlag.burningseries.shared.common.launchIO import dev.datlag.burningseries.shared.common.lifecycle.collectAsStateWithLifecycle import dev.datlag.burningseries.shared.common.withIOContext -import dev.datlag.burningseries.shared.ui.theme.image.PainterImage import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.getAndUpdate import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update -import kotlin.coroutines.CoroutineContext data object SchemeTheme { @@ -78,35 +68,6 @@ data object SchemeTheme { } } -internal data class PainterLoader( - private val density: Density, - private val layoutDirection: LayoutDirection -) : ImageBitmapLoader { - override suspend fun load(input: Painter): ImageBitmap { - return PainterImage(input, density, layoutDirection).asBitmap() - } -} - -@Composable -public fun rememberPainterDominantColorState( - defaultColor: Color = MaterialTheme.colorScheme.primary, - defaultOnColor: Color = MaterialTheme.colorScheme.onPrimary, - density: Density = LocalDensity.current, - layoutDirection: LayoutDirection = LocalLayoutDirection.current, - cacheSize: Int = 0, - coroutineContext: CoroutineContext = Dispatchers.Default, - isSwatchValid: (Palette.Swatch) -> Boolean = { true }, - builder: Palette.Builder.() -> Unit = {}, -): DominantColorState = rememberDominantColorState( - loader = PainterLoader(density, layoutDirection), - defaultColor = defaultColor, - defaultOnColor = defaultOnColor, - cacheSize = cacheSize, - coroutineContext = coroutineContext, - isSwatchValid = isSwatchValid, - builder = builder -) - @Composable fun SchemeTheme(key: Any?, content: @Composable () -> Unit) { if (SchemeTheme._state == null) { @@ -121,7 +82,11 @@ fun SchemeTheme(key: Any?, content: @Composable () -> Unit) { seedColor = color ?: MaterialTheme.colorScheme.primary, useDarkTheme = LocalDarkMode.current ) { - content() + androidx.compose.material.MaterialTheme( + colors = MaterialTheme.colorScheme.toLegacyColors(LocalDarkMode.current) + ) { + content() + } } } diff --git a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/image/PainterImage.kt b/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/image/PainterImage.kt deleted file mode 100644 index 2fb86989..00000000 --- a/app/shared/src/commonMain/kotlin/dev/datlag/burningseries/shared/ui/theme/image/PainterImage.kt +++ /dev/null @@ -1,37 +0,0 @@ -package dev.datlag.burningseries.shared.ui.theme.image - -import androidx.compose.ui.geometry.Size -import androidx.compose.ui.graphics.Canvas -import androidx.compose.ui.graphics.ImageBitmap -import androidx.compose.ui.graphics.drawscope.CanvasDrawScope -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.LayoutDirection -import kotlin.math.roundToInt - -class PainterImage( - private val painter: Painter, - private val density: Density, - private val layoutDirection: LayoutDirection, -) { - fun asBitmap( - width: Int = painter.intrinsicSize.width.roundToInt(), - height: Int = painter.intrinsicSize.height.roundToInt() - ): ImageBitmap { - val bitmap = ImageBitmap(width, height) - val canvas = Canvas(bitmap) - val floatSize = Size(width.toFloat(), height.toFloat()) - - bitmap.prepareToDraw() - - CanvasDrawScope().draw( - density, layoutDirection, canvas, floatSize - ) { - with(painter) { - draw(floatSize) - } - } - - return bitmap - } -} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e1c82e6f..5e4b5d80 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ grpc = "1.59.0" instesx = "0.1.0-alpha10" jsunpacker = "1.0.2" kcef = "2023.10.13" -kmpalette = "2.1.0" +kmpalette = "2.2.0" kodein = "7.21.1" kolor = "1.2.9" kotlin = "1.9.21"