diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt index 5bda63b708da..2e8e56948a1e 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt @@ -793,10 +793,8 @@ private fun ChatShellScreen( ) { ChatScreen( viewModel = viewModel, - onBack = {}, onVoice = onVoice, onOpenSessions = onOpenSessions, - showBackButton = false, ) } } diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt index 6b222bd50e45..d15d900dd9ca 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt @@ -38,7 +38,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.AttachFile import androidx.compose.material.icons.filled.Close @@ -80,10 +79,8 @@ import java.util.Locale @Composable fun ChatScreen( viewModel: MainViewModel, - onBack: () -> Unit, onVoice: () -> Unit, - onOpenSessions: (() -> Unit)? = null, - showBackButton: Boolean = true, + onOpenSessions: () -> Unit, ) { val messages by viewModel.chatMessages.collectAsState() val historyLoading by viewModel.chatHistoryLoading.collectAsState() @@ -162,12 +159,10 @@ fun ChatScreen( thinkingLevel = thinkingLevel, healthOk = healthOk, pendingRunCount = pendingRunCount, - onBack = onBack, onMore = { viewModel.refreshChat() viewModel.refreshChatSessions(limit = 100) }, - showBackButton = showBackButton, ) ChatSessionSwitcher( @@ -236,7 +231,7 @@ private fun ChatSessionSwitcher( sessions: List, mainSessionKey: String, onSelectSession: (String) -> Unit, - onOpenSessions: (() -> Unit)?, + onOpenSessions: () -> Unit, ) { val choices = remember(sessionKey, sessions, mainSessionKey) { @@ -260,7 +255,7 @@ private fun ChatSessionSwitcher( onClick = { onSelectSession(entry.key) }, ) } - if (onOpenSessions != null && sessions.size > choices.size) { + if (sessions.size > choices.size) { Surface( onClick = onOpenSessions, modifier = Modifier.heightIn(min = 36.dp), @@ -312,20 +307,14 @@ private fun ChatHeader( thinkingLevel: String, healthOk: Boolean, pendingRunCount: Int, - onBack: () -> Unit, onMore: () -> Unit, - showBackButton: Boolean, ) { Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp), ) { - if (showBackButton) { - HeaderIcon(icon = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back", onClick = onBack) - } else { - Box(modifier = Modifier.size(ClawTheme.spacing.touchTarget)) - } + Box(modifier = Modifier.size(ClawTheme.spacing.touchTarget)) Column( modifier = Modifier.weight(1f), diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/SessionFilters.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/SessionFilters.kt index b2f1a7200097..f4c7c0aacec8 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/SessionFilters.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/chat/SessionFilters.kt @@ -4,22 +4,9 @@ import ai.openclaw.app.chat.ChatSessionEntry private const val RECENT_WINDOW_MS = 24 * 60 * 60 * 1000L -/** - * Derive a human-friendly label from a raw session key. - * Examples: - * "telegram:g-agent-main-main" -> "Main" - * "agent:main:main" -> "Main" - * "discord:g-server-channel" -> "Server Channel" - * "my-custom-session" -> "My Custom Session" - */ fun friendlySessionName(key: String): String { - // Strip common prefixes like "telegram:", "agent:", "discord:" etc. val stripped = key.substringAfterLast(":") - - // Remove leading "g-" prefix (gateway artifact) val cleaned = if (stripped.startsWith("g-")) stripped.removePrefix("g-") else stripped - - // Split on hyphens/underscores, title-case each word, collapse "main main" -> "Main" val words = cleaned .split('-', '_') @@ -79,7 +66,6 @@ fun resolveSessionChoices( return result } -/** Builds the compact top-of-chat session switcher without dropping main or the active session. */ fun resolveCompactSessionChoices( currentSessionKey: String, sessions: List, @@ -94,24 +80,14 @@ fun resolveCompactSessionChoices( mainSessionKey = mainSessionKey, nowMs = nowMs, ) - if (allChoices.size <= maxOptions) return allChoices - val mainKey = mainSessionKey.trim().ifEmpty { "main" } val current = currentSessionKey.trim().let { if (it == "main" && mainKey != "main") mainKey else it } - val pinnedKeys = listOf(mainKey, current).filter { it.isNotBlank() } - val result = mutableListOf() - val seen = mutableSetOf() + val pinnedRank = listOf(mainKey, current).filter { it.isNotBlank() }.distinct().withIndex().associate { it.value to it.index } + val unpinnedRank = pinnedRank.size - pinnedKeys.forEach { key -> - allChoices.firstOrNull { it.key == key }?.let { entry -> - if (seen.add(entry.key)) result.add(entry) - } - } - - allChoices.forEach { entry -> - if (result.size >= maxOptions) return@forEach - if (seen.add(entry.key)) result.add(entry) - } - - return result + return allChoices + .withIndex() + .sortedWith(compareBy({ pinnedRank[it.value.key] ?: unpinnedRank }, { it.index })) + .take(maxOptions) + .map { it.value } }