diff --git a/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt b/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt index 54a2948..26b7cd3 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt @@ -142,14 +142,10 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M } @Composable -fun ModePillsRow(selected: Set, onToggle: (Int) -> Unit, modifier: Modifier = Modifier) { +fun ModePillsRow(activeMode: Int?, onToggle: (Int) -> Unit, modifier: Modifier = Modifier) { val cs = MaterialTheme.colorScheme val isDark = isSystemInDarkTheme() - - val glassBorder = remember(isDark) { - if (isDark) Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.14f), Color.White.copy(alpha = 0.04f))) - else Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.50f), Color.Black.copy(alpha = 0.06f))) - } + val accent = LocalKaizenAccent.current Row( modifier @@ -158,25 +154,30 @@ fun ModePillsRow(selected: Set, onToggle: (Int) -> Unit, modifier: Modifier .padding(horizontal = 14.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { - chatModes.forEach { mode -> + chatModes.filter { it.labelRes != R.string.mode_standard }.forEach { mode -> val label = stringResource(mode.labelRes) - val active = mode.labelRes in selected + val active = mode.labelRes == activeMode val backgroundFill = if (active) { - if (isDark) cs.surface.copy(alpha = 0.8f) else cs.surface.copy(alpha = 0.88f) + accent.primary.copy(alpha = if (isDark) 0.18f else 0.14f) } else { if (isDark) cs.surface.copy(alpha = 0.35f) else cs.surface.copy(alpha = 0.55f) } + val borderColor = if (active) { + accent.primary.copy(alpha = 0.4f) + } else { + if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.06f) + } Row( Modifier .clip(KaizenShapes.pill) .background(backgroundFill) - .border(1.2.dp, glassBorder, KaizenShapes.pill) + .border(1.2.dp, borderColor, KaizenShapes.pill) .clickable { onToggle(mode.labelRes) } .padding(horizontal = 13.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { - Icon(mode.icon, null, tint = if (active) cs.onBackground else cs.onSurfaceVariant, modifier = Modifier.size(16.dp)) + Icon(mode.icon, null, tint = if (active) accent.primary else cs.onSurfaceVariant, modifier = Modifier.size(16.dp)) Spacer(Modifier.width(6.dp)) Text(label, color = if (active) cs.onBackground else cs.onSurfaceVariant, fontSize = 13.sp, fontWeight = if (active) FontWeight.SemiBold else FontWeight.Medium) } diff --git a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt index 7397423..aa64831 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt @@ -97,7 +97,7 @@ fun ChatScreen( var input by remember { mutableStateOf("") } var isStreaming by remember { mutableStateOf(false) } var nextId by remember { mutableStateOf(0L) } - var selectedModes by remember { mutableStateOf(setOf(R.string.mode_standard)) } + var activeMode by remember { mutableStateOf(null) } // Navigation State var currentScreen by remember { mutableStateOf(AppScreen.Chat) } @@ -339,6 +339,7 @@ fun ChatScreen( KaizenApi.chat( cfg.baseUrl, cfg.token, cfg.model, history, cfg.speed, attachments = uploadedAtts.takeIf { it.isNotEmpty() }, + webSearch = activeMode == R.string.mode_search, ).collect { state -> val idx = messages.indexOfLast { it.id == assistantId } if (idx < 0) return@collect @@ -621,9 +622,9 @@ fun ChatScreen( ) { Spacer(Modifier.height(24.dp)) ModePillsRow( - selected = selectedModes, + activeMode = activeMode, onToggle = { mode -> - selectedModes = if (mode in selectedModes) selectedModes - mode else selectedModes + mode + activeMode = if (activeMode == mode) null else mode haptics.tick() }, ) diff --git a/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt b/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt index 629b4c0..4e88cdc 100644 --- a/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt +++ b/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt @@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit val reasoningEffort: String? = null, val preferThroughput: Boolean? = null, val attachments: List? = null, + val webSearch: Boolean? = null, ) /** One entry from GET /api/v1/models — the picker's row. `provider == "vertex"` drives the hoster badge. */ @@ -440,6 +441,7 @@ object KaizenApi { messages: List, speed: ChatSpeed = ChatSpeed.Normal, attachments: List? = null, + webSearch: Boolean = false, ): Flow = flow { val payload = json.encodeToString( ChatRequest( @@ -448,6 +450,7 @@ object KaizenApi { reasoningEffort = speed.reasoningEffort, preferThroughput = if (speed.preferThroughput) true else null, attachments = attachments?.takeIf { it.isNotEmpty() }, + webSearch = if (webSearch) true else null, ), ).toRequestBody(jsonMedia) val req = Request.Builder()