merge: native agent brand icons on both platforms
@@ -37,6 +37,7 @@ import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
@@ -84,6 +85,7 @@ import app.hapi.companion.feature.chat.composer.QueuedMessagesBar
|
||||
import app.hapi.companion.feature.files.FolderGlyph
|
||||
import app.hapi.companion.feature.sessions.DeleteSessionDialog
|
||||
import app.hapi.companion.feature.sessions.RenameSessionDialog
|
||||
import app.hapi.companion.ui.components.AgentFlavorIcon
|
||||
import app.hapi.companion.ui.markdown.LocalMarkdownLinkHandler
|
||||
import app.hapi.companion.ui.theme.hapi
|
||||
import app.hapi.protocol.chat.VisibleChatBlock
|
||||
@@ -557,13 +559,25 @@ private fun ChatTitle(header: ChatHeaderUi) {
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
header.subtitle?.let { subtitle ->
|
||||
Text(
|
||||
text = subtitle,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
header.flavor?.let { flavor ->
|
||||
// Hint-colored like the meta text (web: currentColor
|
||||
// under --app-hint); color variants ignore the tint.
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
) {
|
||||
AgentFlavorIcon(flavor, modifier = Modifier.size(14.dp))
|
||||
}
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
}
|
||||
Text(
|
||||
text = subtitle,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ data class ChatHeaderUi(
|
||||
val title: String,
|
||||
/** "Flavor · machine · worktree/path" meta line; null when nothing known. */
|
||||
val subtitle: String?,
|
||||
/** Raw `metadata.flavor` — drives the brand icon next to the meta line. */
|
||||
val flavor: String? = null,
|
||||
/** Raw custom `metadata.name` (rename-dialog prefill; the title cascade may show more). */
|
||||
val name: String? = null,
|
||||
val active: Boolean,
|
||||
@@ -1472,6 +1474,7 @@ class ChatViewModel(
|
||||
return ChatHeaderUi(
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
flavor = flavor,
|
||||
name = detail?.metadata?.name ?: summary?.metadata?.name,
|
||||
active = detail?.active ?: summary?.active ?: false,
|
||||
thinking = detail?.thinking ?: summary?.thinking ?: false,
|
||||
|
||||
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
@@ -50,6 +51,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.hapi.companion.R
|
||||
import app.hapi.companion.ui.components.AgentFlavorIcon
|
||||
import app.hapi.companion.ui.theme.HapiTheme
|
||||
|
||||
/**
|
||||
@@ -447,6 +449,7 @@ private fun AgentSection(state: NewSessionUiState, onAgentSelected: (String) ->
|
||||
selected = state.form.agent == agent.value,
|
||||
onClick = { onAgentSelected(agent.value) },
|
||||
enabled = !state.isSpawning,
|
||||
leadingIcon = { AgentFlavorIcon(agent.value, modifier = Modifier.size(16.dp)) },
|
||||
label = { Text(agent.label) },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.hapi.companion.R
|
||||
import app.hapi.companion.ui.components.AgentFlavorIcon
|
||||
import app.hapi.companion.ui.theme.HapiTheme
|
||||
import app.hapi.protocol.catalog.Flavors
|
||||
import app.hapi.protocol.wire.PendingRequest
|
||||
import app.hapi.protocol.wire.SessionSummary
|
||||
import app.hapi.protocol.wire.SessionSummaryMetadata
|
||||
@@ -78,9 +78,9 @@ import app.hapi.protocol.wire.TodoProgress
|
||||
* pull-to-refresh, empty state;
|
||||
* - pinned section first (the sort already puts globalPinned/pinned rows on
|
||||
* top; a header + divider make the boundary visible);
|
||||
* - per row: status dot (active / thinking pulse), title, flavor + machine
|
||||
* labels, summary/path line, relative `updatedAt`, pending-request badge,
|
||||
* todo-progress chip, unread dot;
|
||||
* - per row: status dot (active / thinking pulse), flavor brand icon +
|
||||
* title, machine + worktree labels, summary/path line, relative
|
||||
* `updatedAt`, pending-request badge, todo-progress chip, unread dot;
|
||||
* - long-press → actions sheet: pin (none/project/global), rename (dialog),
|
||||
* reopen (inactive rows; navigates into the possibly-superseding id),
|
||||
* archive, delete (confirm; 409 while active) — optimistic store updates;
|
||||
@@ -312,6 +312,8 @@ private fun SessionRow(
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
AgentFlavorIcon(row.flavor, modifier = Modifier.size(16.dp))
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
// One weighted element only: the title takes ALL leftover
|
||||
// width (start-aligned, ellipsis on true overflow). Splitting
|
||||
// the slack with a weighted trailing spacer truncated even
|
||||
@@ -350,12 +352,12 @@ private fun SessionRow(
|
||||
}
|
||||
}
|
||||
|
||||
// The agent flavor moved into the title line as a brand icon (web parity:
|
||||
// `SessionRowSummary`), so the meta line carries machine + worktree only.
|
||||
@Composable
|
||||
private fun MetaLine(row: SessionRowUi) {
|
||||
val flavorLabel = row.flavor?.let(Flavors::label)
|
||||
val worktree = row.summary.metadata?.worktree
|
||||
val parts = buildList {
|
||||
flavorLabel?.let(::add)
|
||||
row.machineLabel?.let(::add)
|
||||
worktree?.let { add(it.name.ifBlank { it.branch }) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package app.hapi.companion.ui.components
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import app.hapi.companion.R
|
||||
import app.hapi.companion.ui.theme.HapiTheme
|
||||
import app.hapi.companion.ui.theme.hapi
|
||||
|
||||
/**
|
||||
* Brand logo per agent flavor — port of `web/src/components/AgentFlavorIcon.tsx`
|
||||
* (brand SVGs via @lobehub/icons, the same source the web ships).
|
||||
*
|
||||
* Color variants (agy/claude/codex/gemini) keep their literal brand fills and
|
||||
* render untinted so they stay visible on both light and dark surfaces — the
|
||||
* reason the web picked Color for them. Mono variants (cursor/grok/kimi/
|
||||
* opencode/pi) are currentColor upstream and tint with [LocalContentColor];
|
||||
* copilot mirrors the web's fixed GitHub-mark tint (#24292F light /
|
||||
* #E6EDF3 dark). Unknown flavors fall back to the web's "Un" badge.
|
||||
*/
|
||||
@Composable
|
||||
fun AgentFlavorIcon(flavor: String?, modifier: Modifier = Modifier.size(16.dp)) {
|
||||
when (val normalized = flavor?.trim()?.lowercase().orEmpty()) {
|
||||
in COLOR_FLAVOR_ICONS -> Image(
|
||||
painter = painterResource(COLOR_FLAVOR_ICONS.getValue(normalized)),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
in MONO_FLAVOR_ICONS -> Icon(
|
||||
painter = painterResource(MONO_FLAVOR_ICONS.getValue(normalized)),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
tint = LocalContentColor.current,
|
||||
)
|
||||
|
||||
"copilot" -> Icon(
|
||||
painter = painterResource(R.drawable.ic_agent_copilot),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
tint = if (MaterialTheme.hapi.isDark) Color(0xFFE6EDF3) else Color(0xFF24292F),
|
||||
)
|
||||
|
||||
else -> Box(
|
||||
modifier = modifier.background(
|
||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
shape = RoundedCornerShape(3.dp),
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = "Un",
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
fontSize = 8.sp,
|
||||
lineHeight = 8.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val COLOR_FLAVOR_ICONS: Map<String, Int> = mapOf(
|
||||
"agy" to R.drawable.ic_agent_agy,
|
||||
"claude" to R.drawable.ic_agent_claude,
|
||||
"codex" to R.drawable.ic_agent_codex,
|
||||
"gemini" to R.drawable.ic_agent_gemini,
|
||||
)
|
||||
|
||||
private val MONO_FLAVOR_ICONS: Map<String, Int> = mapOf(
|
||||
"cursor" to R.drawable.ic_agent_cursor,
|
||||
"grok" to R.drawable.ic_agent_grok,
|
||||
"kimi" to R.drawable.ic_agent_kimi,
|
||||
"opencode" to R.drawable.ic_agent_opencode,
|
||||
"pi" to R.drawable.ic_agent_pi,
|
||||
)
|
||||
|
||||
// -------------------------------------------------------------- preview --
|
||||
|
||||
@Composable
|
||||
private fun AgentFlavorIconStrip() {
|
||||
Column(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
val flavors = listOf(
|
||||
"agy", "claude", "codex", "copilot", "cursor",
|
||||
"gemini", "grok", "kimi", "opencode", "pi", "mystery",
|
||||
)
|
||||
flavors.chunked(6).forEach { chunk ->
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
chunk.forEach { flavor -> AgentFlavorIcon(flavor) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, name = "Agent icons · light")
|
||||
@Composable
|
||||
private fun AgentFlavorIconPreviewLight() {
|
||||
HapiTheme(darkTheme = false, dynamicColor = false) {
|
||||
Surface { AgentFlavorIconStrip() }
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, name = "Agent icons · dark")
|
||||
@Composable
|
||||
private fun AgentFlavorIconPreviewDark() {
|
||||
HapiTheme(darkTheme = true, dynamicColor = false) {
|
||||
Surface { AgentFlavorIconStrip() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Antigravity brand mark (Color variant). Upstream renders the wing as a
|
||||
mask over 11 gaussian-blurred color blobs (SVG filters) which neither
|
||||
VectorDrawable nor Xcode SVG supports; approximated with a left-to-right
|
||||
gradient matching the blob layout (green wing tip, yellow crest, red
|
||||
right arm, blue tip). iOS flattens further to the dominant brand blue.
|
||||
Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Color variant: literal brand
|
||||
fills, render untinted (Image, not Icon). -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M 21.751 22.607 c 1.34 1.005 3.35 0.335 1.508 -1.508 C 17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74 0.815 21.1 c -2.01 2.009 0.167 2.511 1.507 1.506 5.192 -3.517 4.857 -9.714 9.715 -9.714 4.857 0 4.522 6.197 9.714 9.715 z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:startX="0"
|
||||
android:startY="12"
|
||||
android:endX="24"
|
||||
android:endY="12">
|
||||
<item
|
||||
android:color="#FF00B95C"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FFFBBC04"
|
||||
android:offset="0.35" />
|
||||
<item
|
||||
android:color="#FFFC413D"
|
||||
android:offset="0.68" />
|
||||
<item
|
||||
android:color="#FF3186FF"
|
||||
android:offset="0.92" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Claude brand mark (Color variant): flat brand fill #D97757. Brand SVG
|
||||
via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Color variant: literal brand
|
||||
fills, render untinted (Image, not Icon). -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFD97757"
|
||||
android:pathData="M 4.709 15.955 l 4.72 -2.647 0.08 -0.23 -0.08 -0.128 H 9.2 l -0.79 -0.048 -2.698 -0.073 -2.339 -0.097 -2.266 -0.122 -0.571 -0.121 L 0 11.784 l 0.055 -0.352 0.48 -0.321 0.686 0.06 1.52 0.103 2.278 0.158 1.652 0.097 2.449 0.255 h 0.389 l 0.055 -0.157 -0.134 -0.098 -0.103 -0.097 -2.358 -1.596 -2.552 -1.688 -1.336 -0.972 -0.724 -0.491 -0.364 -0.462 -0.158 -1.008 0.656 -0.722 0.881 0.06 0.225 0.061 0.893 0.686 1.908 1.476 2.491 1.833 0.365 0.304 0.145 -0.103 0.019 -0.073 -0.164 -0.274 -1.355 -2.446 -1.446 -2.49 -0.644 -1.032 -0.17 -0.619 a 2.97 2.97 0 0 1 -0.104 -0.729 L 6.283 0.134 6.696 0 l 0.996 0.134 0.42 0.364 0.62 1.414 1.002 2.229 1.555 3.03 0.456 0.898 0.243 0.832 0.091 0.255 h 0.158 V 9.01 l 0.128 -1.706 0.237 -2.095 0.23 -2.695 0.08 -0.76 0.376 -0.91 0.747 -0.492 0.584 0.28 0.48 0.685 -0.067 0.444 -0.286 1.851 -0.559 2.903 -0.364 1.942 h 0.212 l 0.243 -0.242 0.985 -1.306 1.652 -2.064 0.73 -0.82 0.85 -0.904 0.547 -0.431 h 1.033 l 0.76 1.129 -0.34 1.166 -1.064 1.347 -0.881 1.142 -1.264 1.7 -0.79 1.36 0.073 0.11 0.188 -0.02 2.856 -0.606 1.543 -0.28 1.841 -0.315 0.833 0.388 0.091 0.395 -0.328 0.807 -1.969 0.486 -2.309 0.462 -3.439 0.813 -0.042 0.03 0.049 0.061 1.549 0.146 0.662 0.036 h 1.622 l 3.02 0.225 0.79 0.522 0.474 0.638 -0.079 0.485 -1.215 0.62 -1.64 -0.389 -3.829 -0.91 -1.312 -0.329 h -0.182 v 0.11 l 1.093 1.068 2.006 1.81 2.509 2.33 0.127 0.578 -0.322 0.455 -0.34 -0.049 -2.205 -1.657 -0.851 -0.747 -1.926 -1.62 h -0.128 v 0.17 l 0.444 0.649 2.345 3.521 0.122 1.08 -0.17 0.353 -0.608 0.213 -0.668 -0.122 -1.374 -1.925 -1.415 -2.167 -1.143 -1.943 -0.14 0.08 -0.674 7.254 -0.316 0.37 -0.729 0.28 -0.607 -0.461 -0.322 -0.747 0.322 -1.476 0.389 -1.924 0.315 -1.53 0.286 -1.9 0.17 -0.632 -0.012 -0.042 -0.14 0.018 -1.434 1.967 -2.18 2.945 -1.726 1.845 -0.414 0.164 -0.717 -0.37 0.067 -0.662 0.401 -0.589 2.388 -3.036 1.44 -1.882 0.93 -1.086 -0.006 -0.158 h -0.055 L 4.132 18.56 l -1.13 0.146 -0.487 -0.456 0.061 -0.746 0.231 -0.243 1.908 -1.312 -0.006 0.006 z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Codex brand mark (Color variant): white rounded tile + glyph. Upstream
|
||||
fills the glyph with a vertical 3-stop gradient (#B1A7FF > #7A9DFF >
|
||||
#3941FF); Android ports it, iOS flattens to the middle stop #7A9DFF.
|
||||
Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Color variant: literal brand
|
||||
fills, render untinted (Image, not Icon). -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M 19.503 0 H 4.496 A 4.496 4.496 0 0 0 0 4.496 v 15.007 A 4.496 4.496 0 0 0 4.496 24 h 15.007 A 4.496 4.496 0 0 0 24 19.503 V 4.496 A 4.496 4.496 0 0 0 19.503 0 z" />
|
||||
<path
|
||||
android:pathData="M 9.064 3.344 a 4.578 4.578 0 0 1 2.285 -0.312 c 1 0.115 1.891 0.54 2.673 1.275 0.01 0.01 0.024 0.017 0.037 0.021 a 0.09 0.09 0 0 0 0.043 0 4.55 4.55 0 0 1 3.046 0.275 l 0.047 0.022 0.116 0.057 a 4.581 4.581 0 0 1 2.188 2.399 c 0.209 0.51 0.313 1.041 0.315 1.595 a 4.24 4.24 0 0 1 -0.134 1.223 0.123 0.123 0 0 0 0.03 0.115 c 0.594 0.607 0.988 1.33 1.183 2.17 0.289 1.425 -0.007 2.71 -0.887 3.854 l -0.136 0.166 a 4.548 4.548 0 0 1 -2.201 1.388 0.123 0.123 0 0 0 -0.081 0.076 c -0.191 0.551 -0.383 1.023 -0.74 1.494 -0.9 1.187 -2.222 1.846 -3.711 1.838 -1.187 -0.006 -2.239 -0.44 -3.157 -1.302 a 0.107 0.107 0 0 0 -0.105 -0.024 c -0.388 0.125 -0.78 0.143 -1.204 0.138 a 4.441 4.441 0 0 1 -1.945 -0.466 4.544 4.544 0 0 1 -1.61 -1.335 c -0.152 -0.202 -0.303 -0.392 -0.414 -0.617 a 5.81 5.81 0 0 1 -0.37 -0.961 4.582 4.582 0 0 1 -0.014 -2.298 0.124 0.124 0 0 0 0.006 -0.056 0.085 0.085 0 0 0 -0.027 -0.048 4.467 4.467 0 0 1 -1.034 -1.651 3.896 3.896 0 0 1 -0.251 -1.192 5.189 5.189 0 0 1 0.141 -1.6 c 0.337 -1.112 0.982 -1.985 1.933 -2.618 0.212 -0.141 0.413 -0.251 0.601 -0.33 0.215 -0.089 0.43 -0.164 0.646 -0.227 a 0.098 0.098 0 0 0 0.065 -0.066 4.51 4.51 0 0 1 0.829 -1.615 4.535 4.535 0 0 1 1.837 -1.388 z m 3.482 10.565 a 0.637 0.637 0 0 0 0 1.272 h 3.636 a 0.637 0.637 0 1 0 0 -1.272 h -3.636 z M 8.462 9.23 a 0.637 0.637 0 0 0 -1.106 0.631 l 1.272 2.224 -1.266 2.136 a 0.636 0.636 0 1 0 1.095 0.649 l 1.454 -2.455 a 0.636 0.636 0 0 0 0.005 -0.64 L 8.462 9.23 z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:startX="12"
|
||||
android:startY="3"
|
||||
android:endX="12"
|
||||
android:endY="21">
|
||||
<item
|
||||
android:color="#FFB1A7FF"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#FF7A9DFF"
|
||||
android:offset="0.5" />
|
||||
<item
|
||||
android:color="#FF3941FF"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- GitHub mark for Copilot CLI (web ships the same stand-in, see
|
||||
web/src/components/icons/CopilotIcon.tsx); fixed light/dark tint at the
|
||||
call site (#24292F / #E6EDF3). Brand SVG via @lobehub/icons v5.4.0 -
|
||||
same source as web/src/components/AgentFlavorIcon.tsx. Mono glyph ships
|
||||
black; the AgentFlavorIcon composable applies the tint so dark mode
|
||||
works. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 8 0 C 3.58 0 0 3.58 0 8 c 0 3.54 2.29 6.53 5.47 7.59 0.4 0.07 0.55 -0.17 0.55 -0.38 0 -0.19 -0.01 -0.82 -0.01 -1.49 -2.01 0.37 -2.53 -0.49 -2.69 -0.94 -0.09 -0.23 -0.48 -0.94 -0.82 -1.13 -0.28 -0.15 -0.68 -0.52 -0.01 -0.53 0.63 -0.01 1.08 0.58 1.23 0.82 0.72 1.21 1.87 0.87 2.33 0.66 0.07 -0.52 0.28 -0.87 0.51 -1.07 -1.78 -0.2 -3.64 -0.89 -3.64 -3.95 0 -0.87 0.31 -1.59 0.82 -2.15 -0.08 -0.2 -0.36 -1.02 0.08 -2.12 0 0 0.67 -0.21 2.2 0.82 0.64 -0.18 1.32 -0.27 2 -0.27 0.68 0 1.36 0.09 2 0.27 1.53 -1.04 2.2 -0.82 2.2 -0.82 0.44 1.1 0.16 1.92 0.08 2.12 0.51 0.56 0.82 1.27 0.82 2.15 0 3.07 -1.87 3.75 -3.65 3.95 0.29 0.25 0.54 0.73 0.54 1.48 0 1.07 -0.01 1.93 -0.01 2.2 0 0.21 0.15 0.46 0.55 0.38 A 8.013 8.013 0 0 0 16 8 c 0 -4.42 -3.58 -8 -8 -8 z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Cursor mark (Mono variant): currentColor upstream; tint at the call
|
||||
site. Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Mono glyph ships black; the
|
||||
AgentFlavorIcon composable applies the tint so dark mode works. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 22.106 5.68 L 12.5 0.135 a 0.998 0.998 0 0 0 -0.998 0 L 1.893 5.68 a 0.84 0.84 0 0 0 -0.419 0.726 v 11.186 c 0 0.3 0.16 0.577 0.42 0.727 l 9.607 5.547 a 0.999 0.999 0 0 0 0.998 0 l 9.608 -5.547 a 0.84 0.84 0 0 0 0.42 -0.727 V 6.407 a 0.84 0.84 0 0 0 -0.42 -0.726 z m -0.603 1.176 L 12.228 22.92 c -0.063 0.108 -0.228 0.064 -0.228 -0.061 V 12.34 a 0.59 0.59 0 0 0 -0.295 -0.51 l -9.11 -5.26 c -0.107 -0.062 -0.063 -0.228 0.062 -0.228 h 18.55 c 0.264 0 0.428 0.286 0.296 0.514 z"
|
||||
android:fillType="evenOdd" />
|
||||
</vector>
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Gemini brand mark (Color variant): the same star stacked 4x - solid
|
||||
#3186FF base plus three fade-to-transparent gradient overlays
|
||||
(green/red/yellow). Android ports the stack; iOS flattens to the blue
|
||||
base. Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Color variant: literal brand
|
||||
fills, render untinted (Image, not Icon). -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF3186FF"
|
||||
android:pathData="M 20.616 10.835 a 14.147 14.147 0 0 1 -4.45 -3.001 14.111 14.111 0 0 1 -3.678 -6.452 0.503 0.503 0 0 0 -0.975 0 14.134 14.134 0 0 1 -3.679 6.452 14.155 14.155 0 0 1 -4.45 3.001 c -0.65 0.28 -1.318 0.505 -2.002 0.678 a 0.502 0.502 0 0 0 0 0.975 c 0.684 0.172 1.35 0.397 2.002 0.677 a 14.147 14.147 0 0 1 4.45 3.001 14.112 14.112 0 0 1 3.679 6.453 0.502 0.502 0 0 0 0.975 0 c 0.172 -0.685 0.397 -1.351 0.677 -2.003 a 14.145 14.145 0 0 1 3.001 -4.45 14.113 14.113 0 0 1 6.453 -3.678 0.503 0.503 0 0 0 0 -0.975 13.245 13.245 0 0 1 -2.003 -0.678 z" />
|
||||
<path
|
||||
android:pathData="M 20.616 10.835 a 14.147 14.147 0 0 1 -4.45 -3.001 14.111 14.111 0 0 1 -3.678 -6.452 0.503 0.503 0 0 0 -0.975 0 14.134 14.134 0 0 1 -3.679 6.452 14.155 14.155 0 0 1 -4.45 3.001 c -0.65 0.28 -1.318 0.505 -2.002 0.678 a 0.502 0.502 0 0 0 0 0.975 c 0.684 0.172 1.35 0.397 2.002 0.677 a 14.147 14.147 0 0 1 4.45 3.001 14.112 14.112 0 0 1 3.679 6.453 0.502 0.502 0 0 0 0.975 0 c 0.172 -0.685 0.397 -1.351 0.677 -2.003 a 14.145 14.145 0 0 1 3.001 -4.45 14.113 14.113 0 0 1 6.453 -3.678 0.503 0.503 0 0 0 0 -0.975 13.245 13.245 0 0 1 -2.003 -0.678 z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:startX="7"
|
||||
android:startY="15.5"
|
||||
android:endX="11"
|
||||
android:endY="12">
|
||||
<item
|
||||
android:color="#FF08B962"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#0008B962"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M 20.616 10.835 a 14.147 14.147 0 0 1 -4.45 -3.001 14.111 14.111 0 0 1 -3.678 -6.452 0.503 0.503 0 0 0 -0.975 0 14.134 14.134 0 0 1 -3.679 6.452 14.155 14.155 0 0 1 -4.45 3.001 c -0.65 0.28 -1.318 0.505 -2.002 0.678 a 0.502 0.502 0 0 0 0 0.975 c 0.684 0.172 1.35 0.397 2.002 0.677 a 14.147 14.147 0 0 1 4.45 3.001 14.112 14.112 0 0 1 3.679 6.453 0.502 0.502 0 0 0 0.975 0 c 0.172 -0.685 0.397 -1.351 0.677 -2.003 a 14.145 14.145 0 0 1 3.001 -4.45 14.113 14.113 0 0 1 6.453 -3.678 0.503 0.503 0 0 0 0 -0.975 13.245 13.245 0 0 1 -2.003 -0.678 z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:startX="8"
|
||||
android:startY="5.5"
|
||||
android:endX="11.5"
|
||||
android:endY="11">
|
||||
<item
|
||||
android:color="#FFF94543"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#00F94543"
|
||||
android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M 20.616 10.835 a 14.147 14.147 0 0 1 -4.45 -3.001 14.111 14.111 0 0 1 -3.678 -6.452 0.503 0.503 0 0 0 -0.975 0 14.134 14.134 0 0 1 -3.679 6.452 14.155 14.155 0 0 1 -4.45 3.001 c -0.65 0.28 -1.318 0.505 -2.002 0.678 a 0.502 0.502 0 0 0 0 0.975 c 0.684 0.172 1.35 0.397 2.002 0.677 a 14.147 14.147 0 0 1 4.45 3.001 14.112 14.112 0 0 1 3.679 6.453 0.502 0.502 0 0 0 0.975 0 c 0.172 -0.685 0.397 -1.351 0.677 -2.003 a 14.145 14.145 0 0 1 3.001 -4.45 14.113 14.113 0 0 1 6.453 -3.678 0.503 0.503 0 0 0 0 -0.975 13.245 13.245 0 0 1 -2.003 -0.678 z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:startX="3.5"
|
||||
android:startY="13.5"
|
||||
android:endX="17.5"
|
||||
android:endY="12">
|
||||
<item
|
||||
android:color="#FFFABC12"
|
||||
android:offset="0" />
|
||||
<item
|
||||
android:color="#00FABC12"
|
||||
android:offset="0.46" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Grok mark (Mono variant): currentColor upstream; tint at the call site.
|
||||
Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Mono glyph ships black; the
|
||||
AgentFlavorIcon composable applies the tint so dark mode works. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 9.27 15.29 l 7.978 -5.897 c 0.391 -0.29 0.95 -0.177 1.137 0.272 0.98 2.369 0.542 5.215 -1.41 7.169 -1.951 1.954 -4.667 2.382 -7.149 1.406 l -2.711 1.257 c 3.889 2.661 8.611 2.003 11.562 -0.953 2.341 -2.344 3.066 -5.539 2.388 -8.42 l 0.006 0.007 c -0.983 -4.232 0.242 -5.924 2.75 -9.383 0.06 -0.082 0.12 -0.164 0.179 -0.248 l -3.301 3.305 v -0.01 L 9.267 15.292 M 7.623 16.723 c -2.792 -2.67 -2.31 -6.801 0.071 -9.184 1.761 -1.763 4.647 -2.483 7.166 -1.425 l 2.705 -1.25 a 7.808 7.808 0 0 0 -1.829 -1 A 8.975 8.975 0 0 0 5.984 5.83 c -2.533 2.536 -3.33 6.436 -1.962 9.764 1.022 2.487 -0.653 4.246 -2.34 6.022 -0.599 0.63 -1.199 1.259 -1.682 1.925 l 7.62 -6.815"
|
||||
android:fillType="evenOdd" />
|
||||
</vector>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Kimi mark (Mono variant): currentColor upstream (KimiColor hard-codes a
|
||||
white glyph that vanishes on light surfaces - same call as the web).
|
||||
Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Mono glyph ships black; the
|
||||
AgentFlavorIcon composable applies the tint so dark mode works. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 21.846 0 a 1.923 1.923 0 1 1 0 3.846 H 20.15 a 0.226 0.226 0 0 1 -0.227 -0.226 V 1.923 C 19.923 0.861 20.784 0 21.846 0 z"
|
||||
android:fillType="evenOdd" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 11.065 11.199 l 7.257 -7.2 c 0.137 -0.136 0.06 -0.41 -0.116 -0.41 H 14.3 a 0.164 0.164 0 0 0 -0.117 0.051 l -7.82 7.756 c -0.122 0.12 -0.302 0.013 -0.302 -0.179 V 3.82 c 0 -0.127 -0.083 -0.23 -0.185 -0.23 H 3.186 c -0.103 0 -0.186 0.103 -0.186 0.23 V 19.77 c 0 0.128 0.083 0.23 0.186 0.23 h 2.69 c 0.103 0 0.186 -0.102 0.186 -0.23 v -3.25 c 0 -0.069 0.025 -0.135 0.069 -0.178 l 2.424 -2.406 a 0.158 0.158 0 0 1 0.205 -0.023 l 6.484 4.772 a 7.677 7.677 0 0 0 3.453 1.283 c 0.108 0.012 0.2 -0.095 0.2 -0.23 v -3.06 c 0 -0.117 -0.07 -0.212 -0.164 -0.227 a 5.028 5.028 0 0 1 -2.027 -0.807 l -5.613 -4.064 c -0.117 -0.078 -0.132 -0.279 -0.028 -0.381 z"
|
||||
android:fillType="evenOdd" />
|
||||
</vector>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- OpenCode mark (Mono variant): currentColor upstream; tint at the call
|
||||
site. Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Mono glyph ships black; the
|
||||
AgentFlavorIcon composable applies the tint so dark mode works. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 16 6 H 8 v 12 h 8 V 6 z m 4 16 H 4 V 2 h 16 v 20 z"
|
||||
android:fillType="evenOdd" />
|
||||
</vector>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Pi logo (web's inline PiLogo SVG): currentColor; tint at the call site.
|
||||
Brand SVG via @lobehub/icons v5.4.0 - same source as
|
||||
web/src/components/AgentFlavorIcon.tsx. Mono glyph ships black; the
|
||||
AgentFlavorIcon composable applies the tint so dark mode works. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="800"
|
||||
android:viewportHeight="800">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 165.29 165.29 h 352.07 V 400 H 400 v 117.36 H 282.65 v 117.36 H 165.29 z M 282.65 282.65 V 400 H 400 V 282.65 z"
|
||||
android:fillType="evenOdd" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M 517.36 400 h 117.36 v 234.72 H 517.36 z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "original"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#3186FF" d="M 21.751 22.607 c 1.34 1.005 3.35 0.335 1.508 -1.508 C 17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74 0.815 21.1 c -2.01 2.009 0.167 2.511 1.507 1.506 5.192 -3.517 4.857 -9.714 9.715 -9.714 4.857 0 4.522 6.197 9.714 9.715 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "original"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#D97757" d="M 4.709 15.955 l 4.72 -2.647 0.08 -0.23 -0.08 -0.128 H 9.2 l -0.79 -0.048 -2.698 -0.073 -2.339 -0.097 -2.266 -0.122 -0.571 -0.121 L 0 11.784 l 0.055 -0.352 0.48 -0.321 0.686 0.06 1.52 0.103 2.278 0.158 1.652 0.097 2.449 0.255 h 0.389 l 0.055 -0.157 -0.134 -0.098 -0.103 -0.097 -2.358 -1.596 -2.552 -1.688 -1.336 -0.972 -0.724 -0.491 -0.364 -0.462 -0.158 -1.008 0.656 -0.722 0.881 0.06 0.225 0.061 0.893 0.686 1.908 1.476 2.491 1.833 0.365 0.304 0.145 -0.103 0.019 -0.073 -0.164 -0.274 -1.355 -2.446 -1.446 -2.49 -0.644 -1.032 -0.17 -0.619 a 2.97 2.97 0 0 1 -0.104 -0.729 L 6.283 0.134 6.696 0 l 0.996 0.134 0.42 0.364 0.62 1.414 1.002 2.229 1.555 3.03 0.456 0.898 0.243 0.832 0.091 0.255 h 0.158 V 9.01 l 0.128 -1.706 0.237 -2.095 0.23 -2.695 0.08 -0.76 0.376 -0.91 0.747 -0.492 0.584 0.28 0.48 0.685 -0.067 0.444 -0.286 1.851 -0.559 2.903 -0.364 1.942 h 0.212 l 0.243 -0.242 0.985 -1.306 1.652 -2.064 0.73 -0.82 0.85 -0.904 0.547 -0.431 h 1.033 l 0.76 1.129 -0.34 1.166 -1.064 1.347 -0.881 1.142 -1.264 1.7 -0.79 1.36 0.073 0.11 0.188 -0.02 2.856 -0.606 1.543 -0.28 1.841 -0.315 0.833 0.388 0.091 0.395 -0.328 0.807 -1.969 0.486 -2.309 0.462 -3.439 0.813 -0.042 0.03 0.049 0.061 1.549 0.146 0.662 0.036 h 1.622 l 3.02 0.225 0.79 0.522 0.474 0.638 -0.079 0.485 -1.215 0.62 -1.64 -0.389 -3.829 -0.91 -1.312 -0.329 h -0.182 v 0.11 l 1.093 1.068 2.006 1.81 2.509 2.33 0.127 0.578 -0.322 0.455 -0.34 -0.049 -2.205 -1.657 -0.851 -0.747 -1.926 -1.62 h -0.128 v 0.17 l 0.444 0.649 2.345 3.521 0.122 1.08 -0.17 0.353 -0.608 0.213 -0.668 -0.122 -1.374 -1.925 -1.415 -2.167 -1.143 -1.943 -0.14 0.08 -0.674 7.254 -0.316 0.37 -0.729 0.28 -0.607 -0.461 -0.322 -0.747 0.322 -1.476 0.389 -1.924 0.315 -1.53 0.286 -1.9 0.17 -0.632 -0.012 -0.042 -0.14 0.018 -1.434 1.967 -2.18 2.945 -1.726 1.845 -0.414 0.164 -0.717 -0.37 0.067 -0.662 0.401 -0.589 2.388 -3.036 1.44 -1.882 0.93 -1.086 -0.006 -0.158 h -0.055 L 4.132 18.56 l -1.13 0.146 -0.487 -0.456 0.061 -0.746 0.231 -0.243 1.908 -1.312 -0.006 0.006 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "original"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#FFFFFF" d="M 19.503 0 H 4.496 A 4.496 4.496 0 0 0 0 4.496 v 15.007 A 4.496 4.496 0 0 0 4.496 24 h 15.007 A 4.496 4.496 0 0 0 24 19.503 V 4.496 A 4.496 4.496 0 0 0 19.503 0 z"/>
|
||||
<path fill="#7A9DFF" d="M 9.064 3.344 a 4.578 4.578 0 0 1 2.285 -0.312 c 1 0.115 1.891 0.54 2.673 1.275 0.01 0.01 0.024 0.017 0.037 0.021 a 0.09 0.09 0 0 0 0.043 0 4.55 4.55 0 0 1 3.046 0.275 l 0.047 0.022 0.116 0.057 a 4.581 4.581 0 0 1 2.188 2.399 c 0.209 0.51 0.313 1.041 0.315 1.595 a 4.24 4.24 0 0 1 -0.134 1.223 0.123 0.123 0 0 0 0.03 0.115 c 0.594 0.607 0.988 1.33 1.183 2.17 0.289 1.425 -0.007 2.71 -0.887 3.854 l -0.136 0.166 a 4.548 4.548 0 0 1 -2.201 1.388 0.123 0.123 0 0 0 -0.081 0.076 c -0.191 0.551 -0.383 1.023 -0.74 1.494 -0.9 1.187 -2.222 1.846 -3.711 1.838 -1.187 -0.006 -2.239 -0.44 -3.157 -1.302 a 0.107 0.107 0 0 0 -0.105 -0.024 c -0.388 0.125 -0.78 0.143 -1.204 0.138 a 4.441 4.441 0 0 1 -1.945 -0.466 4.544 4.544 0 0 1 -1.61 -1.335 c -0.152 -0.202 -0.303 -0.392 -0.414 -0.617 a 5.81 5.81 0 0 1 -0.37 -0.961 4.582 4.582 0 0 1 -0.014 -2.298 0.124 0.124 0 0 0 0.006 -0.056 0.085 0.085 0 0 0 -0.027 -0.048 4.467 4.467 0 0 1 -1.034 -1.651 3.896 3.896 0 0 1 -0.251 -1.192 5.189 5.189 0 0 1 0.141 -1.6 c 0.337 -1.112 0.982 -1.985 1.933 -2.618 0.212 -0.141 0.413 -0.251 0.601 -0.33 0.215 -0.089 0.43 -0.164 0.646 -0.227 a 0.098 0.098 0 0 0 0.065 -0.066 4.51 4.51 0 0 1 0.829 -1.615 4.535 4.535 0 0 1 1.837 -1.388 z m 3.482 10.565 a 0.637 0.637 0 0 0 0 1.272 h 3.636 a 0.637 0.637 0 1 0 0 -1.272 h -3.636 z M 8.462 9.23 a 0.637 0.637 0 0 0 -1.106 0.631 l 1.272 2.224 -1.266 2.136 a 0.636 0.636 0 1 0 1.095 0.649 l 1.454 -2.455 a 0.636 0.636 0 0 0 0.005 -0.64 L 8.462 9.23 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#000000" d="M 8 0 C 3.58 0 0 3.58 0 8 c 0 3.54 2.29 6.53 5.47 7.59 0.4 0.07 0.55 -0.17 0.55 -0.38 0 -0.19 -0.01 -0.82 -0.01 -1.49 -2.01 0.37 -2.53 -0.49 -2.69 -0.94 -0.09 -0.23 -0.48 -0.94 -0.82 -1.13 -0.28 -0.15 -0.68 -0.52 -0.01 -0.53 0.63 -0.01 1.08 0.58 1.23 0.82 0.72 1.21 1.87 0.87 2.33 0.66 0.07 -0.52 0.28 -0.87 0.51 -1.07 -1.78 -0.2 -3.64 -0.89 -3.64 -3.95 0 -0.87 0.31 -1.59 0.82 -2.15 -0.08 -0.2 -0.36 -1.02 0.08 -2.12 0 0 0.67 -0.21 2.2 0.82 0.64 -0.18 1.32 -0.27 2 -0.27 0.68 0 1.36 0.09 2 0.27 1.53 -1.04 2.2 -0.82 2.2 -0.82 0.44 1.1 0.16 1.92 0.08 2.12 0.51 0.56 0.82 1.27 0.82 2.15 0 3.07 -1.87 3.75 -3.65 3.95 0.29 0.25 0.54 0.73 0.54 1.48 0 1.07 -0.01 1.93 -0.01 2.2 0 0.21 0.15 0.46 0.55 0.38 A 8.013 8.013 0 0 0 16 8 c 0 -4.42 -3.58 -8 -8 -8 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 872 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#000000" fill-rule="evenodd" d="M 22.106 5.68 L 12.5 0.135 a 0.998 0.998 0 0 0 -0.998 0 L 1.893 5.68 a 0.84 0.84 0 0 0 -0.419 0.726 v 11.186 c 0 0.3 0.16 0.577 0.42 0.727 l 9.607 5.547 a 0.999 0.999 0 0 0 0.998 0 l 9.608 -5.547 a 0.84 0.84 0 0 0 0.42 -0.727 V 6.407 a 0.84 0.84 0 0 0 -0.42 -0.726 z m -0.603 1.176 L 12.228 22.92 c -0.063 0.108 -0.228 0.064 -0.228 -0.061 V 12.34 a 0.59 0.59 0 0 0 -0.295 -0.51 l -9.11 -5.26 c -0.107 -0.062 -0.063 -0.228 0.062 -0.228 h 18.55 c 0.264 0 0.428 0.286 0.296 0.514 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 619 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "original"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#3186FF" d="M 20.616 10.835 a 14.147 14.147 0 0 1 -4.45 -3.001 14.111 14.111 0 0 1 -3.678 -6.452 0.503 0.503 0 0 0 -0.975 0 14.134 14.134 0 0 1 -3.679 6.452 14.155 14.155 0 0 1 -4.45 3.001 c -0.65 0.28 -1.318 0.505 -2.002 0.678 a 0.502 0.502 0 0 0 0 0.975 c 0.684 0.172 1.35 0.397 2.002 0.677 a 14.147 14.147 0 0 1 4.45 3.001 14.112 14.112 0 0 1 3.679 6.453 0.502 0.502 0 0 0 0.975 0 c 0.172 -0.685 0.397 -1.351 0.677 -2.003 a 14.145 14.145 0 0 1 3.001 -4.45 14.113 14.113 0 0 1 6.453 -3.678 0.503 0.503 0 0 0 0 -0.975 13.245 13.245 0 0 1 -2.003 -0.678 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 663 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#000000" fill-rule="evenodd" d="M 9.27 15.29 l 7.978 -5.897 c 0.391 -0.29 0.95 -0.177 1.137 0.272 0.98 2.369 0.542 5.215 -1.41 7.169 -1.951 1.954 -4.667 2.382 -7.149 1.406 l -2.711 1.257 c 3.889 2.661 8.611 2.003 11.562 -0.953 2.341 -2.344 3.066 -5.539 2.388 -8.42 l 0.006 0.007 c -0.983 -4.232 0.242 -5.924 2.75 -9.383 0.06 -0.082 0.12 -0.164 0.179 -0.248 l -3.301 3.305 v -0.01 L 9.267 15.292 M 7.623 16.723 c -2.792 -2.67 -2.31 -6.801 0.071 -9.184 1.761 -1.763 4.647 -2.483 7.166 -1.425 l 2.705 -1.25 a 7.808 7.808 0 0 0 -1.829 -1 A 8.975 8.975 0 0 0 5.984 5.83 c -2.533 2.536 -3.33 6.436 -1.962 9.764 1.022 2.487 -0.653 4.246 -2.34 6.022 -0.599 0.63 -1.199 1.259 -1.682 1.925 l 7.62 -6.815"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 802 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#000000" fill-rule="evenodd" d="M 21.846 0 a 1.923 1.923 0 1 1 0 3.846 H 20.15 a 0.226 0.226 0 0 1 -0.227 -0.226 V 1.923 C 19.923 0.861 20.784 0 21.846 0 z"/>
|
||||
<path fill="#000000" fill-rule="evenodd" d="M 11.065 11.199 l 7.257 -7.2 c 0.137 -0.136 0.06 -0.41 -0.116 -0.41 H 14.3 a 0.164 0.164 0 0 0 -0.117 0.051 l -7.82 7.756 c -0.122 0.12 -0.302 0.013 -0.302 -0.179 V 3.82 c 0 -0.127 -0.083 -0.23 -0.185 -0.23 H 3.186 c -0.103 0 -0.186 0.103 -0.186 0.23 V 19.77 c 0 0.128 0.083 0.23 0.186 0.23 h 2.69 c 0.103 0 0.186 -0.102 0.186 -0.23 v -3.25 c 0 -0.069 0.025 -0.135 0.069 -0.178 l 2.424 -2.406 a 0.158 0.158 0 0 1 0.205 -0.023 l 6.484 4.772 a 7.677 7.677 0 0 0 3.453 1.283 c 0.108 0.012 0.2 -0.095 0.2 -0.23 v -3.06 c 0 -0.117 -0.07 -0.212 -0.164 -0.227 a 5.028 5.028 0 0 1 -2.027 -0.807 l -5.613 -4.064 c -0.117 -0.078 -0.132 -0.279 -0.028 -0.381 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 962 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#000000" fill-rule="evenodd" d="M 16 6 H 8 v 12 h 8 V 6 z m 4 16 H 4 V 2 h 16 v 20 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 193 B |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "icon.svg",
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
},
|
||||
"properties": {
|
||||
"preserves-vector-representation": true,
|
||||
"template-rendering-intent": "template"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 800 800">
|
||||
<path fill="#000000" fill-rule="evenodd" d="M 165.29 165.29 h 352.07 V 400 H 400 v 117.36 H 282.65 v 117.36 H 165.29 z M 282.65 282.65 V 400 H 400 V 282.65 z"/>
|
||||
<path fill="#000000" d="M 517.36 400 h 117.36 v 234.72 H 517.36 z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 329 B |
@@ -8,6 +8,8 @@ struct ChatHeaderUI: Equatable {
|
||||
var title: String
|
||||
/// "Flavor · machine · worktree" meta line; nil when nothing is known.
|
||||
var subtitle: String?
|
||||
/// Raw `metadata.flavor` — drives the brand icon next to the meta line.
|
||||
var flavor: String?
|
||||
var active: Bool
|
||||
var thinking: Bool
|
||||
}
|
||||
@@ -110,6 +112,7 @@ final class ChatModel {
|
||||
self.header = ChatHeaderUI(
|
||||
title: String(sessionId.prefix(8)),
|
||||
subtitle: nil,
|
||||
flavor: nil,
|
||||
active: false,
|
||||
thinking: false
|
||||
)
|
||||
@@ -356,6 +359,7 @@ final class ChatModel {
|
||||
return ChatHeaderUI(
|
||||
title: title,
|
||||
subtitle: parts.isEmpty ? nil : parts.joined(separator: " · "),
|
||||
flavor: flavor,
|
||||
active: detail?.active ?? summary?.active ?? false,
|
||||
thinking: detail?.thinking ?? summary?.thinking ?? false
|
||||
)
|
||||
|
||||
@@ -324,10 +324,18 @@ struct ChatView: View {
|
||||
.font(.headline)
|
||||
.lineLimit(1)
|
||||
if let subtitle = model.header.subtitle {
|
||||
Text(subtitle)
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
HStack(spacing: 4) {
|
||||
if model.header.flavor != nil {
|
||||
// Inherits .secondary like the meta text (web:
|
||||
// currentColor under --app-hint); color variants
|
||||
// ignore the tint.
|
||||
AgentFlavorIconView(flavor: model.header.flavor, size: 12)
|
||||
}
|
||||
Text(subtitle)
|
||||
.font(.caption2)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,19 @@ struct NewSessionView: View {
|
||||
Section("Agent") {
|
||||
Picker("Agent", selection: agentBinding) {
|
||||
ForEach(model.agents, id: \.value) { agent in
|
||||
Text(agent.label).tag(agent.value)
|
||||
// Plain `Image` icon so the menu representation keeps it
|
||||
// (UIMenu drops custom icon views); template monos take
|
||||
// the menu tint, color marks render as-is.
|
||||
if let asset = AgentFlavorIconView.assetName(forFlavor: agent.value) {
|
||||
Label {
|
||||
Text(agent.label)
|
||||
} icon: {
|
||||
Image(asset)
|
||||
}
|
||||
.tag(agent.value)
|
||||
} else {
|
||||
Text(agent.label).tag(agent.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import SwiftUI
|
||||
|
||||
/// Brand logo per agent flavor — port of `web/src/components/AgentFlavorIcon.tsx`
|
||||
/// (brand SVGs via @lobehub/icons, the same source the web ships; assets live
|
||||
/// in `Assets.xcassets/AgentIcons`).
|
||||
///
|
||||
/// Color variants (agy/claude/codex/gemini) carry `original` rendering intent
|
||||
/// so the literal brand fills stay visible on light and dark — the reason the
|
||||
/// web picked Color for them. Mono variants (cursor/grok/kimi/opencode/pi)
|
||||
/// are template images and inherit the environment foreground style (the
|
||||
/// web's currentColor); copilot mirrors the web's fixed GitHub-mark tint
|
||||
/// (#24292F light / #E6EDF3 dark). Unknown flavors fall back to the web's
|
||||
/// "Un" badge.
|
||||
struct AgentFlavorIconView: View {
|
||||
let flavor: String?
|
||||
var size: CGFloat = 16
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
/// Flavors with a bundled `AgentIcons/<flavor>` image set.
|
||||
private static let bundledFlavors: Set<String> = [
|
||||
"agy", "claude", "codex", "copilot", "cursor",
|
||||
"gemini", "grok", "kimi", "opencode", "pi",
|
||||
]
|
||||
|
||||
/// Asset name for a raw `metadata.flavor` value; nil when no icon ships.
|
||||
static func assetName(forFlavor flavor: String?) -> String? {
|
||||
guard let flavor else { return nil }
|
||||
let normalized = flavor.trimmingCharacters(in: .whitespaces).lowercased()
|
||||
return bundledFlavors.contains(normalized) ? normalized : nil
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
content
|
||||
.frame(width: size, height: size)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var content: some View {
|
||||
if let name = Self.assetName(forFlavor: flavor) {
|
||||
let icon = Image(name)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
if name == "copilot" {
|
||||
icon.foregroundStyle(colorScheme == .dark
|
||||
? Color(red: 230 / 255, green: 237 / 255, blue: 243 / 255)
|
||||
: Color(red: 36 / 255, green: 41 / 255, blue: 47 / 255))
|
||||
} else {
|
||||
icon
|
||||
}
|
||||
} else {
|
||||
Text("Un")
|
||||
.font(.system(size: 8, weight: .semibold))
|
||||
.foregroundStyle(.secondary)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(Color.secondary.opacity(0.15), in: RoundedRectangle(cornerRadius: 3))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview("Agent icons") {
|
||||
AgentFlavorIconPreviewGrid()
|
||||
}
|
||||
|
||||
#Preview("Agent icons · dark") {
|
||||
AgentFlavorIconPreviewGrid()
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
|
||||
private struct AgentFlavorIconPreviewGrid: View {
|
||||
private let flavors: [String?] = [
|
||||
"agy", "claude", "codex", "copilot", "cursor",
|
||||
"gemini", "grok", "kimi", "opencode", "pi", "mystery",
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
ForEach(flavors, id: \.self) { flavor in
|
||||
HStack(spacing: 8) {
|
||||
AgentFlavorIconView(flavor: flavor)
|
||||
Text(flavor ?? "nil")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,9 @@ import SwiftUI
|
||||
/// pull-to-refresh, empty/loading states;
|
||||
/// - pinned section first (the sort already puts globalPinned/pinned rows on
|
||||
/// top; a header makes the boundary visible);
|
||||
/// - per row: status dot (active / thinking pulse), title, flavor + machine +
|
||||
/// worktree meta line, summary/path line, relative `updatedAt`,
|
||||
/// pending-request badge, todo-progress chip, unread dot;
|
||||
/// - per row: status dot (active / thinking pulse), flavor brand icon +
|
||||
/// title, machine + worktree meta line, summary/path line, relative
|
||||
/// `updatedAt`, pending-request badge, todo-progress chip, unread dot;
|
||||
/// - long-press context menu → pin (none/project/global) + archive with
|
||||
/// optimistic store updates; failures land in an alert.
|
||||
struct SessionListView: View {
|
||||
@@ -219,6 +219,7 @@ struct SessionRowView: View {
|
||||
|
||||
private var titleLine: some View {
|
||||
HStack(spacing: 6) {
|
||||
AgentFlavorIconView(flavor: row.flavor)
|
||||
Text(row.title)
|
||||
.font(.body)
|
||||
.fontWeight(row.unread ? .semibold : .regular)
|
||||
@@ -236,6 +237,8 @@ struct SessionRowView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// The agent flavor moved into the title line as a brand icon (web parity:
|
||||
// `SessionRowSummary`), so the meta line carries machine + worktree only.
|
||||
@ViewBuilder
|
||||
private var metaLine: some View {
|
||||
let worktree = row.summary.metadata?.worktree
|
||||
@@ -243,7 +246,6 @@ struct SessionRowView: View {
|
||||
tree.name.trimmingCharacters(in: .whitespaces).isEmpty ? tree.branch : tree.name
|
||||
}
|
||||
let parts: [String] = [
|
||||
row.flavor.map { flavorLabel(forFlavor: $0) },
|
||||
row.machineLabel,
|
||||
worktreeLabel,
|
||||
].compactMap { $0 }
|
||||
|
||||