diff --git a/apps/mobile/src/features/threads/thread-list-v2-items.tsx b/apps/mobile/src/features/threads/thread-list-v2-items.tsx
index 69d0c84ecaa8d..e0619fba25018 100644
--- a/apps/mobile/src/features/threads/thread-list-v2-items.tsx
+++ b/apps/mobile/src/features/threads/thread-list-v2-items.tsx
@@ -84,6 +84,7 @@ import {
resolveThreadListV2ProviderDrivers,
resolveThreadListV2SwipeActions,
layoutThreadListV2RowMenuActions,
+ threadListV2RowAccessibilityLabel,
type ThreadListV2Status,
} from "./threadListV2";
import { QueuedMessageIcon } from "./queued-message-icon";
@@ -784,8 +785,20 @@ 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}${providerNameLabel ? `, ${providerNameLabel}` : ""}${props.hasQueuedMessages ? ", messages queued to send" : ""}${isRegeneratingTitle ? ", regenerating title" : ""}`;
const timeLabel = props.timeLabel;
+ const rowAccessibilityLabel = threadListV2RowAccessibilityLabel({
+ title: thread.title,
+ variant,
+ woke: showsWoke,
+ // Working and waiting rows show only an icon and a duration, so name them for speech.
+ statusLabel:
+ statusLabel && (statusLabel.label ?? (status === "waiting" ? "Waiting" : "Working")),
+ timeLabel,
+ snoozeWakeLabel: snoozedRow ? props.snoozeWakeLabelText : undefined,
+ providerNameLabel,
+ hasQueuedMessages: props.hasQueuedMessages === true,
+ regeneratingTitle: isRegeneratingTitle,
+ });
const visitThread = useAtomCommand(threadEnvironment.visit, { reportFailure: false });
const handleAcknowledgeWoke = useCallback(() => {
@@ -1581,7 +1594,12 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: {
threadTitle={thread.title}
>
{(close) => (
-