mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-19 19:12:33 +01:00
Remove Kamel
This commit is contained in:
@@ -26,7 +26,6 @@ dependencies {
|
||||
implementation(libs.accompanist.pager)
|
||||
implementation(libs.accompanist.pagerIndicators)
|
||||
implementation(libs.accompanist.flowLayout)
|
||||
implementation(libs.kamel)
|
||||
implementation(libs.imageloader)
|
||||
implementation(libs.materialDialogs.core)
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ dependencies {
|
||||
implementation(libs.accompanist.pager)
|
||||
implementation(libs.accompanist.pagerIndicators)
|
||||
implementation(libs.accompanist.flowLayout)
|
||||
implementation(libs.kamel)
|
||||
implementation(libs.imageloader)
|
||||
implementation(libs.materialDialogs.core)
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ composeCompiler = "1.3.0"
|
||||
composeAndroid = "1.2.1"
|
||||
voyager = "1.0.0-beta16"
|
||||
accompanist = "0.25.1"
|
||||
kamel = "0.4.1"
|
||||
imageloader = "1.1.3"
|
||||
materialDialogs = "0.8.0"
|
||||
|
||||
@@ -101,7 +100,6 @@ voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", vers
|
||||
accompanist-pager = { module = "ca.gosyer:accompanist-pager", version.ref = "accompanist" }
|
||||
accompanist-pagerIndicators = { module = "ca.gosyer:accompanist-pager-indicators", version.ref = "accompanist" }
|
||||
accompanist-flowLayout = { module = "ca.gosyer:accompanist-flowlayout", version.ref = "accompanist" }
|
||||
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" }
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ kotlin {
|
||||
dependencies {
|
||||
api(kotlin("stdlib-common"))
|
||||
api(libs.coroutines.core)
|
||||
api(libs.kamel)
|
||||
api(libs.imageloader)
|
||||
api(libs.voyager.core)
|
||||
api(libs.voyager.navigation)
|
||||
|
||||
@@ -1,17 +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.jui.ui.base
|
||||
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import io.kamel.core.config.KamelConfigBuilder
|
||||
import io.kamel.image.config.resourcesFetcher
|
||||
import io.kamel.image.config.resourcesIdMapper
|
||||
|
||||
actual fun KamelConfigBuilder.kamelPlatformHandler(contextWrapper: ContextWrapper) {
|
||||
resourcesIdMapper(contextWrapper)
|
||||
resourcesFetcher(contextWrapper)
|
||||
}
|
||||
@@ -11,30 +11,18 @@ import androidx.compose.runtime.compositionLocalOf
|
||||
import ca.gosyer.jui.core.di.AppScope
|
||||
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.uicore.vm.ContextWrapper
|
||||
import com.seiko.imageloader.ImageLoader
|
||||
import com.seiko.imageloader.LocalImageLoader
|
||||
import io.kamel.core.config.KamelConfig
|
||||
import io.kamel.core.config.KamelConfigBuilder
|
||||
import io.kamel.image.config.LocalKamelConfig
|
||||
import me.tatarka.inject.annotations.Provides
|
||||
|
||||
interface UiComponent {
|
||||
val kamelConfigProvider: KamelConfigProvider
|
||||
|
||||
val kamelConfig: KamelConfig
|
||||
|
||||
val imageLoader: ImageLoader
|
||||
|
||||
val contextWrapper: ContextWrapper
|
||||
|
||||
val hooks: Array<ProvidedValue<out Any>>
|
||||
|
||||
@AppScope
|
||||
@Provides
|
||||
fun kamelConfigFactory(contextWrapper: ContextWrapper): KamelConfig = kamelConfigProvider.get { kamelPlatformHandler(contextWrapper) }
|
||||
|
||||
@AppScope
|
||||
@Provides
|
||||
fun imageLoaderFactory(imageLoaderProvider: ImageLoaderProvider): ImageLoader = imageLoaderProvider.get()
|
||||
@@ -42,12 +30,9 @@ interface UiComponent {
|
||||
@Provides
|
||||
fun getHooks(viewModelComponent: ViewModelComponent) = arrayOf(
|
||||
LocalViewModels provides viewModelComponent,
|
||||
LocalKamelConfig provides kamelConfig,
|
||||
LocalImageLoader provides imageLoader
|
||||
)
|
||||
}
|
||||
|
||||
expect fun KamelConfigBuilder.kamelPlatformHandler(contextWrapper: ContextWrapper)
|
||||
|
||||
val LocalViewModels =
|
||||
compositionLocalOf<ViewModelComponent> { throw IllegalArgumentException("ViewModelComponent not found") }
|
||||
|
||||
@@ -1,112 +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.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 io.kamel.core.DataSource
|
||||
import io.kamel.core.Resource
|
||||
import io.kamel.core.config.DefaultCacheSize
|
||||
import io.kamel.core.config.KamelConfig
|
||||
import io.kamel.core.config.KamelConfigBuilder
|
||||
import io.kamel.core.config.ResourceConfig
|
||||
import io.kamel.core.config.fileFetcher
|
||||
import io.kamel.core.config.stringMapper
|
||||
import io.kamel.core.config.uriMapper
|
||||
import io.kamel.core.config.urlMapper
|
||||
import io.kamel.core.fetcher.Fetcher
|
||||
import io.kamel.core.mapper.Mapper
|
||||
import io.kamel.image.config.imageBitmapDecoder
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.plugins.expectSuccess
|
||||
import io.ktor.client.plugins.onDownload
|
||||
import io.ktor.client.request.request
|
||||
import io.ktor.client.request.takeFrom
|
||||
import io.ktor.client.request.url
|
||||
import io.ktor.client.statement.bodyAsChannel
|
||||
import io.ktor.http.Url
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
|
||||
class KamelConfigProvider @Inject constructor(
|
||||
private val http: Http,
|
||||
serverPreferences: ServerPreferences
|
||||
) {
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
val serverUrl = serverPreferences.serverUrl().stateIn(GlobalScope)
|
||||
|
||||
fun get(kamelPlatformHandler: KamelConfigBuilder.() -> Unit): KamelConfig {
|
||||
return KamelConfig {
|
||||
// Default config
|
||||
imageBitmapCacheSize = DefaultCacheSize
|
||||
imageVectorCacheSize = DefaultCacheSize
|
||||
imageBitmapDecoder()
|
||||
stringMapper()
|
||||
urlMapper()
|
||||
uriMapper()
|
||||
fileFetcher()
|
||||
|
||||
// JUI config
|
||||
kamelPlatformHandler()
|
||||
fetcher(HttpFetcher(http))
|
||||
mapper(MangaCoverMapper(serverUrl))
|
||||
mapper(ExtensionIconMapper(serverUrl))
|
||||
mapper(SourceIconMapper(serverUrl))
|
||||
}
|
||||
}
|
||||
|
||||
class MangaCoverMapper(private val serverUrlStateFlow: StateFlow<Url>) : Mapper<Manga, Url> {
|
||||
override fun map(input: Manga): Url {
|
||||
return Url(serverUrlStateFlow.value.toString() + input.thumbnailUrl.orEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
class ExtensionIconMapper(private val serverUrlStateFlow: StateFlow<Url>) : Mapper<Extension, Url> {
|
||||
override fun map(input: Extension): Url {
|
||||
return Url(serverUrlStateFlow.value.toString() + input.iconUrl)
|
||||
}
|
||||
}
|
||||
|
||||
class SourceIconMapper(private val serverUrlStateFlow: StateFlow<Url>) : Mapper<Source, Url> {
|
||||
override fun map(input: Source): Url {
|
||||
return Url(serverUrlStateFlow.value.toString() + input.iconUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpFetcher(private val client: HttpClient) : Fetcher<Url> {
|
||||
|
||||
override val source: DataSource = DataSource.Network
|
||||
|
||||
override val Url.isSupported: Boolean
|
||||
get() = protocol.name == "https" || protocol.name == "http"
|
||||
|
||||
override fun fetch(
|
||||
data: Url,
|
||||
resourceConfig: ResourceConfig
|
||||
): Flow<Resource<ByteReadChannel>> = channelFlow {
|
||||
val response = client.request {
|
||||
onDownload { bytesSentTotal, contentLength ->
|
||||
val progress = (bytesSentTotal.toFloat() / contentLength).coerceAtMost(1.0F)
|
||||
send(Resource.Loading(progress))
|
||||
}
|
||||
takeFrom(resourceConfig.requestData)
|
||||
url(data)
|
||||
expectSuccess = true
|
||||
}
|
||||
val bytes = response.bodyAsChannel()
|
||||
send(Resource.Success(bytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +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.jui.ui.base
|
||||
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import io.kamel.core.config.KamelConfigBuilder
|
||||
import io.kamel.image.config.imageVectorDecoder
|
||||
import io.kamel.image.config.resourcesFetcher
|
||||
import io.kamel.image.config.svgDecoder
|
||||
|
||||
actual fun KamelConfigBuilder.kamelPlatformHandler(contextWrapper: ContextWrapper) {
|
||||
resourcesFetcher()
|
||||
imageVectorDecoder()
|
||||
svgDecoder()
|
||||
}
|
||||
@@ -38,7 +38,6 @@ kotlin {
|
||||
dependencies {
|
||||
api(kotlin("stdlib-common"))
|
||||
api(libs.coroutines.core)
|
||||
api(libs.kamel)
|
||||
api(libs.imageloader)
|
||||
api(libs.voyager.core)
|
||||
api(libs.dateTime)
|
||||
|
||||
@@ -1,148 +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.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.painter.Painter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ca.gosyer.jui.uicore.components.LoadingScreen
|
||||
import io.kamel.core.Resource
|
||||
import org.lighthousegames.logging.logging
|
||||
import io.kamel.image.KamelImage as BaseKamelImage
|
||||
|
||||
private val log = logging()
|
||||
|
||||
private enum class KamelImageState {
|
||||
Loading,
|
||||
Success,
|
||||
Failure,
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun KamelImage(
|
||||
resource: Resource<Painter>,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
errorModifier: Modifier = modifier,
|
||||
alignment: Alignment = Alignment.Center,
|
||||
contentScale: ContentScale = ContentScale.Fit,
|
||||
alpha: Float = DefaultAlpha,
|
||||
colorFilter: ColorFilter? = null,
|
||||
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()
|
||||
) {
|
||||
if (animationSpec != null) {
|
||||
val progress = remember { mutableStateOf(-1F) }
|
||||
val image = remember { mutableStateOf<Painter?>(null) }
|
||||
val error = remember { mutableStateOf<Throwable?>(null) }
|
||||
val state by derivedStateOf {
|
||||
when (resource) {
|
||||
is Resource.Failure -> {
|
||||
progress.value = -1F
|
||||
error.value = resource.exception
|
||||
KamelImageState.Failure
|
||||
}
|
||||
is Resource.Loading -> {
|
||||
progress.value = resource.progress
|
||||
KamelImageState.Loading
|
||||
}
|
||||
is Resource.Success -> {
|
||||
progress.value = 1.0F
|
||||
image.value = resource.value
|
||||
KamelImageState.Success
|
||||
}
|
||||
}
|
||||
}
|
||||
Crossfade(state, animationSpec = animationSpec, modifier = modifier) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment) {
|
||||
when (it) {
|
||||
KamelImageState.Loading -> if (onLoading != null) {
|
||||
onLoading(progress.value)
|
||||
}
|
||||
KamelImageState.Success -> Box {
|
||||
val value = image.value
|
||||
if (value != null) {
|
||||
Image(
|
||||
value,
|
||||
contentDescription,
|
||||
modifier,
|
||||
alignment,
|
||||
contentScale,
|
||||
alpha,
|
||||
colorFilter
|
||||
)
|
||||
} else if (onLoading != null) {
|
||||
onLoading(1.0F)
|
||||
}
|
||||
}
|
||||
KamelImageState.Failure -> {
|
||||
if (onFailure != null) {
|
||||
onFailure(error.value ?: return@Crossfade)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BaseKamelImage(
|
||||
resource,
|
||||
contentDescription,
|
||||
modifier,
|
||||
alignment,
|
||||
contentScale,
|
||||
alpha,
|
||||
colorFilter,
|
||||
onLoading,
|
||||
onFailure,
|
||||
contentAlignment,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user