mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Switch from Kamel to Compose-ImageLoader
This commit is contained in:
@@ -27,6 +27,7 @@ dependencies {
|
|||||||
implementation(libs.accompanist.pagerIndicators)
|
implementation(libs.accompanist.pagerIndicators)
|
||||||
implementation(libs.accompanist.flowLayout)
|
implementation(libs.accompanist.flowLayout)
|
||||||
implementation(libs.kamel)
|
implementation(libs.kamel)
|
||||||
|
implementation(libs.imageloader)
|
||||||
implementation(libs.materialDialogs.core)
|
implementation(libs.materialDialogs.core)
|
||||||
|
|
||||||
// Android
|
// Android
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ dependencies {
|
|||||||
implementation(libs.accompanist.pagerIndicators)
|
implementation(libs.accompanist.pagerIndicators)
|
||||||
implementation(libs.accompanist.flowLayout)
|
implementation(libs.accompanist.flowLayout)
|
||||||
implementation(libs.kamel)
|
implementation(libs.kamel)
|
||||||
|
implementation(libs.imageloader)
|
||||||
implementation(libs.materialDialogs.core)
|
implementation(libs.materialDialogs.core)
|
||||||
|
|
||||||
// UI (Swing)
|
// UI (Swing)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ composeAndroid = "1.2.1"
|
|||||||
voyager = "1.0.0-beta16"
|
voyager = "1.0.0-beta16"
|
||||||
accompanist = "0.25.1"
|
accompanist = "0.25.1"
|
||||||
kamel = "0.4.1"
|
kamel = "0.4.1"
|
||||||
|
imageloader = "1.1.3"
|
||||||
materialDialogs = "0.8.0"
|
materialDialogs = "0.8.0"
|
||||||
|
|
||||||
# Android
|
# Android
|
||||||
@@ -101,6 +102,7 @@ accompanist-pager = { module = "ca.gosyer:accompanist-pager", version.ref = "acc
|
|||||||
accompanist-pagerIndicators = { module = "ca.gosyer:accompanist-pager-indicators", version.ref = "accompanist" }
|
accompanist-pagerIndicators = { module = "ca.gosyer:accompanist-pager-indicators", version.ref = "accompanist" }
|
||||||
accompanist-flowLayout = { module = "ca.gosyer:accompanist-flowlayout", version.ref = "accompanist" }
|
accompanist-flowLayout = { module = "ca.gosyer:accompanist-flowlayout", version.ref = "accompanist" }
|
||||||
kamel = { module = "com.alialbaali.kamel:kamel-image", version.ref = "kamel" }
|
kamel = { module = "com.alialbaali.kamel:kamel-image", version.ref = "kamel" }
|
||||||
|
imageloader = { module = "io.github.qdsfdhvh:image-loader", version.ref = "imageloader" }
|
||||||
materialDialogs-core = { module = "ca.gosyer:compose-material-dialogs-core", version.ref = "materialDialogs" }
|
materialDialogs-core = { module = "ca.gosyer:compose-material-dialogs-core", version.ref = "materialDialogs" }
|
||||||
|
|
||||||
# Android
|
# Android
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ kotlin {
|
|||||||
api(kotlin("stdlib-common"))
|
api(kotlin("stdlib-common"))
|
||||||
api(libs.coroutines.core)
|
api(libs.coroutines.core)
|
||||||
api(libs.kamel)
|
api(libs.kamel)
|
||||||
|
api(libs.imageloader)
|
||||||
api(libs.voyager.core)
|
api(libs.voyager.core)
|
||||||
api(libs.voyager.navigation)
|
api(libs.voyager.navigation)
|
||||||
api(libs.voyager.transitions)
|
api(libs.voyager.transitions)
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.image
|
||||||
|
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import com.seiko.imageloader.ImageLoaderBuilder
|
||||||
|
import com.seiko.imageloader.cache.disk.DiskCache
|
||||||
|
import com.seiko.imageloader.cache.disk.DiskCacheBuilder
|
||||||
|
import com.seiko.imageloader.cache.memory.MemoryCache
|
||||||
|
import com.seiko.imageloader.cache.memory.MemoryCacheBuilder
|
||||||
|
import okio.Path.Companion.toOkioPath
|
||||||
|
|
||||||
|
actual fun imageLoaderBuilder(contextWrapper: ContextWrapper): ImageLoaderBuilder {
|
||||||
|
return ImageLoaderBuilder(contextWrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun diskCache(contextWrapper: ContextWrapper): DiskCache {
|
||||||
|
return DiskCacheBuilder()
|
||||||
|
.directory(contextWrapper.cacheDir.toOkioPath() / "image_cache")
|
||||||
|
.maxSizeBytes(1024 * 1024 * 150) // 150 MB
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun memoryCache(contextWrapper: ContextWrapper): MemoryCache {
|
||||||
|
return MemoryCacheBuilder(contextWrapper)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
@@ -10,8 +10,11 @@ import androidx.compose.runtime.ProvidedValue
|
|||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import ca.gosyer.jui.core.di.AppScope
|
import ca.gosyer.jui.core.di.AppScope
|
||||||
import ca.gosyer.jui.ui.ViewModelComponent
|
import ca.gosyer.jui.ui.ViewModelComponent
|
||||||
|
import ca.gosyer.jui.ui.base.image.ImageLoaderProvider
|
||||||
import ca.gosyer.jui.ui.base.image.KamelConfigProvider
|
import ca.gosyer.jui.ui.base.image.KamelConfigProvider
|
||||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import com.seiko.imageloader.ImageLoader
|
||||||
|
import com.seiko.imageloader.LocalImageLoader
|
||||||
import io.kamel.core.config.KamelConfig
|
import io.kamel.core.config.KamelConfig
|
||||||
import io.kamel.core.config.KamelConfigBuilder
|
import io.kamel.core.config.KamelConfigBuilder
|
||||||
import io.kamel.image.config.LocalKamelConfig
|
import io.kamel.image.config.LocalKamelConfig
|
||||||
@@ -22,6 +25,8 @@ interface UiComponent {
|
|||||||
|
|
||||||
val kamelConfig: KamelConfig
|
val kamelConfig: KamelConfig
|
||||||
|
|
||||||
|
val imageLoader: ImageLoader
|
||||||
|
|
||||||
val contextWrapper: ContextWrapper
|
val contextWrapper: ContextWrapper
|
||||||
|
|
||||||
val hooks: Array<ProvidedValue<out Any>>
|
val hooks: Array<ProvidedValue<out Any>>
|
||||||
@@ -30,10 +35,15 @@ interface UiComponent {
|
|||||||
@Provides
|
@Provides
|
||||||
fun kamelConfigFactory(contextWrapper: ContextWrapper): KamelConfig = kamelConfigProvider.get { kamelPlatformHandler(contextWrapper) }
|
fun kamelConfigFactory(contextWrapper: ContextWrapper): KamelConfig = kamelConfigProvider.get { kamelPlatformHandler(contextWrapper) }
|
||||||
|
|
||||||
|
@AppScope
|
||||||
|
@Provides
|
||||||
|
fun imageLoaderFactory(imageLoaderProvider: ImageLoaderProvider): ImageLoader = imageLoaderProvider.get()
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun getHooks(viewModelComponent: ViewModelComponent) = arrayOf(
|
fun getHooks(viewModelComponent: ViewModelComponent) = arrayOf(
|
||||||
LocalViewModels provides viewModelComponent,
|
LocalViewModels provides viewModelComponent,
|
||||||
LocalKamelConfig provides kamelConfig
|
LocalKamelConfig provides kamelConfig,
|
||||||
|
LocalImageLoader provides imageLoader
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.image
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.extension.model.Extension
|
||||||
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
|
import ca.gosyer.jui.domain.server.Http
|
||||||
|
import ca.gosyer.jui.domain.server.service.ServerPreferences
|
||||||
|
import ca.gosyer.jui.domain.source.model.Source
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import com.seiko.imageloader.ImageLoader
|
||||||
|
import com.seiko.imageloader.ImageLoaderBuilder
|
||||||
|
import com.seiko.imageloader.cache.disk.DiskCache
|
||||||
|
import com.seiko.imageloader.cache.memory.MemoryCache
|
||||||
|
import com.seiko.imageloader.component.mapper.Mapper
|
||||||
|
import com.seiko.imageloader.request.Options
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
|
class ImageLoaderProvider @Inject constructor(
|
||||||
|
private val http: Http,
|
||||||
|
serverPreferences: ServerPreferences,
|
||||||
|
private val context: ContextWrapper
|
||||||
|
) {
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
|
val serverUrl = serverPreferences.serverUrl().stateIn(GlobalScope)
|
||||||
|
|
||||||
|
fun get(): ImageLoader {
|
||||||
|
return imageLoaderBuilder(context).apply {
|
||||||
|
httpClient { http }
|
||||||
|
components {
|
||||||
|
add(MangaCoverMapper())
|
||||||
|
add(ExtensionIconMapper())
|
||||||
|
add(SourceIconMapper())
|
||||||
|
}
|
||||||
|
options(
|
||||||
|
Options(
|
||||||
|
config = Options.ImageConfig.HARDWARE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
diskCache {
|
||||||
|
diskCache(context)
|
||||||
|
}
|
||||||
|
memoryCache {
|
||||||
|
memoryCache(context)
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class MangaCoverMapper : Mapper<String> {
|
||||||
|
override fun map(data: Any, options: Options): String? {
|
||||||
|
if (data !is Manga) return null
|
||||||
|
if (data.thumbnailUrl.isNullOrBlank()) return null
|
||||||
|
return serverUrl.value.toString() + data.thumbnailUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ExtensionIconMapper : Mapper<String> {
|
||||||
|
override fun map(data: Any, options: Options): String? {
|
||||||
|
if (data !is Extension) return null
|
||||||
|
if (data.iconUrl.isBlank()) return null
|
||||||
|
return serverUrl.value.toString() + data.iconUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class SourceIconMapper : Mapper<String> {
|
||||||
|
override fun map(data: Any, options: Options): String? {
|
||||||
|
if (data !is Source) return null
|
||||||
|
if (data.iconUrl.isBlank()) return null
|
||||||
|
return serverUrl.value.toString() + data.iconUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect fun imageLoaderBuilder(contextWrapper: ContextWrapper): ImageLoaderBuilder
|
||||||
|
|
||||||
|
expect fun diskCache(contextWrapper: ContextWrapper): DiskCache
|
||||||
|
|
||||||
|
expect fun memoryCache(contextWrapper: ContextWrapper): MemoryCache
|
||||||
@@ -37,7 +37,6 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
@@ -58,7 +57,6 @@ import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
|||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DownloadsScreenContent(
|
fun DownloadsScreenContent(
|
||||||
@@ -128,7 +126,7 @@ fun DownloadsItem(
|
|||||||
.padding(start = 16.dp, top = 8.dp, bottom = 8.dp)
|
.padding(start = 16.dp, top = 8.dp, bottom = 8.dp)
|
||||||
.clip(MaterialTheme.shapes.medium)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
.clickable { onClickCover() },
|
.clickable { onClickCover() },
|
||||||
cover = lazyPainterResource(item.manga, filterQuality = FilterQuality.Medium),
|
data = item.manga,
|
||||||
contentDescription = item.manga.title
|
contentDescription = item.manga.title
|
||||||
)
|
)
|
||||||
MangaListItemColumn(
|
MangaListItemColumn(
|
||||||
|
|||||||
@@ -54,14 +54,13 @@ import ca.gosyer.jui.uicore.components.LoadingScreen
|
|||||||
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
import com.vanpra.composematerialdialogs.MaterialDialog
|
import com.vanpra.composematerialdialogs.MaterialDialog
|
||||||
import com.vanpra.composematerialdialogs.MaterialDialogState
|
import com.vanpra.composematerialdialogs.MaterialDialogState
|
||||||
import com.vanpra.composematerialdialogs.listItemsMultiChoice
|
import com.vanpra.composematerialdialogs.listItemsMultiChoice
|
||||||
import com.vanpra.composematerialdialogs.rememberMaterialDialogState
|
import com.vanpra.composematerialdialogs.rememberMaterialDialogState
|
||||||
import com.vanpra.composematerialdialogs.title
|
import com.vanpra.composematerialdialogs.title
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ExtensionsScreenContent(
|
fun ExtensionsScreenContent(
|
||||||
@@ -153,7 +152,12 @@ fun ExtensionItem(
|
|||||||
Box(modifier = Modifier.fillMaxWidth().padding(end = 12.dp).height(50.dp).background(MaterialTheme.colors.background)) {
|
Box(modifier = Modifier.fillMaxWidth().padding(end = 12.dp).height(50.dp).background(MaterialTheme.colors.background)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Spacer(Modifier.width(4.dp))
|
Spacer(Modifier.width(4.dp))
|
||||||
KamelImage(lazyPainterResource(extension, filterQuality = FilterQuality.Medium), extension.name, Modifier.size(50.dp))
|
ImageLoaderImage(
|
||||||
|
data = extension,
|
||||||
|
contentDescription = extension.name,
|
||||||
|
modifier = Modifier.size(50.dp),
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
|
)
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Column {
|
Column {
|
||||||
val title = buildAnnotatedString {
|
val title = buildAnnotatedString {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import ca.gosyer.jui.uicore.components.MangaListItem
|
import ca.gosyer.jui.uicore.components.MangaListItem
|
||||||
@@ -31,7 +30,6 @@ import ca.gosyer.jui.uicore.components.MangaListItemTitle
|
|||||||
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryMangaList(
|
fun LibraryMangaList(
|
||||||
@@ -81,7 +79,6 @@ private fun LibraryMangaListItem(
|
|||||||
showLanguage: Boolean,
|
showLanguage: Boolean,
|
||||||
showLocal: Boolean
|
showLocal: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
MangaListItem(
|
MangaListItem(
|
||||||
modifier = modifier then Modifier
|
modifier = modifier then Modifier
|
||||||
.requiredHeight(56.dp)
|
.requiredHeight(56.dp)
|
||||||
@@ -91,7 +88,7 @@ private fun LibraryMangaListItem(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(40.dp)
|
||||||
.clip(MaterialTheme.shapes.medium),
|
.clip(MaterialTheme.shapes.medium),
|
||||||
cover = cover,
|
data = manga,
|
||||||
contentDescription = manga.title
|
contentDescription = manga.title
|
||||||
)
|
)
|
||||||
MangaListItemTitle(
|
MangaListItemTitle(
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
|||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryMangaComfortableGrid(
|
fun LibraryMangaComfortableGrid(
|
||||||
@@ -94,7 +93,6 @@ private fun LibraryMangaComfortableGridItem(
|
|||||||
showLanguage: Boolean,
|
showLanguage: Boolean,
|
||||||
showLocal: Boolean
|
showLocal: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
val fontStyle = LocalTextStyle.current.merge(
|
val fontStyle = LocalTextStyle.current.merge(
|
||||||
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
||||||
)
|
)
|
||||||
@@ -106,14 +104,15 @@ private fun LibraryMangaComfortableGridItem(
|
|||||||
.clip(MaterialTheme.shapes.medium) then modifier
|
.clip(MaterialTheme.shapes.medium) then modifier
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
manga,
|
||||||
contentDescription = manga.title,
|
contentDescription = manga.title,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.aspectRatio(mangaAspectRatio)
|
.aspectRatio(mangaAspectRatio)
|
||||||
.clip(MaterialTheme.shapes.medium),
|
.clip(MaterialTheme.shapes.medium),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = manga.title,
|
text = manga.title,
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
|||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
expect fun Modifier.libraryMangaModifier(
|
expect fun Modifier.libraryMangaModifier(
|
||||||
onClickManga: () -> Unit,
|
onClickManga: () -> Unit,
|
||||||
@@ -102,7 +101,6 @@ private fun LibraryMangaCompactGridItem(
|
|||||||
showLanguage: Boolean,
|
showLanguage: Boolean,
|
||||||
showLocal: Boolean
|
showLocal: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
val fontStyle = LocalTextStyle.current.merge(
|
val fontStyle = LocalTextStyle.current.merge(
|
||||||
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
||||||
)
|
)
|
||||||
@@ -113,11 +111,12 @@ private fun LibraryMangaCompactGridItem(
|
|||||||
.aspectRatio(mangaAspectRatio)
|
.aspectRatio(mangaAspectRatio)
|
||||||
.clip(MaterialTheme.shapes.medium) then modifier
|
.clip(MaterialTheme.shapes.medium) then modifier
|
||||||
) {
|
) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
manga,
|
||||||
manga.title,
|
manga.title,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
Box(modifier = Modifier.fillMaxSize() then shadowGradient)
|
Box(modifier = Modifier.fillMaxSize() then shadowGradient)
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
|||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryMangaCoverOnlyGrid(
|
fun LibraryMangaCoverOnlyGrid(
|
||||||
@@ -88,19 +87,18 @@ private fun LibraryMangaCoverOnlyGridItem(
|
|||||||
showLanguage: Boolean,
|
showLanguage: Boolean,
|
||||||
showLocal: Boolean
|
showLocal: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(4.dp)
|
modifier = Modifier.padding(4.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.aspectRatio(mangaAspectRatio)
|
.aspectRatio(mangaAspectRatio)
|
||||||
.clip(MaterialTheme.shapes.medium) then modifier
|
.clip(MaterialTheme.shapes.medium) then modifier
|
||||||
) {
|
) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
manga,
|
||||||
contentDescription = manga.title,
|
contentDescription = manga.title,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
LibraryMangaBadges(
|
LibraryMangaBadges(
|
||||||
modifier = Modifier.padding(4.dp),
|
modifier = Modifier.padding(4.dp),
|
||||||
|
|||||||
@@ -41,14 +41,13 @@ import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
|||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
import com.google.accompanist.flowlayout.FlowRow
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
import com.vanpra.composematerialdialogs.MaterialDialog
|
import com.vanpra.composematerialdialogs.MaterialDialog
|
||||||
import com.vanpra.composematerialdialogs.MaterialDialogState
|
import com.vanpra.composematerialdialogs.MaterialDialogState
|
||||||
import com.vanpra.composematerialdialogs.listItemsMultiChoice
|
import com.vanpra.composematerialdialogs.listItemsMultiChoice
|
||||||
import com.vanpra.composematerialdialogs.title
|
import com.vanpra.composematerialdialogs.title
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaItem(manga: Manga) {
|
fun MangaItem(manga: Manga) {
|
||||||
@@ -74,15 +73,16 @@ fun MangaItem(manga: Manga) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Cover(manga: Manga, modifier: Modifier = Modifier) {
|
private fun Cover(manga: Manga, modifier: Modifier = Modifier) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
resource = lazyPainterResource(manga, filterQuality = FilterQuality.Medium),
|
data = manga,
|
||||||
contentDescription = manga.title,
|
contentDescription = manga.title,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
errorModifier = modifier then Modifier
|
errorModifier = modifier then Modifier
|
||||||
.aspectRatio(
|
.aspectRatio(
|
||||||
ratio = mangaAspectRatio,
|
ratio = mangaAspectRatio,
|
||||||
matchHeightConstraintsFirst = true
|
matchHeightConstraintsFirst = true
|
||||||
)
|
),
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
|||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourceMangaComfortableGrid(
|
fun SourceMangaComfortableGrid(
|
||||||
@@ -89,7 +88,6 @@ private fun SourceMangaComfortableGridItem(
|
|||||||
manga: Manga,
|
manga: Manga,
|
||||||
inLibrary: Boolean
|
inLibrary: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
val fontStyle = LocalTextStyle.current.merge(
|
val fontStyle = LocalTextStyle.current.merge(
|
||||||
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
||||||
)
|
)
|
||||||
@@ -101,14 +99,15 @@ private fun SourceMangaComfortableGridItem(
|
|||||||
.clip(MaterialTheme.shapes.medium) then modifier
|
.clip(MaterialTheme.shapes.medium) then modifier
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
manga,
|
||||||
contentDescription = manga.title,
|
contentDescription = manga.title,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.aspectRatio(mangaAspectRatio)
|
.aspectRatio(mangaAspectRatio)
|
||||||
.clip(MaterialTheme.shapes.medium),
|
.clip(MaterialTheme.shapes.medium),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = manga.title,
|
text = manga.title,
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
|||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourceMangaCompactGrid(
|
fun SourceMangaCompactGrid(
|
||||||
@@ -92,7 +91,6 @@ private fun SourceMangaCompactGridItem(
|
|||||||
manga: Manga,
|
manga: Manga,
|
||||||
inLibrary: Boolean
|
inLibrary: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
val fontStyle = LocalTextStyle.current.merge(
|
val fontStyle = LocalTextStyle.current.merge(
|
||||||
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
||||||
)
|
)
|
||||||
@@ -103,11 +101,12 @@ private fun SourceMangaCompactGridItem(
|
|||||||
.aspectRatio(mangaAspectRatio)
|
.aspectRatio(mangaAspectRatio)
|
||||||
.clip(MaterialTheme.shapes.medium) then modifier
|
.clip(MaterialTheme.shapes.medium) then modifier
|
||||||
) {
|
) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
manga,
|
||||||
manga.title,
|
manga.title,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
Box(modifier = Modifier.fillMaxSize().then(shadowGradient))
|
Box(modifier = Modifier.fillMaxSize().then(shadowGradient))
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import ca.gosyer.jui.uicore.components.MangaListItem
|
import ca.gosyer.jui.uicore.components.MangaListItem
|
||||||
@@ -31,7 +30,6 @@ import ca.gosyer.jui.uicore.components.MangaListItemTitle
|
|||||||
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourceMangaList(
|
fun SourceMangaList(
|
||||||
@@ -74,7 +72,6 @@ private fun MangaListItem(
|
|||||||
manga: Manga,
|
manga: Manga,
|
||||||
inLibrary: Boolean
|
inLibrary: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
MangaListItem(
|
MangaListItem(
|
||||||
modifier = modifier then Modifier
|
modifier = modifier then Modifier
|
||||||
.requiredHeight(56.dp)
|
.requiredHeight(56.dp)
|
||||||
@@ -84,7 +81,7 @@ private fun MangaListItem(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(40.dp)
|
||||||
.clip(MaterialTheme.shapes.medium),
|
.clip(MaterialTheme.shapes.medium),
|
||||||
cover = cover,
|
data = manga,
|
||||||
contentDescription = manga.title
|
contentDescription = manga.title
|
||||||
)
|
)
|
||||||
MangaListItemTitle(
|
MangaListItemTitle(
|
||||||
|
|||||||
@@ -40,9 +40,8 @@ import ca.gosyer.jui.ui.sources.home.SourceHomeScreen
|
|||||||
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
expect fun Modifier.sourceSideMenuItem(
|
expect fun Modifier.sourceSideMenuItem(
|
||||||
onSourceTabClick: () -> Unit,
|
onSourceTabClick: () -> Unit,
|
||||||
@@ -140,10 +139,11 @@ fun SourcesSideMenu(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
is SourceNavigatorScreen.SourceScreen -> Box(Modifier.align(Alignment.Center)) {
|
is SourceNavigatorScreen.SourceScreen -> Box(Modifier.align(Alignment.Center)) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
resource = lazyPainterResource(screen.source, filterQuality = FilterQuality.Medium),
|
data = screen.source,
|
||||||
contentDescription = screen.source.displayName,
|
contentDescription = screen.source.displayName,
|
||||||
modifier = modifier
|
modifier = modifier,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ import androidx.compose.ui.unit.times
|
|||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import ca.gosyer.jui.ui.sources.browse.components.SourceMangaBadges
|
import ca.gosyer.jui.ui.sources.browse.components.SourceMangaBadges
|
||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GlobalSearchMangaComfortableGridItem(
|
fun GlobalSearchMangaComfortableGridItem(
|
||||||
@@ -37,7 +36,6 @@ fun GlobalSearchMangaComfortableGridItem(
|
|||||||
manga: Manga,
|
manga: Manga,
|
||||||
inLibrary: Boolean
|
inLibrary: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
val fontStyle = LocalTextStyle.current.merge(
|
val fontStyle = LocalTextStyle.current.merge(
|
||||||
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
||||||
)
|
)
|
||||||
@@ -49,14 +47,15 @@ fun GlobalSearchMangaComfortableGridItem(
|
|||||||
.clip(MaterialTheme.shapes.medium) then modifier
|
.clip(MaterialTheme.shapes.medium) then modifier
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
manga,
|
||||||
contentDescription = manga.title,
|
contentDescription = manga.title,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(200.dp)
|
.height(200.dp)
|
||||||
.aspectRatio(mangaAspectRatio, true)
|
.aspectRatio(mangaAspectRatio, true)
|
||||||
.clip(MaterialTheme.shapes.medium),
|
.clip(MaterialTheme.shapes.medium),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = manga.title,
|
text = manga.title,
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import ca.gosyer.jui.ui.sources.browse.components.SourceMangaBadges
|
import ca.gosyer.jui.ui.sources.browse.components.SourceMangaBadges
|
||||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GlobalSearchMangaCompactGridItem(
|
fun GlobalSearchMangaCompactGridItem(
|
||||||
@@ -40,7 +39,6 @@ fun GlobalSearchMangaCompactGridItem(
|
|||||||
manga: Manga,
|
manga: Manga,
|
||||||
inLibrary: Boolean
|
inLibrary: Boolean
|
||||||
) {
|
) {
|
||||||
val cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium)
|
|
||||||
val fontStyle = LocalTextStyle.current.merge(
|
val fontStyle = LocalTextStyle.current.merge(
|
||||||
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
TextStyle(letterSpacing = 0.sp, fontFamily = FontFamily.SansSerif, fontSize = 14.sp)
|
||||||
)
|
)
|
||||||
@@ -51,11 +49,12 @@ fun GlobalSearchMangaCompactGridItem(
|
|||||||
.aspectRatio(mangaAspectRatio, true)
|
.aspectRatio(mangaAspectRatio, true)
|
||||||
.clip(MaterialTheme.shapes.medium) then modifier
|
.clip(MaterialTheme.shapes.medium) then modifier
|
||||||
) {
|
) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
manga,
|
||||||
manga.title,
|
manga.title,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
Box(modifier = Modifier.fillMaxSize().then(shadowGradient))
|
Box(modifier = Modifier.fillMaxSize().then(shadowGradient))
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -56,10 +56,9 @@ import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
|||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberVerticalScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
import com.vanpra.composematerialdialogs.rememberMaterialDialogState
|
import com.vanpra.composematerialdialogs.rememberMaterialDialogState
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourceHomeScreenContent(
|
fun SourceHomeScreenContent(
|
||||||
@@ -175,7 +174,12 @@ fun WideSourceItem(
|
|||||||
},
|
},
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
KamelImage(lazyPainterResource(source, filterQuality = FilterQuality.Medium), source.displayName, Modifier.size(96.dp))
|
ImageLoaderImage(
|
||||||
|
data = source,
|
||||||
|
contentDescription = source.displayName,
|
||||||
|
modifier = Modifier.size(96.dp),
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
|
)
|
||||||
Spacer(Modifier.height(4.dp))
|
Spacer(Modifier.height(4.dp))
|
||||||
Text(
|
Text(
|
||||||
"${source.name} (${source.displayLang.toUpperCase(Locale.current)})",
|
"${source.name} (${source.displayLang.toUpperCase(Locale.current)})",
|
||||||
@@ -199,11 +203,12 @@ fun ThinSourceItem(
|
|||||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
lazyPainterResource(source, filterQuality = FilterQuality.Medium),
|
source,
|
||||||
source.displayName,
|
source.displayName,
|
||||||
Modifier.fillMaxHeight()
|
Modifier.fillMaxHeight()
|
||||||
.aspectRatio(1F, true)
|
.aspectRatio(1F, true),
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Column {
|
Column {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import ca.gosyer.jui.domain.chapter.model.Chapter
|
import ca.gosyer.jui.domain.chapter.model.Chapter
|
||||||
@@ -45,7 +44,6 @@ import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
|||||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
import io.kamel.image.lazyPainterResource
|
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -137,7 +135,7 @@ fun UpdatesItem(
|
|||||||
.padding(start = 16.dp, top = 8.dp, bottom = 8.dp)
|
.padding(start = 16.dp, top = 8.dp, bottom = 8.dp)
|
||||||
.clip(MaterialTheme.shapes.medium)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
.clickable { onClickCover() },
|
.clickable { onClickCover() },
|
||||||
cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium),
|
data = manga,
|
||||||
contentDescription = manga.title
|
contentDescription = manga.title
|
||||||
)
|
)
|
||||||
MangaListItemColumn(
|
MangaListItemColumn(
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.image
|
||||||
|
|
||||||
|
import ca.gosyer.jui.core.io.userDataDir
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import com.seiko.imageloader.ImageLoaderBuilder
|
||||||
|
import com.seiko.imageloader.cache.disk.DiskCache
|
||||||
|
import com.seiko.imageloader.cache.disk.DiskCacheBuilder
|
||||||
|
import com.seiko.imageloader.cache.memory.MemoryCache
|
||||||
|
import com.seiko.imageloader.cache.memory.MemoryCacheBuilder
|
||||||
|
|
||||||
|
actual fun imageLoaderBuilder(contextWrapper: ContextWrapper): ImageLoaderBuilder {
|
||||||
|
return ImageLoaderBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun diskCache(contextWrapper: ContextWrapper): DiskCache {
|
||||||
|
return DiskCacheBuilder()
|
||||||
|
.directory(userDataDir / "image_cache")
|
||||||
|
.maxSizeBytes(1024 * 1024 * 150) // 150 MB
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun memoryCache(contextWrapper: ContextWrapper): MemoryCache {
|
||||||
|
return MemoryCacheBuilder()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@ kotlin {
|
|||||||
api(kotlin("stdlib-common"))
|
api(kotlin("stdlib-common"))
|
||||||
api(libs.coroutines.core)
|
api(libs.coroutines.core)
|
||||||
api(libs.kamel)
|
api(libs.kamel)
|
||||||
|
api(libs.imageloader)
|
||||||
api(libs.voyager.core)
|
api(libs.voyager.core)
|
||||||
api(libs.dateTime)
|
api(libs.dateTime)
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
|
|||||||
@@ -23,20 +23,19 @@ import androidx.compose.ui.draw.drawWithCache
|
|||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.core.Resource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaGridItem(
|
fun MangaGridItem(
|
||||||
title: String,
|
title: String,
|
||||||
cover: Resource<Painter>,
|
data: Any,
|
||||||
onClick: () -> Unit = {}
|
onClick: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val fontStyle = LocalTextStyle.current.merge(
|
val fontStyle = LocalTextStyle.current.merge(
|
||||||
@@ -53,7 +52,7 @@ fun MangaGridItem(
|
|||||||
shape = RoundedCornerShape(4.dp)
|
shape = RoundedCornerShape(4.dp)
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
KamelImage(cover, title, contentScale = ContentScale.Crop)
|
ImageLoaderImage(data, title, contentScale = ContentScale.Crop, filterQuality = FilterQuality.Medium)
|
||||||
Box(modifier = Modifier.fillMaxSize().then(shadowGradient))
|
Box(modifier = Modifier.fillMaxSize().then(shadowGradient))
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
|
|||||||
@@ -15,12 +15,11 @@ import androidx.compose.material.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import ca.gosyer.jui.uicore.image.KamelImage
|
import ca.gosyer.jui.uicore.image.ImageLoaderImage
|
||||||
import io.kamel.core.Resource
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaListItem(
|
fun MangaListItem(
|
||||||
@@ -38,14 +37,15 @@ fun MangaListItem(
|
|||||||
@Composable
|
@Composable
|
||||||
fun MangaListItemImage(
|
fun MangaListItemImage(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
cover: Resource<Painter>,
|
data: Any,
|
||||||
contentDescription: String
|
contentDescription: String
|
||||||
) {
|
) {
|
||||||
KamelImage(
|
ImageLoaderImage(
|
||||||
cover,
|
data,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop,
|
||||||
|
filterQuality = FilterQuality.Medium
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.uicore.image
|
||||||
|
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
|
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.BrokenImage
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
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.Color
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.DefaultAlpha
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.graphics.drawscope.DrawScope.Companion.DefaultFilterQuality
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ca.gosyer.jui.uicore.components.LoadingScreen
|
||||||
|
import com.seiko.imageloader.ImageRequestState
|
||||||
|
import com.seiko.imageloader.rememberAsyncImagePainter
|
||||||
|
import com.seiko.imageloader.request.ImageRequestBuilder
|
||||||
|
import org.lighthousegames.logging.logging
|
||||||
|
|
||||||
|
private val log = logging()
|
||||||
|
|
||||||
|
private enum class ImageLoaderImageState {
|
||||||
|
Loading,
|
||||||
|
Success,
|
||||||
|
Failure,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ImageLoaderImage(
|
||||||
|
data: Any,
|
||||||
|
contentDescription: String?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
errorModifier: Modifier = modifier,
|
||||||
|
alignment: Alignment = Alignment.Center,
|
||||||
|
contentScale: ContentScale = ContentScale.Fit,
|
||||||
|
alpha: Float = DefaultAlpha,
|
||||||
|
colorFilter: ColorFilter? = null,
|
||||||
|
filterQuality: FilterQuality = DefaultFilterQuality,
|
||||||
|
onLoading: (@Composable BoxScope.(Float) -> Unit)? = {
|
||||||
|
LoadingScreen(progress = it.coerceIn(0.0F, 1.0F), modifier = modifier then Modifier.fillMaxSize())
|
||||||
|
},
|
||||||
|
onFailure: (@Composable BoxScope.(Throwable) -> Unit)? = {
|
||||||
|
LaunchedEffect(it) {
|
||||||
|
log.warn(it) { "Error loading image" }
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = errorModifier then Modifier.fillMaxSize()
|
||||||
|
.background(Color(0x1F888888)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.Rounded.BrokenImage,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color(0x1F888888),
|
||||||
|
modifier = Modifier.size(24.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentAlignment: Alignment = Alignment.Center,
|
||||||
|
animationSpec: FiniteAnimationSpec<Float>? = tween()
|
||||||
|
) {
|
||||||
|
val request = remember(data) { ImageRequestBuilder().data(data).build() }
|
||||||
|
val painter = rememberAsyncImagePainter(request, contentScale = contentScale)
|
||||||
|
|
||||||
|
val progress = remember { mutableStateOf(-1F) }
|
||||||
|
val error = remember { mutableStateOf<Throwable?>(null) }
|
||||||
|
val state by derivedStateOf {
|
||||||
|
when (val state = painter.requestState) {
|
||||||
|
is ImageRequestState.Failure -> {
|
||||||
|
progress.value = 0.0F
|
||||||
|
error.value = state.error
|
||||||
|
ImageLoaderImageState.Failure
|
||||||
|
}
|
||||||
|
ImageRequestState.Loading -> {
|
||||||
|
progress.value = 0.0F
|
||||||
|
ImageLoaderImageState.Loading
|
||||||
|
}
|
||||||
|
ImageRequestState.Success -> {
|
||||||
|
progress.value = 1.0F
|
||||||
|
ImageLoaderImageState.Success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (animationSpec != null) {
|
||||||
|
Crossfade(state, animationSpec = animationSpec, modifier = modifier) {
|
||||||
|
Box(Modifier.fillMaxSize(), contentAlignment) {
|
||||||
|
when (it) {
|
||||||
|
ImageLoaderImageState.Loading -> if (onLoading != null) {
|
||||||
|
onLoading(progress.value)
|
||||||
|
}
|
||||||
|
ImageLoaderImageState.Success -> Image(
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
alignment = alignment,
|
||||||
|
contentScale = contentScale,
|
||||||
|
alpha = alpha,
|
||||||
|
colorFilter = colorFilter
|
||||||
|
)
|
||||||
|
ImageLoaderImageState.Failure -> {
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure(error.value ?: return@Crossfade)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Box(modifier, contentAlignment) {
|
||||||
|
Image(
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
alignment = alignment,
|
||||||
|
contentScale = contentScale,
|
||||||
|
alpha = alpha,
|
||||||
|
colorFilter = colorFilter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user