Migrate from glide to coil.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2024-06-27 12:24:39 +02:00
parent ca41948a75
commit 15eb013579
12 changed files with 227 additions and 152 deletions

View file

@ -128,8 +128,7 @@ dependencies {
implementation "com.google.accompanist:accompanist-swiperefresh:0.34.0"
// Landscapist
implementation "com.github.skydoves:landscapist-glide:1.5.2"
kapt 'com.github.bumptech.glide:compiler:4.13.2' // this have to be align with landscapist-glide
implementation("io.coil-kt:coil-compose:2.6.0")
// Reorder element in lazylist
implementation "org.burnoutcrew.composereorderable:reorderable:0.9.6"

View file

@ -1,20 +0,0 @@
package com.pixelized.biblib.module
import android.content.Context
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions
@GlideModule
class AppNameGlideModule : AppGlideModule() {
override fun applyOptions(context: Context, builder: GlideBuilder) {
super.applyOptions(context, builder)
builder.apply {
this.setDefaultRequestOptions {
RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)
}
}
}
}

View file

@ -3,17 +3,20 @@ package com.pixelized.biblib.ui
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.ScaffoldState
import androidx.compose.material.Snackbar
import androidx.compose.material.SnackbarHost
import androidx.compose.material.SnackbarHostState
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.pixelized.biblib.ui.navigation.ScreenNavHost
import com.pixelized.biblib.ui.screen.launch.LauncherViewModel
import com.skydoves.landscapist.glide.LocalGlideRequestOptions
val LocalSnackHostState = staticCompositionLocalOf<SnackbarHostState> {
error("SnackBarHostState is not ready yet.")
@ -22,12 +25,10 @@ val LocalSnackHostState = staticCompositionLocalOf<SnackbarHostState> {
@Composable
fun MainContent(
launcherViewModel: LauncherViewModel = hiltViewModel(),
glideOptions: RequestOptions = RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)
) {
val scaffoldState: ScaffoldState = rememberScaffoldState()
CompositionLocalProvider(
LocalGlideRequestOptions provides glideOptions,
LocalSnackHostState provides scaffoldState.snackbarHostState,
) {
Scaffold(

View file

@ -44,6 +44,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@ -63,6 +64,7 @@ import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -131,17 +133,19 @@ fun AuthenticationScreen(
R.drawable.biblib_background_2,
R.drawable.biblib_background_3,
)
mutableStateOf(tmp.random())
mutableIntStateOf(tmp.random())
}
val displayBibLibSignIn = rememberSaveable { mutableStateOf(false) }
val blur = remember(displayBibLibSignIn) {
derivedStateOf { if (displayBibLibSignIn.value) 8.dp else 0.dp }
}
val displayBibLibSignIn = remember { mutableStateOf(false) }
val blur = remember { derivedStateOf { if (displayBibLibSignIn.value) 8.dp else 0.dp } }
Surface(
modifier = Modifier.fillMaxSize(),
) {
AuthenticationScreenContent(
modifier = Modifier.fillMaxSize(),
background = background.value,
background = background.intValue,
blur = blur,
onGoogleSignIn = authenticationViewModel::loginWithGoogle,
onBibLibSingIn = { displayBibLibSignIn.value = true },
@ -216,7 +220,7 @@ private fun AuthenticationScreenContent(
val colorScheme = MaterialTheme.colors
val animatedBlur = animateDpAsState(
targetValue = blur.value,
// label = "AnimatedContentBlur",
label = "AnimatedContentBlur",
)
Column(
@ -231,9 +235,7 @@ private fun AuthenticationScreenContent(
.weight(1f),
) {
Image(
modifier = Modifier
.matchParentSize()
.background(color = MaterialTheme.colors.surface.copy(alpha = 0.8f)),
modifier = Modifier.matchParentSize(),
contentScale = ContentScale.FillHeight,
painter = painterResource(id = background),
contentDescription = null,
@ -282,7 +284,11 @@ private fun AuthenticationScreenContent(
colors = ButtonDefaults.textButtonColors(),
onClick = onBibLibSingIn,
) {
Text(text = "Sign in with BibLib account")
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
text = stringResource(id = R.string.authentication_sign_in_with_biblib),
)
}
}
}
@ -314,10 +320,10 @@ private fun AuthenticationSignDialog(
.background(
color = animateColorAsState(
targetValue = when (visibility.value) {
true -> colorScheme.surface.copy(alpha = 0.3f)
true -> colorScheme.surface.copy(alpha = 0.5f)
else -> Color.Transparent
},
// label = "AnimatedSignInScrim"
label = "AnimatedSignInScrim"
).value
),
) {
@ -380,9 +386,7 @@ private fun AuthenticationSignDialog(
) {
TextButton(
modifier = Modifier.height(height = 48.dp),
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colors.onSurface
),
colors = ButtonDefaults.textButtonColors(),
onClick = onRegister,
) {
Text(text = stringResource(id = R.string.action_register))

View file

@ -2,30 +2,66 @@ package com.pixelized.biblib.ui.screen.home
import android.content.res.Configuration
import androidx.annotation.StringRes
import androidx.compose.animation.*
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.SnackbarResult
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.pullrefresh.PullRefreshState
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.*
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
@ -34,6 +70,7 @@ import androidx.compose.ui.unit.max
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.PagingData
import androidx.paging.compose.collectAsLazyPagingItems
import coil.compose.AsyncImage
import com.pixelized.biblib.R
import com.pixelized.biblib.model.search.FilterType
import com.pixelized.biblib.model.search.SortType
@ -41,10 +78,23 @@ import com.pixelized.biblib.model.search.SortValue
import com.pixelized.biblib.ui.LocalSnackHostState
import com.pixelized.biblib.ui.composable.Loader
import com.pixelized.biblib.ui.composable.colorElevation
import com.pixelized.biblib.ui.composable.scaffold.*
import com.pixelized.biblib.ui.composable.scaffold.DetailBottomSheet
import com.pixelized.biblib.ui.composable.scaffold.DetailBottomSheetState
import com.pixelized.biblib.ui.composable.scaffold.FilterBottomSheet
import com.pixelized.biblib.ui.composable.scaffold.FilterBottomSheetResult
import com.pixelized.biblib.ui.composable.scaffold.FilterBottomSheetState
import com.pixelized.biblib.ui.composable.scaffold.SortBottomSheet
import com.pixelized.biblib.ui.composable.scaffold.SortBottomSheetResult
import com.pixelized.biblib.ui.composable.scaffold.SortBottomSheetState
import com.pixelized.biblib.ui.composable.scaffold.rememberDetailBottomSheetState
import com.pixelized.biblib.ui.composable.scaffold.rememberFilterBottomSheetState
import com.pixelized.biblib.ui.composable.scaffold.rememberSortBottomSheetState
import com.pixelized.biblib.ui.navigation.LocalScreenNavHostController
import com.pixelized.biblib.ui.navigation.navigateToProfile
import com.pixelized.biblib.ui.screen.home.common.item.*
import com.pixelized.biblib.ui.screen.home.common.item.BookThumbnailUio
import com.pixelized.biblib.ui.screen.home.common.item.LargeBookThumbnail
import com.pixelized.biblib.ui.screen.home.common.item.MicroBookThumbnail
import com.pixelized.biblib.ui.screen.home.common.item.SmallBookThumbnail
import com.pixelized.biblib.ui.screen.home.common.preview.thumbnailPreviewResources
import com.pixelized.biblib.ui.screen.home.filter.FilterChip
import com.pixelized.biblib.ui.screen.home.filter.FilterChipUio
@ -56,7 +106,6 @@ import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.imeHeight
import com.pixelized.biblib.utils.extention.navigationBarsHeight
import com.skydoves.landscapist.glide.GlideImage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
@ -238,18 +287,22 @@ private fun rememberOnFilter(
author = result.filter.filterLabel,
authorId = result.filter.filterId,
)
FilterType.Series -> filterBySeries(
series = result.filter.filterLabel,
seriesId = result.filter.filterId,
)
FilterType.Genre -> filterByGenre(
genre = result.filter.filterLabel,
genreId = result.filter.filterId,
)
FilterType.Language -> filterByLanguage(
language = result.filter.filterLabel,
languageId = result.filter.filterId,
)
else -> Unit
}
}
@ -262,18 +315,22 @@ private fun rememberOnFilter(
author = null,
authorId = null,
)
FilterType.Series -> filterBySeries(
series = null,
seriesId = null,
)
FilterType.Genre -> filterByGenre(
genre = null,
genreId = null,
)
FilterType.Language -> filterByLanguage(
language = null,
languageId = null,
)
else -> Unit
}
}
@ -474,14 +531,14 @@ private fun HomeToolbar(
onClick = onAvatarTap,
) {
if (avatar != null) {
GlideImage(
AsyncImage(
modifier = Modifier
.clip(CircleShape)
.size(MaterialTheme.bibLib.dimen.avatar.medium),
previewPlaceholder = R.drawable.ic_google,
placeHolder = painterResource(id = R.drawable.ic_google),
model = avatar,
placeholder = painterResource(id = R.drawable.ic_google),
contentScale = ContentScale.Fit,
imageModel = avatar,
contentDescription = null,
)
} else {
Icon(
@ -598,7 +655,7 @@ private fun BookList(
@OptIn(ExperimentalMaterialApi::class)
private fun rememberPullRefreshState(
viewModel: BookSearchViewModel,
scope : CoroutineScope = rememberCoroutineScope()
scope: CoroutineScope = rememberCoroutineScope()
): PullRefreshState {
return rememberPullRefreshState(
refreshing = viewModel.updating.value,

View file

@ -3,7 +3,11 @@ package com.pixelized.biblib.ui.screen.home.common.item
import android.annotation.SuppressLint
import android.content.res.Configuration
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
@ -11,17 +15,18 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.pixelized.biblib.utils.extention.placeholder
import com.skydoves.landscapist.glide.GlideImage
@Composable
fun LargeBookThumbnail(
@ -55,15 +60,17 @@ private fun LargeBookThumbnailContent(
thumbnail: BookThumbnailUio,
onClick: (BookThumbnailUio) -> Unit,
) {
GlideImage(
AsyncImage(
modifier = Modifier
.clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge)
.fillMaxWidth()
.aspectRatio(64f / 102f)
.isNew { thumbnail.isNew }
.clickable { thumbnail.let(onClick) },
previewPlaceholder = R.drawable.ic_fondatoin_cover,
imageModel = thumbnail.cover,
.clickable { thumbnail.let(onClick) }
.then(other = modifier),
model = thumbnail.cover,
contentScale = ContentScale.Crop,
contentDescription = null,
)
}
@ -79,6 +86,7 @@ private fun LargeBookThumbnailPlaceHolder(
shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge,
visible = { true }
)
.then(other = modifier)
)
}

View file

@ -15,6 +15,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
@ -24,12 +25,12 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import coil.compose.AsyncImage
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.pixelized.biblib.utils.extention.placeholder
import com.skydoves.landscapist.glide.GlideImage
@Composable
fun MicroBookThumbnail(
@ -68,7 +69,7 @@ private fun MicroBookThumbnailContent(
) {
val (cover, title, author, series) = createRefs()
GlideImage(
AsyncImage(
modifier = Modifier
.constrainAs(cover) {
top.linkTo(parent.top)
@ -78,8 +79,9 @@ private fun MicroBookThumbnailContent(
.clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverSmall)
.size(size = MaterialTheme.bibLib.dimen.thumbnail.micro)
.isNew { thumbnail.isNew },
previewPlaceholder = R.drawable.ic_fondation_thumbnail,
imageModel = thumbnail.thumbnail,
model = thumbnail.thumbnail,
contentScale = ContentScale.Crop,
contentDescription = null,
)
Text(

View file

@ -3,7 +3,10 @@ package com.pixelized.biblib.ui.screen.home.common.item
import android.annotation.SuppressLint
import android.content.res.Configuration
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
@ -12,6 +15,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
@ -20,12 +24,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import coil.compose.AsyncImage
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.pixelized.biblib.utils.extention.placeholder
import com.skydoves.landscapist.glide.GlideImage
@Composable
fun SmallBookThumbnail(
@ -64,7 +68,7 @@ private fun SmallBookThumbnailContent(
) {
val (cover, title, author, series, genre, date) = createRefs()
GlideImage(
AsyncImage(
modifier = Modifier
.constrainAs(cover) {
top.linkTo(parent.top)
@ -74,8 +78,9 @@ private fun SmallBookThumbnailContent(
.clip(shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverSmall)
.size(size = MaterialTheme.bibLib.dimen.thumbnail.cover)
.isNew { thumbnail.isNew },
previewPlaceholder = R.drawable.ic_fondation_thumbnail,
imageModel = thumbnail.thumbnail,
model = thumbnail.thumbnail,
contentScale = ContentScale.Crop,
contentDescription = null,
)
Text(

View file

@ -2,12 +2,25 @@ package com.pixelized.biblib.ui.screen.home.detail
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.graphics.drawable.Drawable
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
@ -15,12 +28,18 @@ import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Send
import androidx.compose.runtime.*
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -31,20 +50,17 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.text.HtmlCompat
import androidx.core.text.toSpannable
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import coil.compose.AsyncImagePainter
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil.size.Dimension
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.composable.Handle
import com.pixelized.biblib.ui.composable.SpannedText
import com.pixelized.biblib.ui.composable.animation.AnimatedDelayer
import com.pixelized.biblib.ui.composable.animation.AnimatedOffset
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.placeholder
import com.skydoves.landscapist.CircularReveal
import com.skydoves.landscapist.glide.GlideImage
import java.io.Serializable
@Stable
@ -243,7 +259,7 @@ fun DetailScreenContent(
Button(
onClick = onSend,
) {
Icon(imageVector = Icons.Default.Send, contentDescription = "")
Icon(imageVector = Icons.AutoMirrored.Filled.Send, contentDescription = "")
Spacer(modifier = Modifier.width(4.dp))
Text(text = stringResource(id = R.string.action_send))
}
@ -257,43 +273,75 @@ private fun Cover(
modifier: Modifier = Modifier,
cover: String,
) {
val placeholder = remember(cover) { mutableStateOf(true) }
val error = remember(cover) { mutableStateOf(false) }
Box(
modifier = modifier,
contentAlignment = Alignment.Center
) {
GlideImage(
requestListener = rememberRequestListener(
placeholder = placeholder,
error = error,
),
previewPlaceholder = R.drawable.ic_fondatoin_cover,
circularReveal = CircularReveal(duration = 500),
contentScale = ContentScale.FillHeight,
imageModel = cover,
)
Box(
modifier = Modifier
.height(MaterialTheme.bibLib.dimen.detail.cover)
.aspectRatio(ratio = remember { 1f / 1.5f })
.placeholder(
shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge,
isShimmering = { error.value.not() },
visible = { placeholder.value },
)
)
AnimatedVisibility(
visible = error.value,
enter = fadeIn(),
exit = fadeOut(),
) {
Icon(
modifier = Modifier.size(64.dp),
painter = painterResource(id = R.drawable.ic_no_photography_24),
contentDescription = null
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data(data = cover)
.size(
width = Dimension.Undefined,
height = Dimension.Pixels(
px = with(LocalDensity.current) {
MaterialTheme.bibLib.dimen.detail.cover.roundToPx()
},
),
)
.build()
)
AnimatedContent(
targetState = painter.state,
label = "Cover image animation",
transitionSpec = { fadeIn() togetherWith fadeOut() }
) {
Box(
modifier = modifier,
contentAlignment = Alignment.Center,
) {
when (it) {
AsyncImagePainter.State.Empty -> {
Box(
modifier = Modifier
.height(MaterialTheme.bibLib.dimen.detail.cover)
.aspectRatio(ratio = remember { 1f / 1.5f })
)
}
is AsyncImagePainter.State.Error -> {
Box(
modifier = Modifier
.height(MaterialTheme.bibLib.dimen.detail.cover)
.aspectRatio(ratio = remember { 1f / 1.5f }),
contentAlignment = Alignment.Center,
) {
Icon(
modifier = Modifier.size(64.dp),
painter = painterResource(id = R.drawable.ic_no_photography_24),
contentDescription = null
)
}
}
is AsyncImagePainter.State.Loading -> {
Box(
modifier = Modifier
.height(MaterialTheme.bibLib.dimen.detail.cover)
.aspectRatio(ratio = remember { 1f / 1.5f })
.placeholder(
shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge,
isShimmering = { painter.state is AsyncImagePainter.State.Loading },
visible = { true },
)
)
}
is AsyncImagePainter.State.Success -> {
Image(
modifier = Modifier.height(MaterialTheme.bibLib.dimen.detail.cover),
painter = painter,
contentScale = ContentScale.FillHeight,
contentDescription = null,
)
}
}
}
}
}
@ -327,37 +375,6 @@ private fun TitleLabel(
}
}
@Composable
fun rememberRequestListener(
placeholder: MutableState<Boolean>,
error: MutableState<Boolean>,
): RequestListener<Drawable> {
return remember(placeholder, error) {
object : RequestListener<Drawable> {
override fun onLoadFailed(
exception: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
error.value = true
return true
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
placeholder.value = false
return false
}
}
}
}
@Composable
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_NO, heightDp = 1000)
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES, heightDp = 1000)

View file

@ -32,7 +32,7 @@ fun Modifier.drawDiagonalLabel(
val textWidth = textSize.width
val textHeight = textSize.height
val rectWidth = textWidth * labelTextRatio * 1.1f
val rectWidth = textWidth * labelTextRatio * 1.5f
val rect = Rect(
offset = Offset(canvasWidth - rectWidth, 0f),

View file

@ -40,6 +40,7 @@
<string name="authentication_login">Alias du compte</string>
<string name="authentication_password">Mot de passe</string>
<string name="authentication_credential_remember">Mémoriser mes identifiants</string>
<string name="authentication_sign_in_with_biblib">Authentifiez-vous avec votre compte BibLib</string>
<string name="detail_open_on_biblib">ouvrir sur bib.bibulle.fr</string>
<string name="detail_rating">Note</string>

View file

@ -53,6 +53,7 @@
<string name="authentication_login">Login</string>
<string name="authentication_password">Password</string>
<string name="authentication_credential_remember">Remember my credential</string>
<string name="authentication_sign_in_with_biblib">Sign in with your BibLib account</string>
<string name="list_is_new" translatable="false">New</string>