Compare commits

...

2 commits

Author SHA1 Message Date
Bruno Deanoz
163a2cee28 fix 3 bugs: pills with keyboard, token count, chat model
1. Mode pills stay visible when keyboard open (were hidden).
   Spacing reduced (6dp vs 24dp) to keep dock compact.

2. Token counter works for loaded chats — sum inputTokens +
   outputTokens from all StoredMessages when fetching from
   server. StoredMessage now parses model/inputTokens/outputTokens.

3. Model pill shows the chat's actual model (from last assistant
   message) instead of always the global default. chatModel state
   tracks per-conversation model, falls back to session default
   for new chats.
2026-06-22 01:27:29 +02:00
Bruno Deanoz
0db20bfda8 docs: document keyboard handling approach (offset, not imePadding) 2026-06-22 01:23:30 +02:00
3 changed files with 26 additions and 19 deletions

View file

@ -231,7 +231,7 @@ All committed on `main`. Compile-verified on Mac (`./gradlew :app:compileDebugKo
- Mesh gradient background with dithered blobs
- Phase-aware haptics (click → thinkingStart → responseStart → responseEnd)
- Tablet/landscape optimization (width capping)
- Dynamic keyboard handling (suggestion pills hide, spacer shrinks)
- Dynamic keyboard handling: `WindowInsets.ime` offset (NOT `imePadding()` — that inflates the dock; NOT `adjustResize` — hides the dock with edge-to-edge). Mode pills hide when keyboard open. `windowSoftInputMode=adjustNothing` in manifest.
- Settings screen with SettingsViewModel
### Bugs fixed (2026-06-19/20/21)

View file

@ -108,6 +108,7 @@ fun ChatScreen(
var reasoningPreset by remember { mutableStateOf(ReasoningPreset.Standard) }
var samplingPrefs by remember { mutableStateOf(SamplingPrefs()) }
var usedTokens by remember { mutableStateOf(0) }
var chatModel by remember { mutableStateOf<String?>(null) }
// Navigation State
var currentScreen by remember { mutableStateOf(AppScreen.Chat) }
@ -225,6 +226,7 @@ fun ChatScreen(
conversationId = null
viewingLockedChat = false
usedTokens = 0
chatModel = null
}
fun unlockAndOpen(summary: ConversationSummary) {
@ -314,6 +316,9 @@ fun ChatScreen(
if (stored.isNotEmpty()) {
val entities = stored.mapIndexed { i, m -> m.toEntity(summary.id, i) }
chat.messageRepo.cacheMessages(summary.id, entities)
val lastAssistant = stored.lastOrNull { it.role == "assistant" }
lastAssistant?.model?.let { chatModel = it }
usedTokens = stored.sumOf { (it.inputTokens ?: 0) + (it.outputTokens ?: 0) }
if (stored.size != cachedList.size || stored.zip(cachedList).any { (s, c) -> s.id != c.id || s.content != c.content }) {
messages.clear()
stored.forEach { m ->
@ -673,12 +678,13 @@ fun ChatScreen(
}
}
Spacer(Modifier.width(8.dp))
val displayModel = chatModel ?: session.config?.model ?: ""
ModelPill(
label = modelDisplayName(session.config?.model ?: "", models),
label = modelDisplayName(displayModel, models),
onClick = { haptics.tick(); showModelSheet = true },
)
Spacer(Modifier.weight(1f))
val ctxLen = models.find { it.id == session.config?.model }?.context_length ?: 1_000_000
val ctxLen = models.find { it.id == displayModel }?.context_length ?: 1_000_000
TokenBadge(used = usedTokens, contextLength = ctxLen)
}
}
@ -730,21 +736,19 @@ fun ChatScreen(
)
.then(if (isTablet) Modifier.widthIn(max = 720.dp) else Modifier)
) {
if (!imeVisible) {
Spacer(Modifier.height(24.dp))
ModePillsRow(
activeMode = activeMode,
onToggle = { mode ->
activeMode = if (activeMode == mode) null else mode
haptics.tick()
},
reasoningPreset = reasoningPreset,
onReasoningChange = { reasoningPreset = it; haptics.tick() },
samplingPrefs = samplingPrefs,
onSamplingChange = { samplingPrefs = it },
)
Spacer(Modifier.height(10.dp))
}
Spacer(Modifier.height(if (imeVisible) 6.dp else 24.dp))
ModePillsRow(
activeMode = activeMode,
onToggle = { mode ->
activeMode = if (activeMode == mode) null else mode
haptics.tick()
},
reasoningPreset = reasoningPreset,
onReasoningChange = { reasoningPreset = it; haptics.tick() },
samplingPrefs = samplingPrefs,
onSamplingChange = { samplingPrefs = it },
)
Spacer(Modifier.height(if (imeVisible) 6.dp else 10.dp))
ChatInput(
value = input,
onValueChange = { input = it },
@ -791,7 +795,7 @@ fun ChatScreen(
models = models,
selectedModelId = session.config?.model ?: "",
favorites = session.favorites,
onSelectModel = { session.setModel(it); haptics.tick() },
onSelectModel = { session.setModel(it); chatModel = it; haptics.tick() },
onToggleFavorite = { session.toggleFavorite(it) },
onDismiss = { showModelSheet = false },
)

View file

@ -87,6 +87,9 @@ data class StoredMessage(
val attachments: List<Attachment> = emptyList(),
val reasoning: String? = null,
val sources: List<SearchSource>? = null,
val model: String? = null,
val inputTokens: Int? = null,
val outputTokens: Int? = null,
)
@Serializable private data class ConversationDetail(val messages: List<StoredMessage> = emptyList())