Compare commits

..

No commits in common. "163a2cee28f5e6451b6c8377826757923f2f5791" and "c014d6d90c491bf330e4ce60e7a5ee34ce9a1c4c" have entirely different histories.

3 changed files with 19 additions and 26 deletions

View file

@ -231,7 +231,7 @@ All committed on `main`. Compile-verified on Mac (`./gradlew :app:compileDebugKo
- Mesh gradient background with dithered blobs - Mesh gradient background with dithered blobs
- Phase-aware haptics (click → thinkingStart → responseStart → responseEnd) - Phase-aware haptics (click → thinkingStart → responseStart → responseEnd)
- Tablet/landscape optimization (width capping) - Tablet/landscape optimization (width capping)
- 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. - Dynamic keyboard handling (suggestion pills hide, spacer shrinks)
- Settings screen with SettingsViewModel - Settings screen with SettingsViewModel
### Bugs fixed (2026-06-19/20/21) ### Bugs fixed (2026-06-19/20/21)

View file

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

View file

@ -87,9 +87,6 @@ data class StoredMessage(
val attachments: List<Attachment> = emptyList(), val attachments: List<Attachment> = emptyList(),
val reasoning: String? = null, val reasoning: String? = null,
val sources: List<SearchSource>? = 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()) @Serializable private data class ConversationDetail(val messages: List<StoredMessage> = emptyList())