porting image bubble to design system

This commit is contained in:
Adam Brown 2022-10-18 22:25:52 +01:00
parent 9ba6d70daa
commit d17ee34d78
2 changed files with 111 additions and 134 deletions

View File

@ -1,5 +1,7 @@
package app.dapk.st.design.components 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.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -8,11 +10,18 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color 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.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.dp
import androidx.compose.ui.unit.sp 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 Event(val authorName: String, val edited: Boolean, val time: String)
data class ImageContent(val width: Int?, val height: Int?, val url: String)
@Composable @Composable
fun Bubble(bubble: BubbleMeta, content: @Composable () -> Unit) { fun Bubble(bubble: BubbleMeta, content: @Composable () -> Unit) {
@ -30,7 +39,7 @@ fun Bubble(bubble: BubbleMeta, content: @Composable () -> Unit) {
} }
@Composable @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) { Bubble(bubble) {
Column( Column(
Modifier Modifier
@ -39,37 +48,101 @@ fun TextBubbleContent(bubble: BubbleMeta, event: Event, textContent: String, sta
.defaultMinSize(minWidth = 50.dp) .defaultMinSize(minWidth = 50.dp)
) { ) {
if (bubble.isNotSelf()) { if (bubble.isNotSelf()) {
Text( AuthorName(event, bubble)
fontSize = 11.sp,
text = event.authorName,
maxLines = 1,
color = bubble.textColor()
)
}
Text(
text = textContent,
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()) {
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()
)
status()
} }
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)
)
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,
text = "${editedPrefix ?: ""}${event.time}",
textAlign = TextAlign.End,
color = bubble.textColor(),
modifier = Modifier.wrapContentSize()
)
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 @Composable
private fun BubbleMeta.textColor(): Color { private fun BubbleMeta.textColor(): Color {
return if (this.isSelf) SmallTalkTheme.extendedColors.onSelfBubble else SmallTalkTheme.extendedColors.onOthersBubble return if (this.isSelf) SmallTalkTheme.extendedColors.onSelfBubble else SmallTalkTheme.extendedColors.onOthersBubble

View File

@ -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 event = Event(item.author.displayName ?: item.author.id.value, item.edited, item.time)
val status = @Composable { SendStatus(item) } val status = @Composable { SendStatus(item) }
when (item) { when (item) {
is RoomEvent.Image -> MessageImage(this, item) is RoomEvent.Image -> {
is RoomEvent.Message -> TextBubbleContent(this, event, item.content, status = status) val context = LocalContext.current
is RoomEvent.Reply -> ReplyBubbleContent(this, item) val imageRequest = ImageRequest.Builder(context)
is RoomEvent.Encrypted -> EncryptedBubbleContent(this, item)
}
}
}
}
}
@Composable
private fun MessageImage(bubble: BubbleMeta, event: 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()
)
}
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) .fetcherFactory(LocalDecyptingFetcherFactory.current)
.memoryCacheKey(event.imageMeta.url) .memoryCacheKey(item.imageMeta.url)
.data(event) .data(item)
.build() .build()
), ImageBubble(this, event, ImageContent(item.imageMeta.width, item.imageMeta.height, item.imageMeta.url), status, imageRequest)
contentDescription = null, }
)
Spacer(modifier = Modifier.height(4.dp))
Row(horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { is RoomEvent.Message -> TextBubble(this, event, item.content, status = status)
val editedPrefix = if (event.edited) "(edited) " else null is RoomEvent.Reply -> ReplyBubble(this, item)
Text( is RoomEvent.Encrypted -> EncryptedBubble(this, event, status)
fontSize = 9.sp,
text = "${editedPrefix ?: ""}${event.time}",
textAlign = TextAlign.End,
color = bubble.textColor(),
modifier = Modifier.wrapContentSize()
)
SendStatus(event)
} }
} }
} }
@ -292,55 +244,7 @@ private fun BubbleMeta.textColor(): Color {
} }
@Composable @Composable
private fun EncryptedBubbleContent(bubble: BubbleMeta, event: RoomEvent.Encrypted) { private fun ReplyBubble(bubble: BubbleMeta, event: RoomEvent.Reply) {
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) {
Box(modifier = Modifier.padding(start = 6.dp)) { Box(modifier = Modifier.padding(start = 6.dp)) {
Box( Box(
Modifier Modifier