Чат, вложения

This commit is contained in:
Халимов Рустам
2026-04-14 21:53:44 +03:00
parent 118f8b8971
commit 58fdf1aca1
22 changed files with 799 additions and 125 deletions
@@ -69,8 +69,7 @@ fun MessageBubble(
RoundedCornerShape(16.dp, 16.dp, 16.dp, 4.dp)
}
val isVoiceMessage = message.mediaType == MediaType.AUDIO &&
(message.content == null || message.content.isEmpty())
val isVoiceMessage = message.media.any { it.type == "voice" } || (message.mediaType == MediaType.AUDIO && (message.content == null || message.content.isEmpty()))
Row(
modifier = Modifier
@@ -225,7 +224,8 @@ fun MessageBubble(
} else {
// Multi-media grid
PhotoGrid(
message.media,
mediaList = message.media,
isCurrentUser = isCurrentUser,
onMediaClick = { index -> onMediaClick(message.media[index]) },
modifier = Modifier.fillMaxWidth().height(300.dp).clip(RoundedCornerShape(12.dp))
)
@@ -365,30 +365,88 @@ fun FileItem(media: Media, isCurrentUser: Boolean, contentColor: Color) {
}
@Composable
fun PhotoGrid(media: List<Media>, onMediaClick: (Int) -> Unit, modifier: Modifier = Modifier) {
val items = media.take(4)
fun PhotoGrid(mediaList: List<Media>, isCurrentUser: Boolean, onMediaClick: (Int) -> Unit, modifier: Modifier = Modifier) {
if (mediaList.isEmpty()) return
val columns = when {
mediaList.size == 1 -> 1
mediaList.size % 3 == 0 -> 3
else -> 2
}
Column(modifier = modifier) {
val rows = (items.size + 1) / 2
val rows = (mediaList.size + columns - 1) / columns
for (i in 0 until rows) {
Row(modifier = Modifier.weight(1f)) {
val firstIndex = i * 2
AsyncImage(
model = items[firstIndex].url,
contentDescription = null,
modifier = Modifier.weight(1f).fillMaxHeight().padding(1.dp).clickable { onMediaClick(firstIndex) },
contentScale = ContentScale.Crop
)
if (firstIndex + 1 < items.size) {
AsyncImage(
model = items[firstIndex + 1].url,
contentDescription = null,
modifier = Modifier.weight(1f).fillMaxHeight().padding(1.dp).clickable { onMediaClick(firstIndex + 1) },
contentScale = ContentScale.Crop
)
} else if (rows > 1) {
Spacer(modifier = Modifier.weight(1f))
Row(modifier = Modifier.weight(1f).fillMaxWidth()) {
for (j in 0 until columns) {
val index = i * columns + j
if (index < mediaList.size) {
GridItem(
media = mediaList[index],
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.padding(1.dp)
.clickable { onMediaClick(index) }
)
} else {
Spacer(modifier = Modifier.weight(1f))
}
}
}
}
}
}
@Composable
fun GridItem(media: Media, modifier: Modifier = Modifier) {
val context = LocalContext.current
val isImage = media.type.startsWith("image")
val isVideo = media.type.startsWith("video")
Box(modifier = modifier.background(Color.White.copy(alpha = 0.1f))) {
if (isImage || isVideo) {
AsyncImage(
model = media.url,
contentDescription = null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
if (isVideo) {
Icon(
imageVector = Icons.Default.PlayCircle,
contentDescription = null,
tint = Color.White.copy(alpha = 0.8f),
modifier = Modifier.align(Alignment.Center).size(32.dp)
)
}
} else {
Column(
modifier = Modifier.fillMaxSize().padding(4.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Icon(
imageVector = Icons.Default.InsertDriveFile,
contentDescription = null,
tint = Color.White.copy(alpha = 0.7f),
modifier = Modifier.size(32.dp)
)
Text(
text = media.filename ?: "File",
style = MaterialTheme.typography.labelSmall,
color = Color.White.copy(alpha = 0.9f),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = androidx.compose.ui.text.style.TextAlign.Center
)
Text(
text = media.url.substringAfterLast(".").uppercase(),
style = MaterialTheme.typography.labelSmall,
color = Color.White.copy(alpha = 0.5f),
fontSize = 8.sp
)
}
}
}
}