fix: prevent IME from hiding latest messages in chat

Changed chat layout from Box overlay to Column flow so imePadding()
applies to the whole container instead of just the input bar. Messages
area now shrinks with the keyboard, keeping latest messages visible.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 13:01:43 +08:00
parent 5dad0cd39b
commit 91231834dc
@@ -162,72 +162,67 @@ fun ChatScreen(
else -> CyreneStatus.OFFLINE
}
// Input area overlaid at bottom, with IME padding so only input moves up
Box(
// Single column layout: everything flows together and IME shrinks the whole view
Column(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding(),
.statusBarsPadding()
.imePadding(),
) {
Column(modifier = Modifier.fillMaxSize()) {
// Top status bar
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
StatusIndicator(status = status)
}
// Top status bar
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
StatusIndicator(status = status)
}
// Messages area (fills space above input area)
PullToRefreshBox(
isRefreshing = isRefreshing,
onRefresh = { viewModel.refreshMessages() },
modifier = Modifier
.weight(1f)
.padding(bottom = 96.dp), // Reserve space for floating input bar
) {
if (messages.isEmpty() && !isStreaming) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
Text(
text = "开始和昔涟对话吧",
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
// Messages area (fills remaining space, shrinks with IME)
PullToRefreshBox(
isRefreshing = isRefreshing,
onRefresh = { viewModel.refreshMessages() },
modifier = Modifier.weight(1f),
) {
if (messages.isEmpty() && !isStreaming) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
Text(
text = "开始和昔涟对话吧",
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
} else {
LazyColumn(
modifier = Modifier.fillMaxSize(),
state = listState,
reverseLayout = true,
) {
itemsIndexed(messages, key = { _, msg -> msg.id }) { index, message ->
AnimatedChatBubble(
message = message,
animIndex = index.coerceAtMost(20),
)
}
} else {
LazyColumn(
modifier = Modifier.fillMaxSize(),
state = listState,
reverseLayout = true,
) {
itemsIndexed(messages, key = { _, msg -> msg.id }) { index, message ->
AnimatedChatBubble(
message = message,
animIndex = index.coerceAtMost(20),
)
}
if (isStreaming) {
item(key = "typing_indicator") {
TypingIndicator()
}
if (isStreaming) {
item(key = "typing_indicator") {
TypingIndicator()
}
}
}
}
}
// Input area at bottom, moved up by IME
// Input area at bottom, in flow (not overlaid)
Column(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.background(MaterialTheme.colorScheme.surface)
.navigationBarsPadding()
.imePadding(),
.navigationBarsPadding(),
) {
// "昔涟正在输入..." indicator
if (isStreaming) {