refactor(chat): share inline attachment list (#1313) (#1350)

This commit is contained in:
m57 authored and GitHub committed 2026-09-28 11:29:12 +03:00
1 parent f2675e0b1a
commit af0c508c1f
3 files changed
+55 -34

No files matched your search

@@ -34,6 +34,39 @@ import androidx.compose.ui.unit.dp
import com.m57.hermescontrol.R
import com.m57.hermescontrol.data.model.Attachment
/**
* Renders a message's attachments, shared by user bubbles and agent messages.
* Emits directly into the caller's Column (no wrapper) so spacing is unchanged:
* 6dp before the list, 4dp after each item. Renders nothing when empty.
*/
@Composable
internal fun InlineAttachmentList(
attachments: List<Attachment>?,
textColor: Color,
onOpen: (Attachment) -> Unit,
onSave: (Attachment) -> Unit,
savingPath: String?,
openingPath: String?,
canSave: Boolean,
onImageClick: (ImageViewerModel) -> Unit,
) {
if (attachments.isNullOrEmpty()) return
Spacer(modifier = Modifier.height(6.dp))
attachments.forEach { attachment ->
InlineAttachment(
attachment = attachment,
textColor = textColor,
onOpen = onOpen,
onSave = onSave,
savingPath = savingPath,
openingPath = openingPath,
canSave = canSave,
onImageClick = onImageClick,
)
Spacer(modifier = Modifier.height(4.dp))
}
}
/**
* Renders an attachment inline inside a chat bubble.
* Images are displayed as thumbnails; other files show a compact card.
@@ -177,22 +177,16 @@ fun UserBubble(
)
}
// Render inline attachments
if (!message.attachments.isNullOrEmpty()) {
Spacer(modifier = Modifier.height(6.dp))
message.attachments.forEach { attachment ->
InlineAttachment(
attachment = attachment,
textColor = userBubbleTextColor,
onOpen = { onOpenAttachment(it) },
onSave = { onSaveAttachment(it) },
savingPath = savingAttachmentPath,
openingPath = openingAttachmentPath,
canSave = canSaveAttachment,
onImageClick = onImageClick,
)
Spacer(modifier = Modifier.height(4.dp))
}
}
InlineAttachmentList(
attachments = message.attachments,
textColor = userBubbleTextColor,
onOpen = onOpenAttachment,
onSave = onSaveAttachment,
savingPath = savingAttachmentPath,
openingPath = openingAttachmentPath,
canSave = canSaveAttachment,
onImageClick = onImageClick,
)
if (!message.isStreaming) {
FlowRow(
modifier =
@@ -36,7 +36,7 @@ import com.m57.hermescontrol.R
import com.m57.hermescontrol.data.model.Attachment
import com.m57.hermescontrol.ui.chat.ChatMessage
import com.m57.hermescontrol.ui.chat.ImageViewerModel
import com.m57.hermescontrol.ui.chat.InlineAttachment
import com.m57.hermescontrol.ui.chat.InlineAttachmentList
import com.m57.hermescontrol.ui.chat.MarkdownText
import com.m57.hermescontrol.ui.chat.TokenEstimator
import com.m57.hermescontrol.ui.chat.components.ReasoningCard
@@ -109,24 +109,18 @@ internal fun FullBleedAgentMessage(
}
}
// Render inline attachments (mirrors ChatBubble so agent-delivered
// Inline attachments (shared with UserBubble so agent-delivered
// media — images, files — shows in full-bleed mode too).
if (!message.attachments.isNullOrEmpty()) {
Spacer(modifier = Modifier.height(6.dp))
message.attachments.forEach { attachment ->
InlineAttachment(
attachment = attachment,
textColor = textColor,
onOpen = { onOpenAttachment(it) },
onSave = { onSaveAttachment(it) },
savingPath = savingAttachmentPath,
openingPath = openingAttachmentPath,
canSave = canSaveAttachment,
onImageClick = onImageClick,
)
Spacer(modifier = Modifier.height(4.dp))
}
}
InlineAttachmentList(
attachments = message.attachments,
textColor = textColor,
onOpen = onOpenAttachment,
onSave = onSaveAttachment,
savingPath = savingAttachmentPath,
openingPath = openingAttachmentPath,
canSave = canSaveAttachment,
onImageClick = onImageClick,
)
if (!message.isStreaming && message.content.isNotBlank()) {
val showTokenStat =