authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-07-09 07:00:51-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-09 14:00:51+00:00
logf61fa9499d96fee825492aba204593c37b27e0cb
treee81d10ce7ecce748dc0793dfecc17bdf23054732
parent8619ef22e9a173678b1ed2d00eae99b329a7c6b6
signature Signed by PGP key B5690EEEBB952194

Expose mobile PR indicator labels to accessibility (#3828)

Co-authored-by: codex <codex@users.noreply.github.com>

3 files changed, 9 insertions(+), 20 deletions(-)

apps/mobile/src/features/threads/thread-list-items.tsx+4-15
......@@ -441,10 +441,8 @@ export const ThreadListRow = memo(function ThreadListRow(props: {
441441 const iconSubtleColor = useThemeColor("--color-icon-subtle");
442442 const screenColor = useThemeColor("--color-screen");
443443 const drawerColor = useThemeColor("--color-drawer");
444 const mutedColor = useThemeColor("--color-foreground-muted");
445444 const pressedBackgroundColor = useThemeColor("--color-subtle");
446445 const selectedBackgroundColor = useThemeColor("--color-user-bubble");
447 const selectedMutedColor = useThemeColor("--color-user-bubble-foreground-muted");
448446
449447 const { thread, onSelectThread, onArchiveThread, onDeleteThread } = props;
450448 const status = resolveThreadStatus(thread);
......@@ -452,12 +450,12 @@ export const ThreadListRow = memo(function ThreadListRow(props: {
452450 const timestamp = relativeTime(
453451 thread.latestUserMessageAt ?? thread.updatedAt ?? thread.createdAt,
454452 );
453 const threadAccessibilityLabel = pr ? `${thread.title}, ${pr.accessibilityLabel}` : thread.title;
455454 const subtitleParts = [props.environmentLabel, thread.branch].filter((part): part is string =>
456455 Boolean(part),
457456 );
458457
459458 const backgroundColor = compact ? screenColor : drawerColor;
460 const effectiveMuted = selected ? selectedMutedColor : mutedColor;
461459 const effectivePressedBackground = selected ? "rgba(255,255,255,0.16)" : pressedBackgroundColor;
462460 const effectiveStatus =
463461 selected && status
......@@ -496,12 +494,6 @@ export const ThreadListRow = memo(function ThreadListRow(props: {
496494 <View className="mt-px flex-row items-center gap-1.5">
497495 {subtitleParts.length > 0 ? (
498496 <>
499 <SymbolView
500 name="arrow.triangle.branch"
501 size={10}
502 tintColor={compact ? iconSubtleColor : effectiveMuted}
503 type="monochrome"
504 />
505497 <Text
506498 className={cn(
507499 "shrink",
......@@ -516,10 +508,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: {
516508 </>
517509 ) : null}
518510 {pr !== null ? (
519 <View
520 accessibilityLabel={pr.accessibilityLabel}
521 className="flex-row items-center gap-0.5"
522 >
511 <View className="flex-row items-center gap-0.5">
523512 <PullRequestIcon
524513 size={compact ? 13 : 11}
525514 color={selected ? "#ffffff" : pullRequestTintColor(pr.state, colorScheme)}
......@@ -540,7 +529,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: {
540529 compact ? (
541530 <Pressable
542531 accessibilityHint="Swipe left for archive and delete actions"
543 accessibilityLabel={thread.title}
532 accessibilityLabel={threadAccessibilityLabel}
544533 accessibilityRole="button"
545534 className="bg-screen"
546535 onPress={() => {
......@@ -586,7 +575,7 @@ export const ThreadListRow = memo(function ThreadListRow(props: {
586575 ) : (
587576 <Pressable
588577 accessibilityHint="Opens the thread"
589 accessibilityLabel={thread.title}
578 accessibilityLabel={threadAccessibilityLabel}
590579 accessibilityRole="button"
591580 accessibilityState={{ selected }}
592581 onHoverIn={() => setHovered(true)}
apps/mobile/src/state/thread-pr-presentation.ts+2-2
......@@ -7,7 +7,7 @@ export interface ThreadPrPresentation {
77 readonly number: number;
88 readonly state: ThreadPr["state"];
99 readonly url: string;
10 /** Compact desktop-style label, e.g. "#3774". */
10 /** Compact pull request number label, e.g. "3774". */
1111 readonly label: string;
1212 /** Full, provider-aware label for assistive technologies. */
1313 readonly accessibilityLabel: string;
......@@ -29,7 +29,7 @@ export function presentThreadPr(
2929 number: pr.number,
3030 state: pr.state,
3131 url: pr.url,
32 label: `#${pr.number}`,
32 label: String(pr.number),
3333 accessibilityLabel: `#${pr.number} ${presentation.longName} ${pr.state}`,
3434 textClassName: PR_STATE_TEXT_CLASS[pr.state],
3535 };
apps/mobile/src/state/use-thread-pr.test.ts+3-3
......@@ -13,9 +13,9 @@ const pullRequest: NonNullable<VcsStatusResult["pr"]> = {
1313};
1414
1515describe("presentThreadPr", () => {
16 it("uses the compact desktop-style pull request number label", () => {
16 it("uses the compact pull request number label without a hash prefix", () => {
1717 expect(presentThreadPr(pullRequest, undefined)).toMatchObject({
18 label: "#3774",
18 label: "3774",
1919 accessibilityLabel: "#3774 pull request merged",
2020 textClassName: "text-violet-600 dark:text-violet-400",
2121 });
......@@ -29,7 +29,7 @@ describe("presentThreadPr", () => {
2929 baseUrl: "https://gitlab.com",
3030 }),
3131 ).toMatchObject({
32 label: "#3774",
32 label: "3774",
3333 accessibilityLabel: "#3774 merge request merged",
3434 });
3535 });