Compare commits
No commits in common. "f62cc4b7ac4bcf1000fc78241623c9e68cb4c972" and "6a8a76d9f8c88bc35830810b6dcc92e3dc9983ed" have entirely different histories.
f62cc4b7ac
...
6a8a76d9f8
2 changed files with 41 additions and 78 deletions
|
|
@ -13,10 +13,7 @@ import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.imePadding
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.isImeVisible
|
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
|
@ -222,7 +219,6 @@ fun ChatScreen(
|
||||||
messages.clear()
|
messages.clear()
|
||||||
conversationId = null
|
conversationId = null
|
||||||
viewingLockedChat = false
|
viewingLockedChat = false
|
||||||
usedTokens = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openConversation(summary: ConversationSummary) {
|
fun openConversation(summary: ConversationSummary) {
|
||||||
|
|
@ -273,7 +269,6 @@ fun ChatScreen(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
viewingLockedChat = false
|
viewingLockedChat = false
|
||||||
usedTokens = 0
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
messages.clear()
|
messages.clear()
|
||||||
val cachedList = chat.messageRepo.getCached(summary.id)
|
val cachedList = chat.messageRepo.getCached(summary.id)
|
||||||
|
|
@ -660,10 +655,11 @@ fun ChatScreen(
|
||||||
ModelPill(
|
ModelPill(
|
||||||
label = modelDisplayName(session.config?.model ?: "", models),
|
label = modelDisplayName(session.config?.model ?: "", models),
|
||||||
onClick = { haptics.tick(); showModelSheet = true },
|
onClick = { haptics.tick(); showModelSheet = true },
|
||||||
|
modifier = Modifier.weight(1f, fill = false),
|
||||||
)
|
)
|
||||||
Spacer(Modifier.weight(1f))
|
if (usedTokens > 0 || messages.isNotEmpty()) {
|
||||||
if (usedTokens > 0) {
|
|
||||||
val ctxLen = models.find { it.id == session.config?.model }?.context_length ?: 1_000_000
|
val ctxLen = models.find { it.id == session.config?.model }?.context_length ?: 1_000_000
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
TokenBadge(used = usedTokens, contextLength = ctxLen)
|
TokenBadge(used = usedTokens, contextLength = ctxLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -708,22 +704,18 @@ fun ChatScreen(
|
||||||
.imePadding()
|
.imePadding()
|
||||||
.then(if (isTablet) Modifier.widthIn(max = 720.dp) else Modifier)
|
.then(if (isTablet) Modifier.widthIn(max = 720.dp) else Modifier)
|
||||||
) {
|
) {
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
Spacer(Modifier.height(24.dp))
|
||||||
val imeVisible = WindowInsets.isImeVisible
|
ModePillsRow(
|
||||||
if (!imeVisible) {
|
activeMode = activeMode,
|
||||||
Spacer(Modifier.height(24.dp))
|
onToggle = { mode ->
|
||||||
ModePillsRow(
|
activeMode = if (activeMode == mode) null else mode
|
||||||
activeMode = activeMode,
|
haptics.tick()
|
||||||
onToggle = { mode ->
|
},
|
||||||
activeMode = if (activeMode == mode) null else mode
|
reasoningPreset = reasoningPreset,
|
||||||
haptics.tick()
|
onReasoningChange = { reasoningPreset = it; haptics.tick() },
|
||||||
},
|
samplingPrefs = samplingPrefs,
|
||||||
reasoningPreset = reasoningPreset,
|
onSamplingChange = { samplingPrefs = it },
|
||||||
onReasoningChange = { reasoningPreset = it; haptics.tick() },
|
)
|
||||||
samplingPrefs = samplingPrefs,
|
|
||||||
onSamplingChange = { samplingPrefs = it },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(Modifier.height(10.dp))
|
Spacer(Modifier.height(10.dp))
|
||||||
ChatInput(
|
ChatInput(
|
||||||
value = input,
|
value = input,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
|
@ -48,7 +50,6 @@ import dev.kaizen.app.net.ToolEvent
|
||||||
import dev.kaizen.app.R
|
import dev.kaizen.app.R
|
||||||
import dev.kaizen.app.ui.shape.KaizenShapes
|
import dev.kaizen.app.ui.shape.KaizenShapes
|
||||||
import dev.kaizen.app.ui.theme.LocalKaizenAccent
|
import dev.kaizen.app.ui.theme.LocalKaizenAccent
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -169,55 +170,36 @@ fun ToolEventsBlock(tools: List<ToolEvent>, streaming: Boolean = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SourcesBlock(sources: List<SearchSource>, query: String = "") {
|
fun SourcesBlock(sources: List<SearchSource>, query: String = "") {
|
||||||
val cs = MaterialTheme.colorScheme
|
val cs = MaterialTheme.colorScheme
|
||||||
val isDark = isSystemInDarkTheme()
|
val isDark = isSystemInDarkTheme()
|
||||||
val accent = LocalKaizenAccent.current
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Row(
|
if (query.isNotBlank()) {
|
||||||
Modifier
|
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(bottom = 6.dp)) {
|
||||||
.clickable { expanded = !expanded }
|
Icon(Icons.Rounded.Language, null, tint = cs.onSurfaceVariant, modifier = Modifier.size(14.dp))
|
||||||
.padding(vertical = 4.dp),
|
Spacer(Modifier.width(6.dp))
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
Text(query, color = cs.onSurfaceVariant, fontSize = 12.sp, fontWeight = FontWeight.Medium)
|
||||||
) {
|
}
|
||||||
Icon(Icons.Rounded.Language, null, tint = cs.onSurfaceVariant.copy(alpha = 0.6f), modifier = Modifier.size(13.dp))
|
|
||||||
Spacer(Modifier.width(6.dp))
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.stream_sources) + " (${sources.size})",
|
|
||||||
color = cs.onSurfaceVariant.copy(alpha = 0.6f),
|
|
||||||
fontSize = 12.sp,
|
|
||||||
fontWeight = FontWeight.Medium,
|
|
||||||
)
|
|
||||||
Spacer(Modifier.width(4.dp))
|
|
||||||
Icon(
|
|
||||||
if (expanded) Icons.Rounded.ExpandLess else Icons.Rounded.ExpandMore,
|
|
||||||
null, tint = cs.onSurfaceVariant.copy(alpha = 0.4f), modifier = Modifier.size(12.dp),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
AnimatedVisibility(expanded, enter = expandVertically(), exit = shrinkVertically()) {
|
FlowRow(
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.padding(top = 4.dp)) {
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
sources.forEach { source ->
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
SourceCard(source, isDark, accent) {
|
) {
|
||||||
try {
|
sources.forEach { source ->
|
||||||
val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(source.url))
|
SourceChip(source, isDark)
|
||||||
context.startActivity(intent)
|
|
||||||
} catch (_: Exception) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SourceCard(source: SearchSource, isDark: Boolean, accent: dev.kaizen.app.ui.theme.themes.KaizenAccentScheme, onClick: () -> Unit) {
|
private fun SourceChip(source: SearchSource, isDark: Boolean) {
|
||||||
val cs = MaterialTheme.colorScheme
|
val cs = MaterialTheme.colorScheme
|
||||||
val bg = if (isDark) Color.White.copy(alpha = 0.05f) else Color.Black.copy(alpha = 0.03f)
|
val bg = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.04f)
|
||||||
val borderColor = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.05f)
|
val borderColor = if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.06f)
|
||||||
|
|
||||||
val domain = remember(source.url) {
|
val domain = remember(source.url) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -227,38 +209,27 @@ private fun SourceCard(source: SearchSource, isDark: Boolean, accent: dev.kaizen
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.width(140.dp)
|
||||||
.clip(KaizenShapes.sm)
|
.clip(KaizenShapes.xs)
|
||||||
.background(bg)
|
.background(bg)
|
||||||
.border(1.dp, borderColor, KaizenShapes.sm)
|
.border(1.dp, borderColor, KaizenShapes.xs)
|
||||||
.clickable(onClick = onClick)
|
.padding(horizontal = 10.dp, vertical = 8.dp),
|
||||||
.padding(horizontal = 12.dp, vertical = 10.dp),
|
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
source.title.ifEmpty { domain },
|
source.title.ifEmpty { domain },
|
||||||
color = cs.onBackground,
|
color = cs.onBackground,
|
||||||
fontSize = 13.sp,
|
fontSize = 12.sp,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Medium,
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
Spacer(Modifier.height(2.dp))
|
Spacer(Modifier.height(2.dp))
|
||||||
Text(
|
Text(
|
||||||
source.url,
|
domain,
|
||||||
color = accent.primary.copy(alpha = 0.7f),
|
color = cs.onSurfaceVariant.copy(alpha = 0.6f),
|
||||||
fontSize = 11.sp,
|
fontSize = 10.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
if (source.snippet.isNotBlank()) {
|
|
||||||
Spacer(Modifier.height(3.dp))
|
|
||||||
Text(
|
|
||||||
source.snippet,
|
|
||||||
color = cs.onSurfaceVariant.copy(alpha = 0.5f),
|
|
||||||
fontSize = 11.sp,
|
|
||||||
maxLines = 2,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue