Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions apps/mobile/src/components/ComposerModelControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { ModelOption } from "../lib/modelOptions";
import { resolveProviderOptionDescriptors } from "../lib/providerOptions";
import { AppText as Text } from "./ui/AppText";
import { ComposerInlineControl } from "./ComposerToolbar";
import { ProviderIcon, ProviderInstanceIcon } from "./ProviderIcon";
import { ProviderIcon, ProviderInstanceIcon, providerInstanceNameLabel } from "./ProviderIcon";

export function ComposerModelControl(props: {
readonly modelOption: ModelOption | null;
Expand Down Expand Up @@ -37,6 +37,15 @@ export function ComposerModelControl(props: {
: "";
const badge = props.modelOption?.providerBadge;
const label = props.modelOption?.label ?? props.selection?.model ?? "Choose model";
const providerNameLabel = badge
? providerInstanceNameLabel({
provider: props.modelOption?.providerDriver,
iconUrl: props.modelOption?.providerIconUrl,
displayName: badge.displayName,
showBadge: badge.showBadge,
})
: null;
const shortLabel = props.modelOption?.shortName ?? label;
return (
<ComposerInlineControl
accessibilityLabel={[
Expand Down Expand Up @@ -69,10 +78,24 @@ export function ComposerModelControl(props: {
/>
)
}
label={props.modelOption?.shortName ?? label}
label={providerNameLabel ?? shortLabel}
labelEllipsizeMode={providerNameLabel ? "middle" : undefined}
iconOnly={props.iconOnly}
suffixWidth={providerNameLabel ? 96 : undefined}
suffix={
summary ? (
providerNameLabel ? (
<Text
className={
props.size === "large"
? "text-sm text-foreground-muted"
: "text-xs text-foreground-muted"
}
numberOfLines={1}
>
{shortLabel}
{summary ? ` · ${summary}` : ""}
</Text>
) : summary ? (
<Text
className={
props.size === "large"
Expand Down
10 changes: 9 additions & 1 deletion apps/mobile/src/components/ComposerToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export function ComposerInlineControl(props: {
readonly icon?: ComponentProps<typeof SymbolView>["name"];
readonly renderIcon?: (size: number) => ReactNode;
readonly label: string;
readonly labelEllipsizeMode?: ComponentProps<typeof Text>["ellipsizeMode"];
readonly suffix?: ReactNode;
readonly suffixWidth?: number;
/** Show only the icon and chevron; the label still names the control for accessibility. */
readonly iconOnly?: boolean;
readonly maxWidth?: ViewStyle["maxWidth"];
Expand Down Expand Up @@ -94,13 +96,19 @@ export function ComposerInlineControl(props: {
props.emphasized || props.selected ? "text-foreground" : "text-foreground-muted",
)}
numberOfLines={1}
ellipsizeMode={props.labelEllipsizeMode}
>
{props.label}
</Text>
</Animated.View>
)}
{!props.iconOnly && props.suffix ? (
<View className="min-w-0 shrink">{props.suffix}</View>
<View
className={cn("min-w-0", props.suffixWidth === undefined ? "shrink" : "shrink-0")}
style={{ width: props.suffixWidth }}
>
{props.suffix}
</View>
) : null}
{props.showChevron === false ? null : (
<SymbolView
Expand Down
14 changes: 14 additions & 0 deletions apps/mobile/src/components/ProviderIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,20 @@ export function ProviderIcon(props: ProviderIconProps) {
);
}

/** Local ACP agents share one fallback glyph, so a badge alone cannot tell instances apart. */
export function providerInstanceNameLabel(props: {
readonly provider: string | null | undefined;
readonly iconUrl?: string | null | undefined;
readonly displayName: string;
readonly showBadge: boolean;
}): string | null {
return props.showBadge &&
props.provider === "acpRegistry" &&
resolveOfficialAcpRegistryIconUrl(props.iconUrl) === null
? props.displayName
: null;
}

export function ProviderInstanceIcon(props: {
readonly iconUrl?: string | null;
readonly provider: string | null | undefined;
Expand Down
45 changes: 43 additions & 2 deletions apps/mobile/src/features/threads/thread-list-v2-items.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ import { AppText as Text } from "../../components/ui/AppText";
import { Menu } from "../../components/ui/Menu";
import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSymbol";
import { ProjectFavicon } from "../../components/ProjectFavicon";
import { ProviderIcon, ProviderInstanceIcon } from "../../components/ProviderIcon";
import {
ProviderIcon,
ProviderInstanceIcon,
providerInstanceNameLabel,
} from "../../components/ProviderIcon";
import { useNowAfter } from "../../lib/clock";
import { cn } from "../../lib/cn";
import { copyTextWithHaptic } from "../../lib/copyTextWithHaptic";
Expand Down Expand Up @@ -743,6 +747,14 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: {
}, [thread, props.providers]);

const providerInstance = props.providerInstance;
const providerNameLabel = providerInstance
? providerInstanceNameLabel({
provider: providerInstance.driverKind,
iconUrl: providerIconUrl,
displayName: providerInstance.displayName,
showBadge: providerInstance.showBadge,
})
: null;
const pr = useThreadPr(thread);
const prBadgeLabel = pr ? resolveThreadPrBadgeAction(pr).accessibilityLabel : null;
const handleOpenPullRequests = useCallback(() => {
Expand All @@ -764,7 +776,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: {
: workingLabel) ?? (isUnread ? DONE_STATUS_LABEL : undefined);
const recede = shouldRecedeThreadRow({ status, selected });
const isRegeneratingTitle = thread.titleRegeneration != null;
const rowAccessibilityLabel = `${thread.title}${props.hasQueuedMessages ? ", messages queued to send" : ""}${isRegeneratingTitle ? ", regenerating title" : ""}`;
const rowAccessibilityLabel = `${thread.title}${providerNameLabel ? `, ${providerNameLabel}` : ""}${props.hasQueuedMessages ? ", messages queued to send" : ""}${isRegeneratingTitle ? ", regenerating title" : ""}`;
const timeLabel = props.timeLabel;

const visitThread = useAtomCommand(threadEnvironment.visit, { reportFailure: false });
Expand Down Expand Up @@ -1381,6 +1393,21 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: {
showBadge={providerInstance.showBadge}
surfaceColor={rowAppearance.providerIconSurfaceColor}
/>
{providerNameLabel ? (
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
<Text
className={cn(
"ml-1.5 text-xs",
selected
? selectedThreadRowColors.mutedForegroundClassName
: rowAppearance.tertiaryForegroundClassName,
)}
ellipsizeMode="middle"
numberOfLines={1}
style={{ maxWidth: 140 }}
>
{providerNameLabel}
Comment thread
shivamhwp marked this conversation as resolved.
Resolved
</Text>
) : null}
</View>
) : null}
</View>
Expand Down Expand Up @@ -1474,6 +1501,20 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: {
>
{thread.title}
</Text>
{providerNameLabel ? (
<Text
className={cn(
"text-xs",
selected
? selectedThreadRowColors.mutedForegroundClassName
: rowAppearance.tertiaryForegroundClassName,
)}
ellipsizeMode="middle"
numberOfLines={1}
>
{providerNameLabel}
</Text>
) : null}
{props.searchMatch ? (
<ThreadSearchMatchExcerpt
sidebar={sidebarPane}
Expand Down
Loading