@@ -34,6 +34,39 @@ import androidx.compose.ui.unit.dp
|
|||||||
import com.m57.hermescontrol.R
|
import com.m57.hermescontrol.R
|
||||||
import com.m57.hermescontrol.data.model.Attachment
|
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.
|
* Renders an attachment inline inside a chat bubble.
|
||||||
* Images are displayed as thumbnails; other files show a compact card.
|
* Images are displayed as thumbnails; other files show a compact card.
|
||||||
|
|||||||
@@ -177,22 +177,16 @@ fun UserBubble(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Render inline attachments
|
// Render inline attachments
|
||||||
if (!message.attachments.isNullOrEmpty()) {
|
InlineAttachmentList(
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
attachments = message.attachments,
|
||||||
message.attachments.forEach { attachment ->
|
|
||||||
InlineAttachment(
|
|
||||||
attachment = attachment,
|
|
||||||
textColor = userBubbleTextColor,
|
textColor = userBubbleTextColor,
|
||||||
onOpen = { onOpenAttachment(it) },
|
onOpen = onOpenAttachment,
|
||||||
onSave = { onSaveAttachment(it) },
|
onSave = onSaveAttachment,
|
||||||
savingPath = savingAttachmentPath,
|
savingPath = savingAttachmentPath,
|
||||||
openingPath = openingAttachmentPath,
|
openingPath = openingAttachmentPath,
|
||||||
canSave = canSaveAttachment,
|
canSave = canSaveAttachment,
|
||||||
onImageClick = onImageClick,
|
onImageClick = onImageClick,
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!message.isStreaming) {
|
if (!message.isStreaming) {
|
||||||
FlowRow(
|
FlowRow(
|
||||||
modifier =
|
modifier =
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import com.m57.hermescontrol.R
|
|||||||
import com.m57.hermescontrol.data.model.Attachment
|
import com.m57.hermescontrol.data.model.Attachment
|
||||||
import com.m57.hermescontrol.ui.chat.ChatMessage
|
import com.m57.hermescontrol.ui.chat.ChatMessage
|
||||||
import com.m57.hermescontrol.ui.chat.ImageViewerModel
|
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.MarkdownText
|
||||||
import com.m57.hermescontrol.ui.chat.TokenEstimator
|
import com.m57.hermescontrol.ui.chat.TokenEstimator
|
||||||
import com.m57.hermescontrol.ui.chat.components.ReasoningCard
|
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).
|
// media — images, files — shows in full-bleed mode too).
|
||||||
if (!message.attachments.isNullOrEmpty()) {
|
InlineAttachmentList(
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
attachments = message.attachments,
|
||||||
message.attachments.forEach { attachment ->
|
|
||||||
InlineAttachment(
|
|
||||||
attachment = attachment,
|
|
||||||
textColor = textColor,
|
textColor = textColor,
|
||||||
onOpen = { onOpenAttachment(it) },
|
onOpen = onOpenAttachment,
|
||||||
onSave = { onSaveAttachment(it) },
|
onSave = onSaveAttachment,
|
||||||
savingPath = savingAttachmentPath,
|
savingPath = savingAttachmentPath,
|
||||||
openingPath = openingAttachmentPath,
|
openingPath = openingAttachmentPath,
|
||||||
canSave = canSaveAttachment,
|
canSave = canSaveAttachment,
|
||||||
onImageClick = onImageClick,
|
onImageClick = onImageClick,
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!message.isStreaming && message.content.isNotBlank()) {
|
if (!message.isStreaming && message.content.isNotBlank()) {
|
||||||
val showTokenStat =
|
val showTokenStat =
|
||||||
|
|||||||
Reference in New Issue
Block a user