Skip to content

Commit ce0f5fe

Browse files
committed
feat(chat): add MessageItem and StreamingMessageItem components for chat message display #453
1 parent ae65f49 commit ce0f5fe

File tree

2 files changed

+128
-125
lines changed

2 files changed

+128
-125
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package cc.unitmesh.devins.ui.compose.chat
2+
3+
import androidx.compose.foundation.layout.*
4+
import androidx.compose.material3.CircularProgressIndicator
5+
import androidx.compose.material3.MaterialTheme
6+
import androidx.compose.material3.Text
7+
import androidx.compose.runtime.Composable
8+
import androidx.compose.ui.Alignment
9+
import androidx.compose.ui.Modifier
10+
import androidx.compose.ui.unit.dp
11+
import cc.unitmesh.devins.llm.Message
12+
import cc.unitmesh.devins.llm.MessageRole
13+
import cc.unitmesh.devins.ui.compose.sketch.SketchRenderer
14+
15+
/**
16+
* 单条消息项 - 使用统一的连续流式布局
17+
*/
18+
@Composable
19+
fun MessageItem(message: Message) {
20+
Column(
21+
modifier = Modifier.Companion.fillMaxWidth()
22+
) {
23+
// 消息标签
24+
MessageLabel(
25+
role = message.role,
26+
modifier = Modifier.Companion.padding(vertical = 4.dp)
27+
)
28+
29+
// 消息内容 - 统一使用 SketchRenderer
30+
when (message.role) {
31+
MessageRole.SYSTEM -> {
32+
// 系统消息使用简单样式
33+
Text(
34+
text = message.content,
35+
style = MaterialTheme.typography.bodySmall,
36+
color = MaterialTheme.colorScheme.onSurfaceVariant,
37+
modifier = Modifier.Companion.padding(start = 32.dp, bottom = 8.dp)
38+
)
39+
}
40+
41+
else -> {
42+
// 用户和 AI 消息都使用 SketchRenderer
43+
Box(
44+
modifier = Modifier.Companion
45+
.fillMaxWidth()
46+
.padding(start = 32.dp)
47+
) {
48+
SketchRenderer.RenderResponse(
49+
content = message.content,
50+
isComplete = true,
51+
modifier = Modifier.Companion.fillMaxWidth()
52+
)
53+
}
54+
}
55+
}
56+
}
57+
}
58+
59+
/**
60+
* 流式输出消息项
61+
*/
62+
@Composable
63+
fun StreamingMessageItem(
64+
content: String,
65+
onContentUpdate: (blockCount: Int) -> Unit = {}
66+
) {
67+
Column(
68+
modifier = Modifier.fillMaxWidth()
69+
) {
70+
// AI 标签(带加载指示)
71+
Row(
72+
modifier = Modifier.padding(vertical = 4.dp),
73+
horizontalArrangement = Arrangement.spacedBy(8.dp),
74+
verticalAlignment = Alignment.CenterVertically
75+
) {
76+
Text(
77+
text = "🤖",
78+
style = MaterialTheme.typography.titleSmall
79+
)
80+
Text(
81+
text = "AI Assistant",
82+
style = MaterialTheme.typography.titleSmall,
83+
color = MaterialTheme.colorScheme.primary
84+
)
85+
CircularProgressIndicator(
86+
modifier = Modifier.size(12.dp),
87+
strokeWidth = 2.dp
88+
)
89+
}
90+
91+
Box(modifier = Modifier.fillMaxWidth().padding(start = 32.dp)) {
92+
SketchRenderer.RenderResponse(
93+
content = content,
94+
isComplete = false,
95+
onContentUpdate = onContentUpdate,
96+
modifier = Modifier.Companion.fillMaxWidth()
97+
)
98+
}
99+
}
100+
}
101+
102+
@Composable
103+
fun MessageLabel(
104+
role: MessageRole,
105+
modifier: Modifier = Modifier.Companion
106+
) {
107+
val (icon, label, color) = when (role) {
108+
MessageRole.USER -> Triple("👤", "You", MaterialTheme.colorScheme.secondary)
109+
MessageRole.ASSISTANT -> Triple("🤖", "AI Assistant", MaterialTheme.colorScheme.primary)
110+
MessageRole.SYSTEM -> Triple("⚙️", "System", MaterialTheme.colorScheme.tertiary)
111+
}
112+
113+
Row(
114+
modifier = modifier,
115+
horizontalArrangement = Arrangement.spacedBy(8.dp),
116+
verticalAlignment = Alignment.Companion.CenterVertically
117+
) {
118+
Text(
119+
text = icon,
120+
style = MaterialTheme.typography.titleSmall
121+
)
122+
Text(
123+
text = label,
124+
style = MaterialTheme.typography.titleSmall,
125+
color = color
126+
)
127+
}
128+
}

mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/chat/MessageList.kt

Lines changed: 0 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ import androidx.compose.material3.*
88
import androidx.compose.runtime.*
99
import androidx.compose.ui.Alignment
1010
import androidx.compose.ui.Modifier
11-
import androidx.compose.ui.text.font.FontFamily
1211
import androidx.compose.ui.unit.dp
1312
import cc.unitmesh.devins.filesystem.ProjectFileSystem
1413
import cc.unitmesh.devins.llm.Message
15-
import cc.unitmesh.devins.llm.MessageRole
16-
import cc.unitmesh.devins.ui.compose.sketch.SketchRenderer
1714
import kotlinx.coroutines.delay
1815
import kotlinx.coroutines.launch
1916

@@ -145,128 +142,6 @@ fun MessageList(
145142
}
146143
}
147144

148-
/**
149-
* 单条消息项 - 使用统一的连续流式布局
150-
*/
151-
@Composable
152-
private fun MessageItem(message: Message) {
153-
Column(
154-
modifier = Modifier.fillMaxWidth()
155-
) {
156-
// 消息标签
157-
MessageLabel(
158-
role = message.role,
159-
modifier = Modifier.padding(vertical = 4.dp)
160-
)
161-
162-
// 消息内容 - 统一使用 SketchRenderer
163-
when (message.role) {
164-
MessageRole.SYSTEM -> {
165-
// 系统消息使用简单样式
166-
Text(
167-
text = message.content,
168-
style = MaterialTheme.typography.bodySmall,
169-
color = MaterialTheme.colorScheme.onSurfaceVariant,
170-
modifier = Modifier.padding(start = 32.dp, bottom = 8.dp)
171-
)
172-
}
173-
else -> {
174-
// 用户和 AI 消息都使用 SketchRenderer
175-
Box(
176-
modifier = Modifier
177-
.fillMaxWidth()
178-
.padding(start = 32.dp)
179-
) {
180-
SketchRenderer.RenderResponse(
181-
content = message.content,
182-
isComplete = true,
183-
modifier = Modifier.fillMaxWidth()
184-
)
185-
}
186-
}
187-
}
188-
}
189-
}
190-
191-
/**
192-
* 流式输出消息项
193-
*/
194-
@Composable
195-
private fun StreamingMessageItem(
196-
content: String,
197-
onContentUpdate: (blockCount: Int) -> Unit = {}
198-
) {
199-
Column(
200-
modifier = Modifier.fillMaxWidth()
201-
) {
202-
// AI 标签(带加载指示)
203-
Row(
204-
modifier = Modifier.padding(vertical = 4.dp),
205-
horizontalArrangement = Arrangement.spacedBy(8.dp),
206-
verticalAlignment = Alignment.CenterVertically
207-
) {
208-
Text(
209-
text = "🤖",
210-
style = MaterialTheme.typography.titleSmall
211-
)
212-
Text(
213-
text = "AI Assistant",
214-
style = MaterialTheme.typography.titleSmall,
215-
color = MaterialTheme.colorScheme.primary
216-
)
217-
CircularProgressIndicator(
218-
modifier = Modifier.size(12.dp),
219-
strokeWidth = 2.dp
220-
)
221-
}
222-
223-
// 流式输出内容
224-
Box(
225-
modifier = Modifier
226-
.fillMaxWidth()
227-
.padding(start = 32.dp)
228-
) {
229-
SketchRenderer.RenderResponse(
230-
content = content,
231-
isComplete = false,
232-
onContentUpdate = onContentUpdate,
233-
modifier = Modifier.fillMaxWidth()
234-
)
235-
}
236-
}
237-
}
238-
239-
/**
240-
* 消息标签
241-
*/
242-
@Composable
243-
private fun MessageLabel(
244-
role: MessageRole,
245-
modifier: Modifier = Modifier
246-
) {
247-
val (icon, label, color) = when (role) {
248-
MessageRole.USER -> Triple("👤", "You", MaterialTheme.colorScheme.secondary)
249-
MessageRole.ASSISTANT -> Triple("🤖", "AI Assistant", MaterialTheme.colorScheme.primary)
250-
MessageRole.SYSTEM -> Triple("⚙️", "System", MaterialTheme.colorScheme.tertiary)
251-
}
252-
253-
Row(
254-
modifier = modifier,
255-
horizontalArrangement = Arrangement.spacedBy(8.dp),
256-
verticalAlignment = Alignment.CenterVertically
257-
) {
258-
Text(
259-
text = icon,
260-
style = MaterialTheme.typography.titleSmall
261-
)
262-
Text(
263-
text = label,
264-
style = MaterialTheme.typography.titleSmall,
265-
color = color
266-
)
267-
}
268-
}
269-
270145
/**
271146
* 项目信息底部栏
272147
*/

0 commit comments

Comments
 (0)