porting image bubble to design system
This commit is contained in:
parent
9ba6d70daa
commit
d17ee34d78
|
@ -1,5 +1,7 @@
|
|||
package app.dapk.st.design.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -8,11 +10,18 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.rememberAsyncImagePainter
|
||||
import coil.request.ImageRequest
|
||||
|
||||
data class Event(val authorName: String, val edited: Boolean, val time: String)
|
||||
data class ImageContent(val width: Int?, val height: Int?, val url: String)
|
||||
|
||||
@Composable
|
||||
fun Bubble(bubble: BubbleMeta, content: @Composable () -> Unit) {
|
||||
|
@ -30,7 +39,7 @@ fun Bubble(bubble: BubbleMeta, content: @Composable () -> Unit) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun TextBubbleContent(bubble: BubbleMeta, event: Event, textContent: String, status: @Composable () -> Unit) {
|
||||
fun TextBubble(bubble: BubbleMeta, event: Event, textContent: String, status: @Composable () -> Unit) {
|
||||
Bubble(bubble) {
|
||||
Column(
|
||||
Modifier
|
||||
|
@ -39,23 +48,68 @@ fun TextBubbleContent(bubble: BubbleMeta, event: Event, textContent: String, sta
|
|||
.defaultMinSize(minWidth = 50.dp)
|
||||
) {
|
||||
if (bubble.isNotSelf()) {
|
||||
Text(
|
||||
fontSize = 11.sp,
|
||||
text = event.authorName,
|
||||
maxLines = 1,
|
||||
color = bubble.textColor()
|
||||
)
|
||||
AuthorName(event, bubble)
|
||||
}
|
||||
Text(
|
||||
text = textContent,
|
||||
color = bubble.textColor(),
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
textAlign = TextAlign.Start,
|
||||
TextContent(bubble, text = textContent)
|
||||
Footer(event, bubble, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EncryptedBubble(bubble: BubbleMeta, event: Event, status: @Composable () -> Unit) {
|
||||
TextBubble(bubble, event, textContent = "Encrypted message", status)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ImageBubble(bubble: BubbleMeta, event: Event, imageContent: ImageContent, status: @Composable () -> Unit, imageRequest: ImageRequest) {
|
||||
Bubble(bubble) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
.width(IntrinsicSize.Max)
|
||||
.defaultMinSize(minWidth = 50.dp)
|
||||
) {
|
||||
if (bubble.isNotSelf()) {
|
||||
AuthorName(event, bubble)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Image(
|
||||
modifier = Modifier.size(imageContent.scale(LocalDensity.current, LocalConfiguration.current)),
|
||||
painter = rememberAsyncImagePainter(model = imageRequest),
|
||||
contentDescription = null,
|
||||
)
|
||||
Footer(event, bubble, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImageContent.scale(density: Density, configuration: Configuration): DpSize {
|
||||
val height = this@scale.height ?: 250
|
||||
val width = this@scale.width ?: 250
|
||||
return with(density) {
|
||||
val scaler = minOf(
|
||||
height.scalerFor(configuration.screenHeightDp.dp.toPx() * 0.5f),
|
||||
width.scalerFor(configuration.screenWidthDp.dp.toPx() * 0.6f)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Row(horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
DpSize(
|
||||
width = (width * scaler).toDp(),
|
||||
height = (height * scaler).toDp(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun Int.scalerFor(max: Float): Float {
|
||||
return max / this
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun Footer(event: Event, bubble: BubbleMeta, status: @Composable () -> Unit) {
|
||||
Row(horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(top = 2.dp)) {
|
||||
val editedPrefix = if (event.edited) "(edited) " else null
|
||||
Text(
|
||||
fontSize = 9.sp,
|
||||
|
@ -67,7 +121,26 @@ fun TextBubbleContent(bubble: BubbleMeta, event: Event, textContent: String, sta
|
|||
status()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextContent(bubble: BubbleMeta, text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
color = bubble.textColor(),
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AuthorName(event: Event, bubble: BubbleMeta) {
|
||||
Text(
|
||||
fontSize = 11.sp,
|
||||
text = event.authorName,
|
||||
maxLines = 1,
|
||||
color = bubble.textColor()
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -198,67 +198,19 @@ private fun ColumnScope.RoomContent(self: UserId, state: RoomState, replyActions
|
|||
val event = Event(item.author.displayName ?: item.author.id.value, item.edited, item.time)
|
||||
val status = @Composable { SendStatus(item) }
|
||||
when (item) {
|
||||
is RoomEvent.Image -> MessageImage(this, item)
|
||||
is RoomEvent.Message -> TextBubbleContent(this, event, item.content, status = status)
|
||||
is RoomEvent.Reply -> ReplyBubbleContent(this, item)
|
||||
is RoomEvent.Encrypted -> EncryptedBubbleContent(this, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MessageImage(bubble: BubbleMeta, event: RoomEvent.Image) {
|
||||
is RoomEvent.Image -> {
|
||||
val context = LocalContext.current
|
||||
|
||||
Box(modifier = Modifier.padding(start = 6.dp)) {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.clip(bubble.shape)
|
||||
.background(bubble.background)
|
||||
.height(IntrinsicSize.Max),
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
.width(IntrinsicSize.Max)
|
||||
.defaultMinSize(minWidth = 50.dp)
|
||||
) {
|
||||
if (bubble.isNotSelf()) {
|
||||
Text(
|
||||
fontSize = 11.sp,
|
||||
text = event.author.displayName ?: event.author.id.value,
|
||||
maxLines = 1,
|
||||
color = bubble.textColor()
|
||||
)
|
||||
val imageRequest = ImageRequest.Builder(context)
|
||||
.fetcherFactory(LocalDecyptingFetcherFactory.current)
|
||||
.memoryCacheKey(item.imageMeta.url)
|
||||
.data(item)
|
||||
.build()
|
||||
ImageBubble(this, event, ImageContent(item.imageMeta.width, item.imageMeta.height, item.imageMeta.url), status, imageRequest)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Image(
|
||||
modifier = Modifier.size(event.imageMeta.scale(LocalDensity.current, LocalConfiguration.current)),
|
||||
painter = rememberAsyncImagePainter(
|
||||
model = ImageRequest.Builder(context)
|
||||
.fetcherFactory(LocalDecyptingFetcherFactory.current)
|
||||
.memoryCacheKey(event.imageMeta.url)
|
||||
.data(event)
|
||||
.build()
|
||||
),
|
||||
contentDescription = null,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
Row(horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
val editedPrefix = if (event.edited) "(edited) " else null
|
||||
Text(
|
||||
fontSize = 9.sp,
|
||||
text = "${editedPrefix ?: ""}${event.time}",
|
||||
textAlign = TextAlign.End,
|
||||
color = bubble.textColor(),
|
||||
modifier = Modifier.wrapContentSize()
|
||||
)
|
||||
SendStatus(event)
|
||||
is RoomEvent.Message -> TextBubble(this, event, item.content, status = status)
|
||||
is RoomEvent.Reply -> ReplyBubble(this, item)
|
||||
is RoomEvent.Encrypted -> EncryptedBubble(this, event, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -292,55 +244,7 @@ private fun BubbleMeta.textColor(): Color {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun EncryptedBubbleContent(bubble: BubbleMeta, event: RoomEvent.Encrypted) {
|
||||
Box(modifier = Modifier.padding(start = 6.dp)) {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.clip(bubble.shape)
|
||||
.background(bubble.background)
|
||||
.height(IntrinsicSize.Max),
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
.width(IntrinsicSize.Max)
|
||||
.defaultMinSize(minWidth = 50.dp)
|
||||
) {
|
||||
if (bubble.isNotSelf()) {
|
||||
Text(
|
||||
fontSize = 11.sp,
|
||||
text = event.author.displayName ?: event.author.id.value,
|
||||
maxLines = 1,
|
||||
color = bubble.textColor()
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "Encrypted message",
|
||||
color = bubble.textColor(),
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Row(horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
fontSize = 9.sp,
|
||||
text = event.time,
|
||||
textAlign = TextAlign.End,
|
||||
color = bubble.textColor(),
|
||||
modifier = Modifier.wrapContentSize()
|
||||
)
|
||||
SendStatus(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReplyBubbleContent(bubble: BubbleMeta, event: RoomEvent.Reply) {
|
||||
private fun ReplyBubble(bubble: BubbleMeta, event: RoomEvent.Reply) {
|
||||
Box(modifier = Modifier.padding(start = 6.dp)) {
|
||||
Box(
|
||||
Modifier
|
||||
|
|
Loading…
Reference in New Issue