feat(profile): show user banner

This commit is contained in:
Diego Beraldin 2023-08-11 22:56:11 +02:00
parent a25a930085
commit 63b46867e4
10 changed files with 112 additions and 47 deletions

View File

@ -129,7 +129,7 @@ class CommunityDetailScreen(
val communityIcon = community.icon.orEmpty()
val communityTitle = community.title
val iconSize = 50.dp
val iconSize = 80.dp
Box(
modifier = Modifier.fillMaxWidth(),
) {

View File

@ -24,10 +24,11 @@ import dev.icerock.moko.resources.compose.stringResource
@Composable
fun UserCounters(
modifier: Modifier = Modifier,
user: UserModel,
) {
Row(
modifier = Modifier.padding(horizontal = Spacing.m).fillMaxWidth(),
modifier = modifier.padding(horizontal = Spacing.m).fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
) {

View File

@ -1,7 +1,11 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
@ -11,7 +15,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
import io.kamel.image.KamelImage
@ -21,38 +28,74 @@ import io.kamel.image.asyncPainterResource
fun UserHeader(
user: UserModel,
) {
val avatar = user.avatar.orEmpty()
val profileImageSize = 100.dp
if (avatar.isNotEmpty()) {
val painterResource = asyncPainterResource(data = avatar)
KamelImage(
modifier = Modifier.size(profileImageSize)
.clip(RoundedCornerShape(profileImageSize / 2)),
resource = painterResource,
contentDescription = null,
)
} else {
Box(
modifier = Modifier.padding(Spacing.xxxs).size(profileImageSize)
.background(
color = MaterialTheme.colorScheme.primary,
shape = RoundedCornerShape(profileImageSize / 2),
),
contentAlignment = Alignment.Center,
val userAvatar = user.avatar.orEmpty()
val userDisplayName = user.name
val iconSize = 80.dp
Box(
modifier = Modifier.fillMaxWidth(),
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = user.name.firstOrNull()?.toString().orEmpty().uppercase(),
style = MaterialTheme.typography.headlineLarge,
color = MaterialTheme.colorScheme.onPrimary,
)
val banner = user.banner.orEmpty()
if (banner.isNotEmpty()) {
val painterResource = asyncPainterResource(banner)
KamelImage(
modifier = Modifier.fillMaxWidth().aspectRatio(2.25f),
resource = painterResource,
contentScale = ContentScale.FillBounds,
contentDescription = null,
)
} else {
Box(
modifier = Modifier.fillMaxWidth().aspectRatio(2.5f),
)
}
Column(
modifier = Modifier.graphicsLayer(translationY = -(iconSize / 2).toLocalPixel()),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) {
if (userAvatar.isNotEmpty()) {
val painterResource =
asyncPainterResource(data = userAvatar)
KamelImage(
modifier = Modifier.padding(Spacing.xxxs).size(iconSize)
.clip(RoundedCornerShape(iconSize / 2)),
resource = painterResource,
contentDescription = null,
contentScale = ContentScale.FillBounds,
)
} else {
Box(
modifier = Modifier.padding(Spacing.xxxs)
.size(iconSize)
.background(
color = MaterialTheme.colorScheme.primary,
shape = RoundedCornerShape(iconSize / 2),
),
contentAlignment = Alignment.Center,
) {
Text(
text = user.name.firstOrNull()?.toString()
.orEmpty()
.uppercase(),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onPrimary,
)
}
}
Text(
text = buildString {
append(userDisplayName)
},
style = MaterialTheme.typography.headlineSmall,
)
Text(
text = user.host,
style = MaterialTheme.typography.titleMedium,
)
}
}
}
Text(
text = user.name,
style = MaterialTheme.typography.headlineSmall,
)
Text(
text = user.host,
style = MaterialTheme.typography.titleMedium,
)
}

View File

@ -5,10 +5,8 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
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.lazy.LazyColumn
@ -40,11 +38,13 @@ import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserCounters
@ -88,8 +88,10 @@ internal class UserDetailCommentsScreen(
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
UserHeader(user = uiState.user)
UserCounters(user = uiState.user)
Spacer(modifier = Modifier.height(Spacing.xxs))
UserCounters(
modifier = Modifier.graphicsLayer(translationY = -Spacing.m.toLocalPixel()),
user = uiState.user,
)
SectionSelector(
currentSection = UserDetailSection.COMMENTS,
onSectionSelected = {

View File

@ -40,6 +40,7 @@ import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
@ -47,6 +48,7 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
@ -96,8 +98,11 @@ internal class UserDetailPostsScreen(
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
UserHeader(user = uiState.user)
UserCounters(user = uiState.user)
Spacer(modifier = Modifier.height(Spacing.xxs))
UserCounters(
modifier = Modifier.graphicsLayer(translationY = -Spacing.m.toLocalPixel()),
user = uiState.user,
)
Spacer(modifier = Modifier.height(Spacing.s))
SectionSelector(
currentSection = UserDetailSection.POSTS,
onSectionSelected = {

View File

@ -4,6 +4,7 @@ data class UserModel(
val id: Int = 0,
val name: String = "",
val avatar: String? = null,
val banner: String? = null,
val host: String = "",
val score: UserScoreModel? = null,
val accountAge: String = "",

View File

@ -26,6 +26,7 @@ class UserRepository(
id = dto.personView.person.id,
name = dto.personView.person.name,
avatar = dto.personView.person.avatar,
banner = dto.personView.person.banner,
host = dto.personView.person.actorId.toHost(),
score = dto.personView.counts.toModel(),
accountAge = dto.personView.person.published,

View File

@ -22,9 +22,11 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.UserCounters
@ -62,8 +64,11 @@ internal class ProfileCommentsScreen(
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
UserHeader(user = user)
UserCounters(user = user)
Spacer(modifier = Modifier.height(Spacing.xxs))
UserCounters(
modifier = Modifier.graphicsLayer(translationY = -Spacing.m.toLocalPixel()),
user = user,
)
Spacer(modifier = Modifier.height(Spacing.s))
SectionSelector(
currentSection = ProfileLoggedSection.COMMENTS,
onSectionSelected = {

View File

@ -22,11 +22,13 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
@ -70,8 +72,11 @@ internal class ProfilePostsScreen(
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
UserHeader(user = user)
UserCounters(user = user)
Spacer(modifier = Modifier.height(Spacing.xxs))
UserCounters(
modifier = Modifier.graphicsLayer(translationY = -Spacing.m.toLocalPixel()),
user = user,
)
Spacer(modifier = Modifier.height(Spacing.s))
SectionSelector(
currentSection = ProfileLoggedSection.POSTS,
onSectionSelected = {

View File

@ -3,10 +3,8 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.profile.content.logged.
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
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.lazy.LazyColumn
@ -22,11 +20,13 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import com.github.diegoberaldin.racconforlemmy.core.utils.toLocalPixel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
@ -73,8 +73,10 @@ internal class ProfileSavedScreen(
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
UserHeader(user = user)
UserCounters(user = user)
Spacer(modifier = Modifier.height(Spacing.xxs))
UserCounters(
modifier = Modifier.graphicsLayer(translationY = -Spacing.m.toLocalPixel()),
user = user,
)
SectionSelector(
currentSection = ProfileLoggedSection.SAVED,
onSectionSelected = {