diff --git a/app/src/main/java/com/nullpointer/userscompose/core/utils/AsyncImageFade.kt b/app/src/main/java/com/nullpointer/userscompose/core/utils/AsyncImageFade.kt new file mode 100644 index 0000000..7f6778e --- /dev/null +++ b/app/src/main/java/com/nullpointer/userscompose/core/utils/AsyncImageFade.kt @@ -0,0 +1,44 @@ +package com.nullpointer.userscompose.core.utils + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import coil.compose.rememberAsyncImagePainter +import coil.request.ImageRequest +import coil.transform.CircleCropTransformation + + +@Composable +fun AsyncImageFade( + data: Any?, + @DrawableRes + resourceLoading: Int, + @DrawableRes + resourceFailed: Int, + contentDescription: String, + modifier: Modifier = Modifier, +) { + + val painterImg = rememberAsyncImagePainter( + model = ImageRequest + .Builder(LocalContext.current) + .crossfade(true) + .data(data) + .transformations(CircleCropTransformation()) + .build(), + placeholder = painterResource(id = resourceLoading), + error = painterResource(id = resourceFailed), + ) + Image( + painter = painterImg, + contentDescription = contentDescription, + colorFilter = if (painterImg.isSuccess) null else ColorFilter.tint(getGrayColor()), + contentScale = if (painterImg.isSuccess) ContentScale.Crop else ContentScale.Fit, + modifier = modifier + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/nullpointer/userscompose/core/utils/Extensions.kt b/app/src/main/java/com/nullpointer/userscompose/core/utils/Extensions.kt index ad08fd0..440fbd6 100644 --- a/app/src/main/java/com/nullpointer/userscompose/core/utils/Extensions.kt +++ b/app/src/main/java/com/nullpointer/userscompose/core/utils/Extensions.kt @@ -4,11 +4,19 @@ import android.content.Context import android.text.format.DateFormat import androidx.activity.ComponentActivity import androidx.annotation.PluralsRes +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import coil.compose.AsyncImagePainter +import com.valentinilk.shimmer.Shimmer +import com.valentinilk.shimmer.shimmer import kotlinx.coroutines.* import java.text.SimpleDateFormat import java.util.* @@ -49,4 +57,17 @@ fun ViewModel.launchSafeIO( blockAfter() } } -} \ No newline at end of file +} + +val AsyncImagePainter.isSuccess get() = state is AsyncImagePainter.State.Success + +@Composable +fun getGrayColor(): Color { + return if (isSystemInDarkTheme()) Color.LightGray else Color.DarkGray +} + +fun Modifier.myShimmer( + shimmer: Shimmer, +): Modifier = composed { + shimmer(shimmer).background(getGrayColor()) +} diff --git a/app/src/main/java/com/nullpointer/userscompose/ui/screens/details/DetailsScreen.kt b/app/src/main/java/com/nullpointer/userscompose/ui/screens/details/DetailsScreen.kt index 029afe6..f503ca9 100644 --- a/app/src/main/java/com/nullpointer/userscompose/ui/screens/details/DetailsScreen.kt +++ b/app/src/main/java/com/nullpointer/userscompose/ui/screens/details/DetailsScreen.kt @@ -2,29 +2,24 @@ package com.nullpointer.userscompose.ui.screens.details import android.content.Context import android.content.res.Configuration -import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import coil.request.ImageRequest -import coil.transform.CircleCropTransformation import com.nullpointer.userscompose.R +import com.nullpointer.userscompose.core.utils.AsyncImageFade import com.nullpointer.userscompose.core.utils.shareViewModel import com.nullpointer.userscompose.core.utils.toFormat import com.nullpointer.userscompose.models.User @@ -60,21 +55,26 @@ fun DetailsScreen( Row(modifier = Modifier .fillMaxWidth() .padding(it)) { - HeaderUserPhoto(imgUser = user.imgUser, modifier = Modifier.weight(.3f)) - InfoUser(user = user, + HeaderUserPhoto( + imgUser = user.imgUser, + modifier = Modifier.weight(.3f), + nameUser = user.name, + ) + InfoUser( + user = user, Modifier .weight(.7f) - .fillMaxHeight()) + .fillMaxHeight() + ) } } else -> { Column( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .padding(it) ) { - HeaderUserPhoto(imgUser = user.imgUser) + HeaderUserPhoto(imgUser = user.imgUser, nameUser = user.name) Spacer(modifier = Modifier.height(20.dp)) InfoUser(user = user) } @@ -90,9 +90,7 @@ private fun InfoUser( modifier: Modifier = Modifier, context: Context = LocalContext.current ) { - val textDateSave by remember { - derivedStateOf { user.timestamp.toFormat(context) } - } + val textDateSave = remember { user.timestamp.toFormat(context) } Card(modifier = modifier.padding(5.dp)) { Column(modifier = Modifier.padding(10.dp)) { RowInfo(nameField = stringResource(R.string.name_user_text), dataField = user.name) @@ -109,31 +107,35 @@ private fun InfoUser( @Composable private fun HeaderUserPhoto( imgUser: String, - modifier: Modifier = Modifier + nameUser: String, + modifier: Modifier = Modifier, + colorHeader: Color = MaterialTheme.colors.primary ) { Box( modifier = modifier .height(200.dp) + .fillMaxWidth() + .drawBehind { + drawRect( + color = colorHeader, + size = size.copy(height = size.height / 2) + ) + } + .padding(15.dp) ) { - Box( - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight(.5f) - .background(MaterialTheme.colors.primary) - ) - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(imgUser) - .placeholder(R.drawable.ic_person) - .transformations(CircleCropTransformation()) - .error(R.drawable.ic_broken_image) - .build(), - contentDescription = stringResource(id = R.string.description_img_user), + + AsyncImageFade( + data = imgUser, + resourceLoading = R.drawable.ic_person, + resourceFailed = R.drawable.ic_broken_image, + contentDescription = stringResource(id = R.string.description_img_user, nameUser), modifier = Modifier - .size(150.dp) + .fillMaxHeight() + .aspectRatio(1f) .align(Alignment.Center) ) + } } diff --git a/app/src/main/java/com/nullpointer/userscompose/ui/screens/users/components/UserItem.kt b/app/src/main/java/com/nullpointer/userscompose/ui/screens/users/components/UserItem.kt index 3465e19..fd9272a 100644 --- a/app/src/main/java/com/nullpointer/userscompose/ui/screens/users/components/UserItem.kt +++ b/app/src/main/java/com/nullpointer/userscompose/ui/screens/users/components/UserItem.kt @@ -11,14 +11,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import coil.request.ImageRequest -import coil.transform.CircleCropTransformation import com.nullpointer.userscompose.R +import com.nullpointer.userscompose.core.utils.AsyncImageFade import com.nullpointer.userscompose.models.User @OptIn(ExperimentalFoundationApi::class) @@ -52,10 +49,12 @@ fun UserItem( .padding(10.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - ImageUser( - urlImg = user.imgUser, - modifier = Modifier.size(80.dp), - contentDescription = stringResource(R.string.description_img_user, user.name) + AsyncImageFade( + data = user.imgUser, + resourceLoading = R.drawable.ic_person, + resourceFailed = R.drawable.ic_broken_image, + contentDescription = stringResource(id = R.string.description_img_user, user.name), + modifier = Modifier.size(80.dp) ) Spacer(modifier = Modifier.height(10.dp)) Text( @@ -68,25 +67,3 @@ fun UserItem( } } -@Composable -private fun ImageUser( - urlImg: String, - modifier: Modifier = Modifier, - contentDescription: String -) { - - AsyncImage( - model = ImageRequest - .Builder(LocalContext.current) - .placeholder(R.drawable.ic_person) - .error(R.drawable.ic_broken_image) - .transformations(CircleCropTransformation()) - .data(urlImg) - .crossfade(true) - .build(), - contentDescription = contentDescription, - modifier = modifier - - ) - -} \ No newline at end of file diff --git a/app/src/main/java/com/nullpointer/userscompose/ui/share/ToolbarBack.kt b/app/src/main/java/com/nullpointer/userscompose/ui/share/ToolbarBack.kt index 92e234a..ea167aa 100644 --- a/app/src/main/java/com/nullpointer/userscompose/ui/share/ToolbarBack.kt +++ b/app/src/main/java/com/nullpointer/userscompose/ui/share/ToolbarBack.kt @@ -6,7 +6,10 @@ import androidx.annotation.PluralsRes import androidx.annotation.StringRes import androidx.compose.animation.animateColorAsState import androidx.compose.material.* -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @@ -45,12 +48,9 @@ fun SelectToolbar( ) { val (showMenu, changeVisibleMenu) = rememberSaveable { mutableStateOf(false) } - val title by remember(numberSelection) { - derivedStateOf { - if (numberSelection == 0) - context.getString(titleDefault) else - context.getPlural(titleSelection, numberSelection) - } + val title = remember(numberSelection) { + if (numberSelection == 0) + context.getString(titleDefault) else context.getPlural(titleSelection, numberSelection) } val toolbarColor by animateColorAsState(