From e4b77744940f30fe21413542df5c5cf669da895b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 19:54:59 +0000 Subject: [PATCH 1/2] [jules] a11y: Complete accessibility labels for all mobile screens Co-authored-by: Devasy <110348311+Devasy@users.noreply.github.com> --- .Jules/changelog.md | 8 ++++++++ .Jules/knowledge.md | 11 +++++++++++ .Jules/todo.md | 3 ++- mobile/screens/AccountScreen.js | 10 ++++++++++ mobile/screens/AddExpenseScreen.js | 19 ++++++++++++++++++- mobile/screens/EditProfileScreen.js | 6 ++++++ mobile/screens/FriendsScreen.js | 13 ++++++++++++- mobile/screens/GroupDetailsScreen.js | 12 +++++++++++- mobile/screens/GroupSettingsScreen.js | 17 +++++++++++++++++ mobile/screens/HomeScreen.js | 15 ++++++++++++++- mobile/screens/JoinGroupScreen.js | 3 +++ mobile/screens/LoginScreen.js | 12 +++++++++++- mobile/screens/SignupScreen.js | 15 ++++++++++++++- mobile/screens/SplitwiseImportScreen.js | 3 +++ 14 files changed, 140 insertions(+), 7 deletions(-) diff --git a/.Jules/changelog.md b/.Jules/changelog.md index b3cfda1d..007d6531 100644 --- a/.Jules/changelog.md +++ b/.Jules/changelog.md @@ -7,6 +7,14 @@ ## [Unreleased] ### Added +- **Mobile Accessibility:** Completed accessibility audit for all mobile screens. + - **Features:** + - Added `accessibilityLabel` to all interactive elements (buttons, inputs, list items). + - Added `accessibilityRole` to ensure screen readers identify element types correctly. + - Added `accessibilityHint` for clearer context on destructive actions or complex interactions. + - Covered Auth, Dashboard, Groups, and Utility screens. + - **Technical:** Updated all files in `mobile/screens/` to compliant with React Native accessibility standards. + - **Mobile Pull-to-Refresh:** Implemented native pull-to-refresh interactions with haptic feedback for key lists. - **Features:** - Integrated `RefreshControl` into `HomeScreen`, `FriendsScreen`, and `GroupDetailsScreen`. diff --git a/.Jules/knowledge.md b/.Jules/knowledge.md index 3361c5da..43a9ab01 100644 --- a/.Jules/knowledge.md +++ b/.Jules/knowledge.md @@ -306,6 +306,17 @@ Commonly used components: Most screens use `` - consider wrapping in `SafeAreaView` for notched devices. +### Accessibility Patterns + +**Date:** 2026-01-29 +**Context:** Auditing and fixing mobile accessibility + +When building mobile screens with React Native Paper: +1. **Explicit Labels:** Always add `accessibilityLabel` to `IconButton`, `FAB`, and `Card` components that act as buttons. +2. **Roles:** Use `accessibilityRole="button"` for pressable elements, `accessibilityRole="header"` for titles. +3. **Hints:** Use `accessibilityHint` for non-obvious actions (e.g., "Double tap to delete"). +4. **State:** For custom checkboxes or toggles, use `accessibilityState={{ checked: boolean }}`. + --- ## API Response Patterns diff --git a/.Jules/todo.md b/.Jules/todo.md index 7797cfbe..de49cb80 100644 --- a/.Jules/todo.md +++ b/.Jules/todo.md @@ -64,7 +64,8 @@ - Size: ~40 lines - Added: 2026-01-01 -- [ ] **[a11y]** Complete accessibility labels for all screens +- [x] **[a11y]** Complete accessibility labels for all screens + - Completed: 2026-01-29 - Files: All screens in `mobile/screens/` - Context: Add accessibilityLabel, accessibilityHint, accessibilityRole throughout - Impact: Screen reader users can use app fully diff --git a/mobile/screens/AccountScreen.js b/mobile/screens/AccountScreen.js index 5c735040..c0ee6748 100644 --- a/mobile/screens/AccountScreen.js +++ b/mobile/screens/AccountScreen.js @@ -39,30 +39,40 @@ const AccountScreen = ({ navigation }) => { title="Edit Profile" left={() => } onPress={() => navigation.navigate("EditProfile")} + accessibilityLabel="Edit Profile" + accessibilityRole="button" /> } onPress={handleComingSoon} + accessibilityLabel="Email Settings" + accessibilityRole="button" /> } onPress={handleComingSoon} + accessibilityLabel="Send Feedback" + accessibilityRole="button" /> } onPress={() => navigation.navigate("SplitwiseImport")} + accessibilityLabel="Import from Splitwise" + accessibilityRole="button" /> } onPress={handleLogout} + accessibilityLabel="Logout" + accessibilityRole="button" /> diff --git a/mobile/screens/AddExpenseScreen.js b/mobile/screens/AddExpenseScreen.js index 59cb65ed..f5f58a3d 100644 --- a/mobile/screens/AddExpenseScreen.js +++ b/mobile/screens/AddExpenseScreen.js @@ -282,6 +282,11 @@ const AddExpenseScreen = ({ route, navigation }) => { label={member.user.name} status={selectedMembers[member.userId] ? "checked" : "unchecked"} onPress={() => handleMemberSelect(member.userId)} + accessibilityLabel={`Select ${member.user.name}`} + accessibilityRole="checkbox" + accessibilityState={{ + checked: !!selectedMembers[member.userId], + }} /> )); case "exact": @@ -295,6 +300,7 @@ const AddExpenseScreen = ({ route, navigation }) => { } keyboardType="numeric" style={styles.splitInput} + accessibilityLabel={`${member.user.name}'s exact amount`} /> )); case "percentage": @@ -308,6 +314,7 @@ const AddExpenseScreen = ({ route, navigation }) => { } keyboardType="numeric" style={styles.splitInput} + accessibilityLabel={`${member.user.name}'s percentage`} /> )); case "shares": @@ -321,6 +328,7 @@ const AddExpenseScreen = ({ route, navigation }) => { } keyboardType="numeric" style={styles.splitInput} + accessibilityLabel={`${member.user.name}'s shares`} /> )); default: @@ -351,6 +359,7 @@ const AddExpenseScreen = ({ route, navigation }) => { value={description} onChangeText={setDescription} style={styles.input} + accessibilityLabel="Expense Description" /> { onChangeText={setAmount} style={styles.input} keyboardType="numeric" + accessibilityLabel="Expense Amount" /> setMenuVisible(false)} anchor={ - } @@ -442,6 +457,8 @@ const AddExpenseScreen = ({ route, navigation }) => { style={styles.button} loading={isSubmitting} disabled={isSubmitting} + accessibilityLabel="Add Expense" + accessibilityRole="button" > Add Expense diff --git a/mobile/screens/EditProfileScreen.js b/mobile/screens/EditProfileScreen.js index 8201b708..33a8faf1 100644 --- a/mobile/screens/EditProfileScreen.js +++ b/mobile/screens/EditProfileScreen.js @@ -103,6 +103,9 @@ const EditProfileScreen = ({ navigation }) => { onPress={pickImage} icon="camera" style={styles.imageButton} + accessibilityLabel="Change profile picture" + accessibilityRole="button" + accessibilityHint="Opens your media library to select a new photo" > {pickedImage ? "Change Photo" : "Add Photo"} @@ -113,6 +116,7 @@ const EditProfileScreen = ({ navigation }) => { value={name} onChangeText={setName} style={styles.input} + accessibilityLabel="Full Name" /> diff --git a/mobile/screens/FriendsScreen.js b/mobile/screens/FriendsScreen.js index b145efde..ad9bea24 100644 --- a/mobile/screens/FriendsScreen.js +++ b/mobile/screens/FriendsScreen.js @@ -100,6 +100,11 @@ const FriendsScreen = () => { descriptionStyle={{ color: item.netBalance !== 0 ? balanceColor : "gray", }} + accessibilityRole="button" + accessibilityLabel={`Friend ${item.name}. ${ + item.netBalance !== 0 ? balanceText : "Settled up" + }`} + accessibilityHint="Double tap to see balance breakdown" left={(props) => imageUri ? ( @@ -207,7 +212,11 @@ const FriendsScreen = () => { - + {Array.from({ length: 5 }).map((_, i) => ( ))} @@ -234,6 +243,8 @@ const FriendsScreen = () => { size={16} onPress={() => setShowTooltip(false)} style={styles.closeButton} + accessibilityLabel="Close tooltip" + accessibilityRole="button" /> diff --git a/mobile/screens/GroupDetailsScreen.js b/mobile/screens/GroupDetailsScreen.js index 8913a351..bcb0018e 100644 --- a/mobile/screens/GroupDetailsScreen.js +++ b/mobile/screens/GroupDetailsScreen.js @@ -68,6 +68,8 @@ const GroupDetailsScreen = ({ route, navigation }) => { navigation.navigate("GroupSettings", { groupId })} + accessibilityLabel="Group settings" + accessibilityRole="button" /> ), }); @@ -101,7 +103,13 @@ const GroupDetailsScreen = ({ route, navigation }) => { } return ( - + {item.description} Amount: {formatCurrency(item.amount)} @@ -227,6 +235,8 @@ const GroupDetailsScreen = ({ route, navigation }) => { style={styles.fab} icon="plus" onPress={() => navigation.navigate("AddExpense", { groupId: groupId })} + accessibilityLabel="Add expense" + accessibilityRole="button" /> ); diff --git a/mobile/screens/GroupSettingsScreen.js b/mobile/screens/GroupSettingsScreen.js index 90de5d16..0df56ebb 100644 --- a/mobile/screens/GroupSettingsScreen.js +++ b/mobile/screens/GroupSettingsScreen.js @@ -280,6 +280,8 @@ const GroupSettingsScreen = ({ route, navigation }) => { onKick(m.userId, displayName)} + accessibilityLabel={`Remove ${displayName} from group`} + accessibilityRole="button" /> ) : null } @@ -307,6 +309,7 @@ const GroupSettingsScreen = ({ route, navigation }) => { onChangeText={setName} editable={!!isAdmin} style={{ marginBottom: 12 }} + accessibilityLabel="Group Name" /> Icon @@ -317,6 +320,8 @@ const GroupSettingsScreen = ({ route, navigation }) => { style={styles.iconBtn} onPress={() => setIcon(i)} disabled={!isAdmin} + accessibilityLabel={`Select icon ${i}`} + accessibilityRole="button" > {i} @@ -329,6 +334,8 @@ const GroupSettingsScreen = ({ route, navigation }) => { disabled={!isAdmin} icon="image" style={{ marginRight: 12 }} + accessibilityLabel="Change group image" + accessibilityRole="button" > {pickedImage ? "Change Image" : "Upload Image"} @@ -354,6 +361,8 @@ const GroupSettingsScreen = ({ route, navigation }) => { loading={saving} disabled={saving} onPress={onSave} + accessibilityLabel="Save Changes" + accessibilityRole="button" > Save Changes @@ -376,6 +385,8 @@ const GroupSettingsScreen = ({ route, navigation }) => { mode="outlined" onPress={onShareInvite} icon="share-variant" + accessibilityLabel="Share invite code" + accessibilityRole="button" > Share invite @@ -392,6 +403,9 @@ const GroupSettingsScreen = ({ route, navigation }) => { textColor="#d32f2f" onPress={onLeave} icon="logout-variant" + accessibilityLabel="Leave Group" + accessibilityRole="button" + accessibilityHint="You must settle balances before leaving" > Leave Group @@ -402,6 +416,9 @@ const GroupSettingsScreen = ({ route, navigation }) => { onPress={onDeleteGroup} icon="delete" style={{ marginTop: 8 }} + accessibilityLabel="Delete Group" + accessibilityRole="button" + accessibilityHint="Permanently deletes the group and all data" > Delete Group diff --git a/mobile/screens/HomeScreen.js b/mobile/screens/HomeScreen.js index ada77b58..373bb0ab 100644 --- a/mobile/screens/HomeScreen.js +++ b/mobile/screens/HomeScreen.js @@ -185,6 +185,9 @@ const HomeScreen = ({ navigation }) => { groupIcon, }) } + accessibilityRole="button" + accessibilityLabel={`Group ${item.name}. ${getSettlementStatusText()}`} + accessibilityHint="Double tap to view group details" > { value={newGroupName} onChangeText={setNewGroupName} style={styles.input} + accessibilityLabel="New group name" /> @@ -233,12 +239,19 @@ const HomeScreen = ({ navigation }) => { - + navigation.navigate("JoinGroup", { onGroupJoined: fetchGroups }) } + accessibilityLabel="Join a group" + accessibilityRole="button" /> diff --git a/mobile/screens/JoinGroupScreen.js b/mobile/screens/JoinGroupScreen.js index 153e4eac..a1fc05b0 100644 --- a/mobile/screens/JoinGroupScreen.js +++ b/mobile/screens/JoinGroupScreen.js @@ -46,6 +46,7 @@ const JoinGroupScreen = ({ navigation, route }) => { onChangeText={setJoinCode} style={styles.input} autoCapitalize="characters" + accessibilityLabel="Group Join Code" /> diff --git a/mobile/screens/LoginScreen.js b/mobile/screens/LoginScreen.js index 076e9956..aa5e94a1 100644 --- a/mobile/screens/LoginScreen.js +++ b/mobile/screens/LoginScreen.js @@ -32,6 +32,7 @@ const LoginScreen = ({ navigation }) => { style={styles.input} keyboardType="email-address" autoCapitalize="none" + accessibilityLabel="Email address" /> { onChangeText={setPassword} style={styles.input} secureTextEntry + accessibilityLabel="Password" /> - diff --git a/mobile/screens/SignupScreen.js b/mobile/screens/SignupScreen.js index 5594be60..c3ba18f5 100644 --- a/mobile/screens/SignupScreen.js +++ b/mobile/screens/SignupScreen.js @@ -43,6 +43,7 @@ const SignupScreen = ({ navigation }) => { onChangeText={setName} style={styles.input} autoCapitalize="words" + accessibilityLabel="Full Name" /> { style={styles.input} keyboardType="email-address" autoCapitalize="none" + accessibilityLabel="Email address" /> { onChangeText={setPassword} style={styles.input} secureTextEntry + accessibilityLabel="Password" /> { onChangeText={setConfirmPassword} style={styles.input} secureTextEntry + accessibilityLabel="Confirm Password" /> - diff --git a/mobile/screens/SplitwiseImportScreen.js b/mobile/screens/SplitwiseImportScreen.js index 6d1b06fb..8abf5cd6 100644 --- a/mobile/screens/SplitwiseImportScreen.js +++ b/mobile/screens/SplitwiseImportScreen.js @@ -66,6 +66,9 @@ const SplitwiseImportScreen = ({ navigation }) => { style={styles.button} icon={loading ? undefined : "login"} loading={loading} + accessibilityLabel="Connect with Splitwise" + accessibilityRole="button" + accessibilityHint="Opens Splitwise in your browser to authorize access" > {loading ? "Connecting..." : "Connect with Splitwise"} From f1207295c973bf3ac0a2bfaaf90b3bfe3b7f1e3b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 31 Jan 2026 05:18:52 +0000 Subject: [PATCH 2/2] [jules] a11y: Add accessibility hints for destructive actions Co-authored-by: Devasy <110348311+Devasy@users.noreply.github.com> --- mobile/screens/AccountScreen.js | 1 + mobile/screens/GroupSettingsScreen.js | 1 + 2 files changed, 2 insertions(+) diff --git a/mobile/screens/AccountScreen.js b/mobile/screens/AccountScreen.js index c0ee6748..c4ed8698 100644 --- a/mobile/screens/AccountScreen.js +++ b/mobile/screens/AccountScreen.js @@ -73,6 +73,7 @@ const AccountScreen = ({ navigation }) => { onPress={handleLogout} accessibilityLabel="Logout" accessibilityRole="button" + accessibilityHint="Logs you out of the application" /> diff --git a/mobile/screens/GroupSettingsScreen.js b/mobile/screens/GroupSettingsScreen.js index 0df56ebb..f45c099a 100644 --- a/mobile/screens/GroupSettingsScreen.js +++ b/mobile/screens/GroupSettingsScreen.js @@ -282,6 +282,7 @@ const GroupSettingsScreen = ({ route, navigation }) => { onPress={() => onKick(m.userId, displayName)} accessibilityLabel={`Remove ${displayName} from group`} accessibilityRole="button" + accessibilityHint="Removes this member from the group" /> ) : null }