From 1731e7c0010df33aacda7ca78668745c3510c70d Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sun, 24 Oct 2021 17:44:20 -0400 Subject: [PATCH] Migrate image loading and display to Kamel --- build.gradle.kts | 1 + src/main/kotlin/ca/gosyer/data/DataModule.kt | 6 ++ .../kotlin/ca/gosyer/data/models/Extension.kt | 4 +- .../kotlin/ca/gosyer/data/models/Manga.kt | 4 +- .../kotlin/ca/gosyer/data/models/Source.kt | 1 - .../gosyer/data/server/KamelConfigProvider.kt | 78 ++++++++++++++ .../kotlin/ca/gosyer/ui/base/WindowDialog.kt | 10 +- .../gosyer/ui/base/components/KamelImage.kt | 53 ++++++++++ .../ca/gosyer/ui/base/components/KtorImage.kt | 100 ------------------ .../ca/gosyer/ui/base/components/Manga.kt | 8 +- .../ui/base/components/MangaListItem.kt | 21 ++-- .../ca/gosyer/ui/extensions/ExtensionsMenu.kt | 9 +- .../ui/extensions/ExtensionsMenuViewModel.kt | 3 - .../ca/gosyer/ui/library/LibraryScreen.kt | 4 - .../ui/library/LibraryScreenViewModel.kt | 6 +- .../ca/gosyer/ui/library/MangaCompactGrid.kt | 14 +-- src/main/kotlin/ca/gosyer/ui/main/main.kt | 6 +- .../kotlin/ca/gosyer/ui/manga/MangaMenu.kt | 25 ++--- .../ca/gosyer/ui/manga/MangaMenuViewModel.kt | 4 - .../kotlin/ca/gosyer/ui/reader/ReaderMenu.kt | 6 +- .../ca/gosyer/ui/sources/SourcesMenu.kt | 15 ++- .../gosyer/ui/sources/SourcesMenuViewModel.kt | 4 - .../ui/sources/components/SourceHomeScreen.kt | 12 +-- .../ui/sources/components/SourceScreen.kt | 7 +- .../components/SourceScreenViewModel.kt | 11 +- .../ca/gosyer/ui/updates/UpdatesMenu.kt | 8 +- .../gosyer/ui/updates/UpdatesMenuViewModel.kt | 4 - 27 files changed, 221 insertions(+), 203 deletions(-) create mode 100644 src/main/kotlin/ca/gosyer/data/server/KamelConfigProvider.kt create mode 100644 src/main/kotlin/ca/gosyer/ui/base/components/KamelImage.kt delete mode 100644 src/main/kotlin/ca/gosyer/ui/base/components/KtorImage.kt diff --git a/build.gradle.kts b/build.gradle.kts index b3fef253..56f17ce2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation("ca.gosyer:compose-router:0.24.2-jetbrains-2") implementation("ca.gosyer:accompanist-pager:0.18.1") implementation("ca.gosyer:accompanist-flowlayout:0.18.1") + implementation("com.alialbaali.kamel:kamel-image:0.3.0") // UI (Swing) implementation("com.github.weisj:darklaf-core:2.7.3") diff --git a/src/main/kotlin/ca/gosyer/data/DataModule.kt b/src/main/kotlin/ca/gosyer/data/DataModule.kt index 3e739e72..7daf94ac 100644 --- a/src/main/kotlin/ca/gosyer/data/DataModule.kt +++ b/src/main/kotlin/ca/gosyer/data/DataModule.kt @@ -14,6 +14,7 @@ import ca.gosyer.data.library.LibraryPreferences import ca.gosyer.data.reader.ReaderPreferences import ca.gosyer.data.server.Http import ca.gosyer.data.server.HttpProvider +import ca.gosyer.data.server.KamelConfigProvider import ca.gosyer.data.server.ServerHostPreferences import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.ServerService @@ -28,6 +29,7 @@ import ca.gosyer.data.server.interactions.SourceInteractionHandler import ca.gosyer.data.translation.ResourceProvider import ca.gosyer.data.translation.XmlResourceBundle import ca.gosyer.data.ui.UiPreferences +import io.kamel.core.config.KamelConfig import toothpick.ktp.binding.bind import toothpick.ktp.binding.module @@ -66,6 +68,10 @@ val DataModule = module { .toProvider(HttpProvider::class) .providesSingleton() + bind() + .toProvider(KamelConfigProvider::class) + .providesSingleton() + bind() .toProvider(ResourceProvider::class) .providesSingleton() diff --git a/src/main/kotlin/ca/gosyer/data/models/Extension.kt b/src/main/kotlin/ca/gosyer/data/models/Extension.kt index 45ba1c93..aec046a4 100644 --- a/src/main/kotlin/ca/gosyer/data/models/Extension.kt +++ b/src/main/kotlin/ca/gosyer/data/models/Extension.kt @@ -21,6 +21,4 @@ data class Extension( val hasUpdate: Boolean, val obsolete: Boolean, val isNsfw: Boolean -) { - fun iconUrl(serverUrl: String) = serverUrl + iconUrl -} +) diff --git a/src/main/kotlin/ca/gosyer/data/models/Manga.kt b/src/main/kotlin/ca/gosyer/data/models/Manga.kt index 9dda6123..0a56c502 100644 --- a/src/main/kotlin/ca/gosyer/data/models/Manga.kt +++ b/src/main/kotlin/ca/gosyer/data/models/Manga.kt @@ -27,9 +27,7 @@ data class Manga( val meta: MangaMeta, val realUrl: String?, val inLibraryAt: Long -) { - fun cover(serverUrl: String) = thumbnailUrl?.let { serverUrl + it } -} +) @Serializable data class MangaMeta( diff --git a/src/main/kotlin/ca/gosyer/data/models/Source.kt b/src/main/kotlin/ca/gosyer/data/models/Source.kt index 103cb4d7..da8e2872 100644 --- a/src/main/kotlin/ca/gosyer/data/models/Source.kt +++ b/src/main/kotlin/ca/gosyer/data/models/Source.kt @@ -19,7 +19,6 @@ data class Source( val isNsfw: Boolean, val displayName: String ) { - fun iconUrl(serverUrl: String) = serverUrl + iconUrl companion object { const val LOCAL_SOURCE_LANG = "localsourcelang" } diff --git a/src/main/kotlin/ca/gosyer/data/server/KamelConfigProvider.kt b/src/main/kotlin/ca/gosyer/data/server/KamelConfigProvider.kt new file mode 100644 index 00000000..39f46197 --- /dev/null +++ b/src/main/kotlin/ca/gosyer/data/server/KamelConfigProvider.kt @@ -0,0 +1,78 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package ca.gosyer.data.server + +import ca.gosyer.data.models.Extension +import ca.gosyer.data.models.Manga +import ca.gosyer.data.models.Source +import ca.gosyer.ui.base.prefs.asStateIn +import io.kamel.core.config.DefaultCacheSize +import io.kamel.core.config.KamelConfig +import io.kamel.core.config.fileFetcher +import io.kamel.core.config.httpFetcher +import io.kamel.core.config.stringMapper +import io.kamel.core.config.uriMapper +import io.kamel.core.config.urlMapper +import io.kamel.core.mapper.Mapper +import io.kamel.image.config.imageBitmapDecoder +import io.kamel.image.config.resourcesFetcher +import io.ktor.http.Url +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject +import javax.inject.Provider + +class KamelConfigProvider @Inject constructor( + private val http: Http, + serverPreferences: ServerPreferences +) : Provider { + @OptIn(DelicateCoroutinesApi::class) + val serverUrl = serverPreferences.serverUrl().asStateIn(GlobalScope) + + override fun get(): KamelConfig { + return KamelConfig { + // Default config + imageBitmapCacheSize = DefaultCacheSize + imageVectorCacheSize = DefaultCacheSize + imageBitmapDecoder() + stringMapper() + urlMapper() + uriMapper() + fileFetcher() + + // JUI config + httpFetcher(http.engine) { + install(http) + } + resourcesFetcher() + val serverUrl = serverUrl.asStateFlow() + mapper(MangaCoverMapper(serverUrl)) + mapper(ExtensionIconMapper(serverUrl)) + mapper(SourceIconMapper(serverUrl)) + } + } + + class MangaCoverMapper(private val serverUrlStateFlow: StateFlow) : Mapper { + override fun map(input: Manga): Url { + return Url(serverUrlStateFlow.value + input.thumbnailUrl) + } + } + + class ExtensionIconMapper(private val serverUrlStateFlow: StateFlow) : Mapper { + override fun map(input: Extension): Url { + return Url(serverUrlStateFlow.value + input.iconUrl) + } + } + + class SourceIconMapper(private val serverUrlStateFlow: StateFlow) : Mapper { + override fun map(input: Source): Url { + return Url(serverUrlStateFlow.value + input.iconUrl) + } + } +} diff --git a/src/main/kotlin/ca/gosyer/ui/base/WindowDialog.kt b/src/main/kotlin/ca/gosyer/ui/base/WindowDialog.kt index 8c37a8b0..ed7d5cf2 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/WindowDialog.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/WindowDialog.kt @@ -40,6 +40,8 @@ import ca.gosyer.ui.base.components.setIcon import ca.gosyer.ui.base.resources.LocalResources import ca.gosyer.ui.base.theme.AppTheme import ca.gosyer.util.lang.launchApplication +import io.kamel.core.config.KamelConfig +import io.kamel.image.config.LocalKamelConfig import kotlinx.coroutines.DelicateCoroutinesApi @OptIn(DelicateCoroutinesApi::class) @@ -69,6 +71,7 @@ fun WindowDialog( } val resources = remember { AppScope.getInstance() } + val kamelConfig = remember { AppScope.getInstance() } val windowState = rememberWindowState(size = size, position = WindowPosition(Alignment.Center)) Window( @@ -95,7 +98,8 @@ fun WindowDialog( ) { setIcon() CompositionLocalProvider( - LocalResources provides resources + LocalResources provides resources, + LocalKamelConfig provides kamelConfig ) { AppTheme { Surface { @@ -144,6 +148,7 @@ fun WindowDialog( } val resources = remember { AppScope.getInstance() } + val kamelConfig = remember { AppScope.getInstance() } val windowState = rememberWindowState(size = size, position = WindowPosition.Aligned(Alignment.Center)) Window( @@ -162,7 +167,8 @@ fun WindowDialog( ) { setIcon() CompositionLocalProvider( - LocalResources provides resources + LocalResources provides resources, + LocalKamelConfig provides kamelConfig ) { AppTheme { Surface { diff --git a/src/main/kotlin/ca/gosyer/ui/base/components/KamelImage.kt b/src/main/kotlin/ca/gosyer/ui/base/components/KamelImage.kt new file mode 100644 index 00000000..07b4c1d9 --- /dev/null +++ b/src/main/kotlin/ca/gosyer/ui/base/components/KamelImage.kt @@ -0,0 +1,53 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package ca.gosyer.ui.base.components + +import androidx.compose.animation.core.FiniteAnimationSpec +import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.fillMaxSize +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.DefaultAlpha +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale +import io.kamel.core.Resource +import io.kamel.image.KamelImage as BaseKamelImage + +@Composable +fun KamelImage( + resource: Resource, + contentDescription: String?, + modifier: Modifier = Modifier, + alignment: Alignment = Alignment.Center, + contentScale: ContentScale = ContentScale.Fit, + alpha: Float = DefaultAlpha, + colorFilter: ColorFilter? = null, + onLoading: @Composable (Float) -> Unit = { + LoadingScreen(progress = it, modifier = modifier then Modifier.fillMaxSize()) + }, + onFailure: @Composable (Throwable) -> Unit = { + ErrorScreen(it.localizedMessage, modifier = modifier then Modifier.fillMaxSize()) + }, + crossfade: Boolean = true, + animationSpec: FiniteAnimationSpec = tween() +) { + BaseKamelImage( + resource, + contentDescription, + modifier, + alignment, + contentScale, + alpha, + colorFilter, + onLoading, + onFailure, + crossfade, + animationSpec + ) +} diff --git a/src/main/kotlin/ca/gosyer/ui/base/components/KtorImage.kt b/src/main/kotlin/ca/gosyer/ui/base/components/KtorImage.kt deleted file mode 100644 index cf2a09da..00000000 --- a/src/main/kotlin/ca/gosyer/ui/base/components/KtorImage.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package ca.gosyer.ui.base.components - -import androidx.compose.animation.Crossfade -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.BoxWithConstraints -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.DefaultAlpha -import androidx.compose.ui.graphics.FilterQuality -import androidx.compose.ui.graphics.ImageBitmap -import androidx.compose.ui.layout.ContentScale -import ca.gosyer.common.di.AppScope -import ca.gosyer.data.server.Http -import ca.gosyer.util.compose.imageFromUrl -import ca.gosyer.util.system.kLogger -import io.ktor.client.features.onDownload -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.sync.Semaphore -import kotlinx.coroutines.sync.withPermit - -private val logger = kLogger {} -private val semaphore = Semaphore(5) - -@OptIn(DelicateCoroutinesApi::class) -@Composable -fun KtorImage( - imageUrl: String, - modifier: Modifier = Modifier.fillMaxSize(), - loadingModifier: Modifier = modifier, - contentDescription: String? = null, - alignment: Alignment = Alignment.Center, - contentScale: ContentScale = ContentScale.Fit, - alpha: Float = DefaultAlpha, - colorFilter: ColorFilter? = null, - filterQuality: FilterQuality = FilterQuality.Medium, - client: Http = remember { AppScope.getInstance() } -) { - BoxWithConstraints(modifier) { - val drawable = remember { mutableStateOf(null) } - val loading = remember { mutableStateOf(true) } - val progress = remember { mutableStateOf(0.0F) } - val error = remember { mutableStateOf(null) } - DisposableEffect(imageUrl) { - val handler = CoroutineExceptionHandler { _, throwable -> - logger.error(throwable) { "Error loading image $imageUrl" } - loading.value = false - error.value = throwable.message - } - val job = GlobalScope.launch(handler) { - if (drawable.value == null) { - semaphore.withPermit { - drawable.value = imageFromUrl(client, imageUrl) { - onDownload { bytesSentTotal, contentLength -> - progress.value = (bytesSentTotal.toFloat() / contentLength).coerceAtMost(1.0F) - } - } - } - } - loading.value = false - } - - onDispose { - job.cancel() - drawable.value = null - } - } - - Crossfade(drawable.value to loading.value) { (value, loading) -> - if (value != null) { - Image( - value, - modifier = Modifier.fillMaxSize(), - contentDescription = contentDescription, - alignment = alignment, - contentScale = contentScale, - alpha = alpha, - colorFilter = colorFilter, - filterQuality = filterQuality - ) - } else { - LoadingScreen(loading, loadingModifier, progress.value, error.value) - } - } - } -} diff --git a/src/main/kotlin/ca/gosyer/ui/base/components/Manga.kt b/src/main/kotlin/ca/gosyer/ui/base/components/Manga.kt index e4e09f99..13810c2b 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/components/Manga.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/components/Manga.kt @@ -23,17 +23,19 @@ import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import io.kamel.core.Resource @Composable fun MangaGridItem( title: String, - cover: String?, + cover: Resource, onClick: () -> Unit = {}, ) { val fontStyle = LocalTextStyle.current.merge( @@ -50,9 +52,7 @@ fun MangaGridItem( shape = RoundedCornerShape(4.dp) ) { Box(modifier = Modifier.fillMaxSize()) { - if (cover != null) { - KtorImage(cover, contentScale = ContentScale.Crop) - } + KamelImage(cover, title, contentScale = ContentScale.Crop) Box(modifier = Modifier.fillMaxSize().then(shadowGradient)) Text( text = title, diff --git a/src/main/kotlin/ca/gosyer/ui/base/components/MangaListItem.kt b/src/main/kotlin/ca/gosyer/ui/base/components/MangaListItem.kt index 10b38ad0..513a4a55 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/components/MangaListItem.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/components/MangaListItem.kt @@ -15,9 +15,11 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow +import io.kamel.core.Resource @Composable fun MangaListItem( @@ -35,18 +37,15 @@ fun MangaListItem( @Composable fun MangaListItemImage( modifier: Modifier = Modifier, - imageUrl: String? + cover: Resource, + contentDescription: String ) { - if (imageUrl != null) { - KtorImage( - imageUrl = imageUrl, - contentDescription = null, - modifier = modifier, - contentScale = ContentScale.Crop - ) - } else { - ErrorScreen(modifier = modifier) - } + KamelImage( + cover, + contentDescription = contentDescription, + modifier = modifier, + contentScale = ContentScale.Crop + ) } @Composable diff --git a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt index 305800c0..f40ba935 100644 --- a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt @@ -39,6 +39,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle @@ -50,7 +51,7 @@ import ca.gosyer.build.BuildConfig import ca.gosyer.data.models.Extension import ca.gosyer.ui.base.WindowDialog import ca.gosyer.ui.base.components.ActionIcon -import ca.gosyer.ui.base.components.KtorImage +import ca.gosyer.ui.base.components.KamelImage import ca.gosyer.ui.base.components.LoadingScreen import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.resources.stringResource @@ -58,6 +59,7 @@ import ca.gosyer.ui.base.vm.viewModel import ca.gosyer.util.compose.ThemedWindow import ca.gosyer.util.compose.persistentLazyListState import ca.gosyer.util.lang.launchApplication +import io.kamel.image.lazyPainterResource import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -80,7 +82,6 @@ fun ExtensionsMenu() { val vm = viewModel() val extensions by vm.extensions.collectAsState() val isLoading by vm.isLoading.collectAsState() - val serverUrl by vm.serverUrl.collectAsState() val search by vm.searchQuery.collectAsState() if (isLoading) { @@ -119,7 +120,6 @@ fun ExtensionsMenu() { items(items) { extension -> ExtensionItem( extension, - serverUrl, onInstallClicked = vm::install, onUpdateClicked = vm::update, onUninstallClicked = vm::uninstall @@ -167,7 +167,6 @@ fun ExtensionsToolbar( @Composable fun ExtensionItem( extension: Extension, - serverUrl: String, onInstallClicked: (Extension) -> Unit, onUpdateClicked: (Extension) -> Unit, onUninstallClicked: (Extension) -> Unit @@ -175,7 +174,7 @@ fun ExtensionItem( Box(modifier = Modifier.fillMaxWidth().padding(end = 12.dp).height(50.dp).background(MaterialTheme.colors.background)) { Row(verticalAlignment = Alignment.CenterVertically) { Spacer(Modifier.width(4.dp)) - KtorImage(extension.iconUrl(serverUrl), Modifier.size(50.dp)) + KamelImage(lazyPainterResource(extension, filterQuality = FilterQuality.Medium), extension.name, Modifier.size(50.dp)) Spacer(Modifier.width(8.dp)) Column { val title = buildAnnotatedString { diff --git a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt index d645d327..989a0c6d 100644 --- a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt @@ -8,7 +8,6 @@ package ca.gosyer.ui.extensions import ca.gosyer.data.extension.ExtensionPreferences import ca.gosyer.data.models.Extension -import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.interactions.ExtensionInteractionHandler import ca.gosyer.data.translation.XmlResourceBundle import ca.gosyer.ui.base.vm.ViewModel @@ -26,10 +25,8 @@ import javax.inject.Inject class ExtensionsMenuViewModel @Inject constructor( private val extensionHandler: ExtensionInteractionHandler, private val resources: XmlResourceBundle, - serverPreferences: ServerPreferences, extensionPreferences: ExtensionPreferences ) : ViewModel() { - val serverUrl = serverPreferences.serverUrl().stateIn(scope) private val _enabledLangs = extensionPreferences.languages().asStateFlow() val enabledLangs = _enabledLangs.asStateFlow() diff --git a/src/main/kotlin/ca/gosyer/ui/library/LibraryScreen.kt b/src/main/kotlin/ca/gosyer/ui/library/LibraryScreen.kt index 1f9ba72b..a6c74af2 100644 --- a/src/main/kotlin/ca/gosyer/ui/library/LibraryScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/library/LibraryScreen.kt @@ -73,7 +73,6 @@ fun LibraryScreen(bundle: Bundle, onClickManga: (Long) -> Unit = { openMangaMenu val displayMode by vm.displayMode.collectAsState() val isLoading by vm.isLoading.collectAsState() val error by vm.error.collectAsState() - val serverUrl by vm.serverUrl.collectAsState() val query by vm.query.collectAsState() // val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden) @@ -116,7 +115,6 @@ fun LibraryScreen(bundle: Bundle, onClickManga: (Long) -> Unit = { openMangaMenu categories = categories, displayMode = displayMode, selectedPage = selectedCategoryIndex, - serverUrl = serverUrl, getLibraryForPage = { vm.getLibraryForCategoryIndex(it).collectAsState() }, onPageChanged = vm::setSelectedPage, onClickManga = onClickManga, @@ -163,7 +161,6 @@ private fun LibraryPager( categories: List, displayMode: DisplayMode, selectedPage: Int, - serverUrl: String, getLibraryForPage: @Composable (Int) -> State>, onPageChanged: (Int) -> Unit, onClickManga: (Long) -> Unit, @@ -187,7 +184,6 @@ private fun LibraryPager( when (displayMode) { DisplayMode.CompactGrid -> LibraryMangaCompactGrid( library = library, - serverUrl = serverUrl, onClickManga = onClickManga, onRemoveMangaClicked = onRemoveMangaClicked ) diff --git a/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt b/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt index 4798eb3d..3230df26 100644 --- a/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt @@ -9,7 +9,6 @@ package ca.gosyer.ui.library import ca.gosyer.data.library.LibraryPreferences import ca.gosyer.data.models.Category import ca.gosyer.data.models.Manga -import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.interactions.CategoryInteractionHandler import ca.gosyer.data.server.interactions.LibraryInteractionHandler import ca.gosyer.ui.base.vm.ViewModel @@ -73,11 +72,8 @@ class LibraryScreenViewModel @Inject constructor( private val bundle: Bundle, private val categoryHandler: CategoryInteractionHandler, private val libraryHandler: LibraryInteractionHandler, - libraryPreferences: LibraryPreferences, - serverPreferences: ServerPreferences, + libraryPreferences: LibraryPreferences ) : ViewModel() { - val serverUrl = serverPreferences.serverUrl().stateIn(scope) - private val library = Library(MutableStateFlow(emptyList()), mutableMapOf()) val categories = library.categories.asStateFlow() diff --git a/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt b/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt index d9d85ed9..f3df3fec 100644 --- a/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt +++ b/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt @@ -19,7 +19,6 @@ import androidx.compose.material.LocalTextStyle import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -27,19 +26,20 @@ import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import ca.gosyer.data.models.Manga -import ca.gosyer.ui.base.components.KtorImage +import ca.gosyer.ui.base.components.KamelImage import ca.gosyer.ui.base.components.contextMenuClickable +import io.kamel.image.lazyPainterResource @Composable fun LibraryMangaCompactGrid( library: List, - serverUrl: String, onClickManga: (Long) -> Unit = {}, onRemoveMangaClicked: (Long) -> Unit = {} ) { @@ -52,7 +52,6 @@ fun LibraryMangaCompactGrid( manga = manga, unread = null, // TODO downloaded = null, // TODO - serverUrl = serverUrl, onClick = { onClickManga(manga.id) } ) { listOf( @@ -68,11 +67,10 @@ private fun LibraryMangaCompactGridItem( manga: Manga, unread: Int?, downloaded: Int?, - serverUrl: String, onClick: () -> Unit = {}, contextMenuItems: () -> List = { emptyList() } ) { - val cover = remember(manga.id, serverUrl) { manga.cover(serverUrl) } + val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium) val fontStyle = LocalTextStyle.current.merge( TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp) ) @@ -87,9 +85,7 @@ private fun LibraryMangaCompactGridItem( items = contextMenuItems ) ) { - if (cover != null) { - KtorImage(cover, contentScale = ContentScale.Crop) - } + KamelImage(cover, manga.title, contentScale = ContentScale.Crop) Box(modifier = Modifier.fillMaxSize().then(shadowGradient)) Text( text = manga.title, diff --git a/src/main/kotlin/ca/gosyer/ui/main/main.kt b/src/main/kotlin/ca/gosyer/ui/main/main.kt index c5af705d..394526b2 100644 --- a/src/main/kotlin/ca/gosyer/ui/main/main.kt +++ b/src/main/kotlin/ca/gosyer/ui/main/main.kt @@ -48,6 +48,8 @@ import com.github.weisj.darklaf.theme.IntelliJTheme import com.github.zsoltk.compose.backpress.BackPressHandler import com.github.zsoltk.compose.backpress.LocalBackPressHandler import com.github.zsoltk.compose.savedinstancestate.Bundle +import io.kamel.core.config.KamelConfig +import io.kamel.image.config.LocalKamelConfig import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.MutableStateFlow @@ -94,6 +96,7 @@ suspend fun main() { } val resources = scope.getInstance() + val kamelConfig = scope.getInstance() // Set the Compose constants before any // Swing functions are called @@ -181,7 +184,8 @@ suspend fun main() { CompositionLocalProvider( LocalComposeWindow provides window, LocalBackPressHandler provides backPressHandler, - LocalResources provides resources + LocalResources provides resources, + LocalKamelConfig provides kamelConfig ) { Crossfade(serverService.initialized.collectAsState().value) { initialized -> when (initialized) { diff --git a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt index 2f49a82c..e8a9db90 100644 --- a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt @@ -40,6 +40,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -50,7 +51,7 @@ import ca.gosyer.data.models.Manga import ca.gosyer.ui.base.WindowDialog import ca.gosyer.ui.base.components.ActionIcon import ca.gosyer.ui.base.components.ErrorScreen -import ca.gosyer.ui.base.components.KtorImage +import ca.gosyer.ui.base.components.KamelImage import ca.gosyer.ui.base.components.LoadingScreen import ca.gosyer.ui.base.components.LocalMenuController import ca.gosyer.ui.base.components.MenuController @@ -61,6 +62,7 @@ import ca.gosyer.ui.reader.openReaderMenu import ca.gosyer.util.compose.ThemedWindow import ca.gosyer.util.lang.launchApplication import com.google.accompanist.flowlayout.FlowRow +import io.kamel.image.lazyPainterResource import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collect @@ -84,7 +86,6 @@ fun MangaMenu(mangaId: Long, menuController: MenuController? = LocalMenuControll val manga by vm.manga.collectAsState() val chapters by vm.chapters.collectAsState() val isLoading by vm.isLoading.collectAsState() - val serverUrl by vm.serverUrl.collectAsState() val dateTimeFormatter by vm.dateTimeFormatter.collectAsState() val categoriesExist by vm.categoriesExist.collectAsState() @@ -128,7 +129,7 @@ fun MangaMenu(mangaId: Long, menuController: MenuController? = LocalMenuControll val state = rememberLazyListState() LazyColumn(state = state) { item { - MangaItem(manga, serverUrl) + MangaItem(manga) } if (chapters.isNotEmpty()) { items(chapters) { chapter -> @@ -171,17 +172,17 @@ fun MangaMenu(mangaId: Long, menuController: MenuController? = LocalMenuControll } @Composable -fun MangaItem(manga: Manga, serverUrl: String) { +fun MangaItem(manga: Manga) { BoxWithConstraints(Modifier.padding(8.dp)) { if (maxWidth > 600.dp) { Row { - Cover(manga, serverUrl, Modifier.width(300.dp)) + Cover(manga, Modifier.width(300.dp)) Spacer(Modifier.width(16.dp)) MangaInfo(manga) } } else { Column { - Cover(manga, serverUrl, Modifier.align(Alignment.CenterHorizontally)) + Cover(manga, Modifier.align(Alignment.CenterHorizontally)) Spacer(Modifier.height(16.dp)) MangaInfo(manga) } @@ -190,17 +191,17 @@ fun MangaItem(manga: Manga, serverUrl: String) { } @Composable -private fun Cover(manga: Manga, serverUrl: String, modifier: Modifier = Modifier) { +private fun Cover(manga: Manga, modifier: Modifier = Modifier) { Surface( modifier = modifier then Modifier .padding(4.dp), shape = RoundedCornerShape(4.dp) ) { - Box(modifier = Modifier.fillMaxSize()) { - manga.cover(serverUrl)?.let { - KtorImage(it) - } - } + KamelImage( + lazyPainterResource(manga, filterQuality = FilterQuality.Medium), + manga.title, + Modifier.fillMaxSize() + ) } } diff --git a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt index 83e2c51d..9e1c6425 100644 --- a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt @@ -10,7 +10,6 @@ import ca.gosyer.data.download.DownloadService import ca.gosyer.data.models.Category import ca.gosyer.data.models.Chapter import ca.gosyer.data.models.Manga -import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.interactions.CategoryInteractionHandler import ca.gosyer.data.server.interactions.ChapterInteractionHandler import ca.gosyer.data.server.interactions.LibraryInteractionHandler @@ -41,11 +40,8 @@ class MangaMenuViewModel @Inject constructor( private val categoryHandler: CategoryInteractionHandler, private val libraryHandler: LibraryInteractionHandler, private val downloadService: DownloadService, - serverPreferences: ServerPreferences, uiPreferences: UiPreferences, ) : ViewModel() { - val serverUrl = serverPreferences.serverUrl().stateIn(scope) - private val downloadingChapters = downloadService.registerWatch(params.mangaId) private val _manga = MutableStateFlow(null) diff --git a/src/main/kotlin/ca/gosyer/ui/reader/ReaderMenu.kt b/src/main/kotlin/ca/gosyer/ui/reader/ReaderMenu.kt index 5fc6789e..b78ee1c3 100644 --- a/src/main/kotlin/ca/gosyer/ui/reader/ReaderMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/reader/ReaderMenu.kt @@ -66,6 +66,8 @@ import ca.gosyer.ui.reader.navigation.navigationClickable import ca.gosyer.ui.reader.viewer.ContinuousReader import ca.gosyer.ui.reader.viewer.PagerReader import ca.gosyer.util.lang.launchApplication +import io.kamel.core.config.KamelConfig +import io.kamel.image.config.LocalKamelConfig import kotlinx.coroutines.DelicateCoroutinesApi @OptIn(DelicateCoroutinesApi::class) @@ -79,6 +81,7 @@ fun openReaderMenu(chapterIndex: Int, mangaId: Long) { ) = windowSettings.get().get() val resources = AppScope.getInstance() + val kamelConfig = AppScope.getInstance() launchApplication { var shortcuts by remember { @@ -110,7 +113,8 @@ fun openReaderMenu(chapterIndex: Int, mangaId: Long) { setIcon() CompositionLocalProvider( LocalComposeWindow provides window, - LocalResources provides resources + LocalResources provides resources, + LocalKamelConfig provides kamelConfig ) { AppTheme { ReaderMenu(chapterIndex, mangaId) { shortcuts = it } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt index ce900c57..52c51c7c 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt @@ -35,11 +35,12 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import ca.gosyer.build.BuildConfig import ca.gosyer.ui.base.components.ActionIcon -import ca.gosyer.ui.base.components.KtorImage +import ca.gosyer.ui.base.components.KamelImage import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.components.combinedMouseClickable import ca.gosyer.ui.base.resources.stringResource @@ -54,6 +55,7 @@ import ca.gosyer.util.lang.launchApplication import com.github.zsoltk.compose.savedinstancestate.Bundle import com.github.zsoltk.compose.savedinstancestate.BundleScope import com.github.zsoltk.compose.savedinstancestate.LocalSavedInstanceState +import io.kamel.image.lazyPainterResource import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow @@ -91,7 +93,6 @@ fun SourcesMenu(bundle: Bundle, onSourceSettingsClick: (Long) -> Unit, onMangaCl val selectedSourceTab by vm.selectedSourceTab.collectAsState() val sourceSearchEnabled by vm.sourceSearchEnabled.collectAsState() val sourceSearchQuery by vm.sourceSearchQuery.collectAsState() - val serverUrl by vm.serverUrl.collectAsState() Column { Toolbar( selectedSourceTab?.name ?: stringResource("location_sources"), @@ -165,7 +166,13 @@ fun SourcesMenu(bundle: Bundle, onSourceSettingsClick: (Long) -> Unit, onMangaCl .requiredSize(50.dp) .align(Alignment.Center) if (source != null) { - KtorImage(source.iconUrl(serverUrl), modifier = modifier) + Box(Modifier.align(Alignment.Center)) { + KamelImage( + lazyPainterResource(source, filterQuality = FilterQuality.Medium), + source.displayName, + modifier + ) + } } else { Icon(Icons.Rounded.Home, stringResource("sources_home"), modifier = modifier) } @@ -180,7 +187,7 @@ fun SourcesMenu(bundle: Bundle, onSourceSettingsClick: (Long) -> Unit, onMangaCl if (selectedSource != null) { SourceScreen(it, selectedSource, onMangaClick, vm::enableSearch, vm::setSearch) } else { - SourceHomeScreen(isLoading, sources, serverUrl, vm::addTab) + SourceHomeScreen(isLoading, sources, vm::addTab) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt index ea2f2a51..191d169e 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt @@ -8,7 +8,6 @@ package ca.gosyer.ui.sources import ca.gosyer.data.catalog.CatalogPreferences import ca.gosyer.data.models.Source -import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.interactions.SourceInteractionHandler import ca.gosyer.ui.base.vm.ViewModel import ca.gosyer.util.lang.throwIfCancellation @@ -25,11 +24,8 @@ import javax.inject.Inject class SourcesMenuViewModel @Inject constructor( private val bundle: Bundle, private val sourceHandler: SourceInteractionHandler, - serverPreferences: ServerPreferences, catalogPreferences: CatalogPreferences ) : ViewModel() { - val serverUrl = serverPreferences.serverUrl().stateIn(scope) - private val _languages = catalogPreferences.languages().asStateFlow() val languages = _languages.asStateFlow() diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt index 82f95b0c..4f67ed39 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt @@ -33,17 +33,18 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import ca.gosyer.data.models.Source -import ca.gosyer.ui.base.components.KtorImage +import ca.gosyer.ui.base.components.KamelImage import ca.gosyer.ui.base.components.LoadingScreen +import io.kamel.image.lazyPainterResource @Composable fun SourceHomeScreen( isLoading: Boolean, sources: List, - serverUrl: String, onSourceClicked: (Source) -> Unit ) { if (sources.isEmpty()) { @@ -51,7 +52,7 @@ fun SourceHomeScreen( } else { Box(Modifier.fillMaxSize(), Alignment.TopCenter) { val state = rememberLazyListState() - SourceCategory(sources, serverUrl, onSourceClicked, state) + SourceCategory(sources, onSourceClicked, state) /*val sourcesByLang = sources.groupBy { it.lang.toLowerCase() }.toList() LazyColumn(state = state) { items(sourcesByLang) { (lang, sources) -> @@ -75,7 +76,6 @@ fun SourceHomeScreen( @Composable fun SourceCategory( sources: List, - serverUrl: String, onSourceClicked: (Source) -> Unit, state: LazyListState ) { @@ -83,7 +83,6 @@ fun SourceCategory( items(sources) { source -> SourceItem( source, - serverUrl, onSourceClicked = onSourceClicked ) Spacer(Modifier.height(8.dp)) @@ -94,7 +93,6 @@ fun SourceCategory( @Composable fun SourceItem( source: Source, - serverUrl: String, onSourceClicked: (Source) -> Unit ) { TooltipArea( @@ -117,7 +115,7 @@ fun SourceItem( }, horizontalAlignment = Alignment.CenterHorizontally ) { - KtorImage(source.iconUrl(serverUrl), Modifier.size(96.dp)) + KamelImage(lazyPainterResource(source, filterQuality = FilterQuality.Medium), source.displayName, Modifier.size(96.dp)) Spacer(Modifier.height(4.dp)) Text( "${source.name} (${source.lang.uppercase()})", diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt index 0045cd46..48542bbf 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.unit.dp import ca.gosyer.data.models.Manga import ca.gosyer.data.models.Source @@ -30,6 +31,7 @@ import ca.gosyer.ui.base.resources.stringResource import ca.gosyer.ui.base.vm.viewModel import ca.gosyer.util.compose.persistentLazyListState import com.github.zsoltk.compose.savedinstancestate.Bundle +import io.kamel.image.lazyPainterResource @Composable fun SourceScreen( @@ -46,7 +48,6 @@ fun SourceScreen( val hasNextPage by vm.hasNextPage.collectAsState() val loading by vm.loading.collectAsState() val isLatest by vm.isLatest.collectAsState() - val serverUrl by vm.serverUrl.collectAsState() LaunchedEffect(Unit) { setSearch(vm::search) @@ -67,7 +68,6 @@ fun SourceScreen( hasNextPage, source.supportsLatest, isLatest, - serverUrl, onLoadNextPage = vm::loadNextPage, onMangaClick = onMangaClick, onClickMode = vm::setMode @@ -82,7 +82,6 @@ private fun MangaTable( hasNextPage: Boolean = false, supportsLatest: Boolean, isLatest: Boolean, - serverUrl: String, onLoadNextPage: () -> Unit, onMangaClick: (Long) -> Unit, onClickMode: (Boolean) -> Unit @@ -111,7 +110,7 @@ private fun MangaTable( } MangaGridItem( title = manga.title, - cover = manga.cover(serverUrl), + cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium), onClick = { onMangaClick(manga.id) } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt index 14659d41..bd03bf55 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt @@ -9,7 +9,6 @@ package ca.gosyer.ui.sources.components import ca.gosyer.data.models.Manga import ca.gosyer.data.models.MangaPage import ca.gosyer.data.models.Source -import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.interactions.SourceInteractionHandler import ca.gosyer.ui.base.vm.ViewModel import ca.gosyer.util.compose.saveBooleanInBundle @@ -26,21 +25,17 @@ import javax.inject.Inject class SourceScreenViewModel( private val source: Source, private val bundle: Bundle, - private val sourceHandler: SourceInteractionHandler, - serverPreferences: ServerPreferences + private val sourceHandler: SourceInteractionHandler ) : ViewModel() { @Inject constructor( params: Params, - sourceHandler: SourceInteractionHandler, - serverPreferences: ServerPreferences + sourceHandler: SourceInteractionHandler ) : this( params.source, params.bundle, - sourceHandler, - serverPreferences + sourceHandler ) - val serverUrl = serverPreferences.serverUrl().stateIn(scope) private val _mangas = saveObjectInBundle(scope, bundle, MANGAS_KEY) { emptyList() } val mangas = _mangas.asStateFlow() diff --git a/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt b/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt index 70c2f6f9..5bdea255 100644 --- a/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.FilterQuality import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import ca.gosyer.data.models.Chapter @@ -37,6 +38,7 @@ import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.components.mangaAspectRatio import ca.gosyer.ui.base.resources.stringResource import ca.gosyer.ui.base.vm.viewModel +import io.kamel.image.lazyPainterResource @Composable fun UpdatesMenu( @@ -44,7 +46,6 @@ fun UpdatesMenu( openManga: (Long) -> Unit ) { val vm = viewModel() - val serverUrl by vm.serverUrl.collectAsState() val isLoading by vm.isLoading.collectAsState() val updates by vm.updates.collectAsState() Column { @@ -57,7 +58,6 @@ fun UpdatesMenu( val manga = it.manga!! val chapter = it.chapter UpdatesItem( - serverUrl, it, onClickItem = { openChapter(chapter.index, chapter.mangaId) }, onClickCover = { openManga(manga.id) }, @@ -73,7 +73,6 @@ fun UpdatesMenu( @Composable fun UpdatesItem( - serverUrl: String, chapterDownloadItem: ChapterDownloadItem, onClickItem: () -> Unit, onClickCover: () -> Unit, @@ -101,7 +100,8 @@ fun UpdatesItem( .padding(start = 16.dp, top = 8.dp, bottom = 8.dp) .clip(MaterialTheme.shapes.medium) .clickable { onClickCover() }, - imageUrl = manga.cover(serverUrl) + cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium), + contentDescription = manga.title ) MangaListItemColumn( modifier = Modifier diff --git a/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenuViewModel.kt index c73e4ec4..edfe1e88 100644 --- a/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenuViewModel.kt @@ -8,11 +8,9 @@ package ca.gosyer.ui.updates import ca.gosyer.data.download.DownloadService import ca.gosyer.data.models.Chapter -import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.interactions.ChapterInteractionHandler import ca.gosyer.data.server.interactions.UpdatesInteractionHandler import ca.gosyer.ui.base.components.ChapterDownloadItem -import ca.gosyer.ui.base.prefs.asStateIn import ca.gosyer.ui.base.vm.ViewModel import ca.gosyer.util.lang.throwIfCancellation import kotlinx.coroutines.flow.MutableStateFlow @@ -26,10 +24,8 @@ import javax.inject.Inject class UpdatesMenuViewModel @Inject constructor( private val chapterHandler: ChapterInteractionHandler, private val updatesHandler: UpdatesInteractionHandler, - private val serverPreferences: ServerPreferences, private val downloadService: DownloadService ) : ViewModel() { - val serverUrl = serverPreferences.serverUrl().asStateIn(scope).asStateFlow() private val _isLoading = MutableStateFlow(true) val isLoading = _isLoading.asStateFlow()