Fixes layout issues of LongForm content when the image is not present.

This commit is contained in:
Vitor Pamplona
2024-03-20 16:02:49 -04:00
parent f2a8e51b20
commit 97cdc0bc7a
6 changed files with 122 additions and 100 deletions
@@ -22,17 +22,23 @@ package com.vitorpamplona.amethyst.ui.note.elements
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.Size55dp
import com.vitorpamplona.amethyst.ui.theme.authorNotePictureForImageHeader
@@ -43,28 +49,42 @@ fun DefaultImageHeader(
note: Note,
accountViewModel: AccountViewModel,
) {
Box {
note.author?.info?.banner?.let {
AsyncImage(
model = it,
contentDescription =
stringResource(
R.string.preview_card_image_for,
it,
),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
)
}
?: Image(
painter = painterResource(R.drawable.profile_banner),
contentDescription = stringResource(R.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = imageHeaderBannerSize,
)
val authorState by note.live().authorChanges.observeAsState(note.author)
Box(authorNotePictureForImageHeader.align(Alignment.BottomStart)) {
NoteAuthorPicture(baseNote = note, accountViewModel = accountViewModel, size = Size55dp)
authorState?.let { author ->
Box {
BannerImage(author)
Box(authorNotePictureForImageHeader.align(Alignment.BottomStart)) {
BaseUserPicture(author, Size55dp, accountViewModel, Modifier)
}
}
}
}
@Composable
private fun BoxScope.BannerImage(author: User) {
val currentInfo by author.live().userMetadataInfo.observeAsState()
currentInfo?.banner?.let {
AsyncImage(
model = it,
contentDescription =
stringResource(
R.string.preview_card_image_for,
it,
),
contentScale = ContentScale.FillWidth,
modifier =
Modifier
.fillMaxWidth()
.heightIn(max = 200.dp),
)
} ?: run {
Image(
painter = painterResource(R.drawable.profile_banner),
contentDescription = stringResource(R.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = imageHeaderBannerSize,
)
}
}
@@ -88,8 +88,9 @@ fun RenderClassifieds(
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
)
} ?: run {
DefaultImageHeader(note, accountViewModel)
}
?: DefaultImageHeader(note, accountViewModel)
}
Row(
@@ -127,8 +127,9 @@ private fun WikiNoteHeader(
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
)
} ?: run {
DefaultImageHeader(note, accountViewModel)
}
?: DefaultImageHeader(note, accountViewModel)
}
title?.let {
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.note.types
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -65,14 +64,14 @@ private fun LongFormHeader(
note: Note,
accountViewModel: AccountViewModel,
) {
val image = remember(noteEvent) { noteEvent.image() }
val title = remember(noteEvent) { noteEvent.title() }
val image = noteEvent.image()
val title = noteEvent.title()
val summary =
remember(noteEvent) {
noteEvent.summary()?.ifBlank { null } ?: noteEvent.content.take(200).ifBlank { null }
}
Row(
Column(
modifier =
Modifier
.padding(top = Size5dp)
@@ -83,51 +82,53 @@ private fun LongFormHeader(
QuoteBorder,
),
) {
Column {
val automaticallyShowUrlPreview =
remember { accountViewModel.settings.showUrlPreview.value }
val automaticallyShowUrlPreview =
remember { accountViewModel.settings.showImages.value }
if (automaticallyShowUrlPreview) {
image?.let {
AsyncImage(
model = it,
contentDescription =
stringResource(
R.string.preview_card_image_for,
it,
),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
)
}
?: DefaultImageHeader(note, accountViewModel)
}
title?.let {
Text(
text = it,
style = MaterialTheme.typography.bodyLarge,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 10.dp, end = 10.dp, top = 10.dp),
if (automaticallyShowUrlPreview) {
println("ImagePreview: $title $image")
image?.let {
println("ImagePreview: Drawing $title $image")
AsyncImage(
model = it,
contentDescription =
stringResource(
R.string.preview_card_image_for,
it,
),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
)
} ?: run {
println("ImagePreview: DefaultHeader $title $image")
DefaultImageHeader(note, accountViewModel)
}
}
summary?.let {
Spacer(modifier = StdVertSpacer)
Text(
text = it,
style = MaterialTheme.typography.bodySmall,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 10.dp, end = 10.dp, bottom = 10.dp),
color = Color.Gray,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
)
}
title?.let {
Text(
text = it,
style = MaterialTheme.typography.bodyLarge,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 10.dp, end = 10.dp, top = 10.dp),
)
}
summary?.let {
Spacer(modifier = StdVertSpacer)
Text(
text = it,
style = MaterialTheme.typography.bodySmall,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 10.dp, end = 10.dp, bottom = 10.dp),
color = Color.Gray,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
)
}
}
}
@@ -135,8 +135,9 @@ fun VideoDisplay(
contentScale = ContentScale.FillWidth,
modifier = MaterialTheme.colorScheme.imageModifier,
)
} ?: run {
DefaultImageHeader(note, accountViewModel)
}
?: DefaultImageHeader(note, accountViewModel)
}
} else {
ZoomableContentView(
@@ -789,43 +789,41 @@ private fun RenderClassifiedsReaderForThread(
@Composable
private fun RenderLongFormHeaderForThread(noteEvent: LongTextNoteEvent) {
Row(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp)) {
Column {
noteEvent.image()?.let {
AsyncImage(
model = it,
contentDescription =
stringResource(
R.string.preview_card_image_for,
it,
),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
)
}
Column(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp)) {
noteEvent.image()?.let {
AsyncImage(
model = it,
contentDescription =
stringResource(
R.string.preview_card_image_for,
it,
),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
)
}
noteEvent.title()?.let {
noteEvent.title()?.let {
Spacer(modifier = DoubleVertSpacer)
Text(
text = it,
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.fillMaxWidth(),
)
}
noteEvent
.summary()
?.ifBlank { null }
?.let {
Spacer(modifier = DoubleVertSpacer)
Text(
text = it,
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.fillMaxWidth(),
color = Color.Gray,
)
}
noteEvent
.summary()
?.ifBlank { null }
?.let {
Spacer(modifier = DoubleVertSpacer)
Text(
text = it,
modifier = Modifier.fillMaxWidth(),
color = Color.Gray,
)
}
}
}
}