Skip to content

Conversation

github-actions[bot]
Copy link

@github-actions github-actions bot commented May 6, 2025

The following files were modified by the accessibility bot:

  • ./cards/Home/HomeView.swift
  • ./cards/CreditCard.swift
  • ./cards/Settings/AppSettingsView.swift
  • ./cards/CardView/CardView.swift
View changes
diff --git a/cards/CardView/CardView.swift b/cards/CardView/CardView.swift
index e2f9e43..565638e 100644
--- a/cards/CardView/CardView.swift
+++ b/cards/CardView/CardView.swift
@@ -24,10 +24,14 @@ struct CardView: View {
 		return HStack{
 			Text(heading)
 				.bold()
+				.accessibilityLabel(Text(heading))
 			Spacer()
 			if !model.isAuthenticated {
 				SecureField("", text: value)
 					.multilineTextAlignment(.trailing)
+					.accessibilityLabel(Text(heading))
+					.accessibilityHint(Text("Secure field"))
+					.accessibilityIdentifier("\(heading.lowercased())SecureField")
 			} else {
 				TextField("", text: value)
 					.multilineTextAlignment(.trailing)
@@ -43,6 +47,9 @@ struct CardView: View {
 							Image(systemName: "doc.on.doc")
 						}
 					})
+					.accessibilityLabel(Text(heading))
+					.accessibilityHint(Text(model.isEditing ? "Editable field" : "Read only"))
+					.accessibilityIdentifier("\(heading.lowercased())TextField")
 			}
 		}
         .if (!model.isEditing, transform: { view in
@@ -50,6 +57,8 @@ struct CardView: View {
                 model.copyAction(with: value.wrappedValue)
             })
         })
+        .accessibilityElement(children: .combine)
+        .accessibilityIdentifier("\(heading.lowercased())ItemView")
     }
 
 	fileprivate func getCardListView() -> some View {
@@ -72,6 +81,7 @@ struct CardView: View {
 
 						if heading == "Number" && !model.isEditing {
 							view.popoverTip(tip, arrowEdge: .top)
+								.accessibilityHint(Text("Double tap to copy card number"))
 						} else if heading == "Expiration" {
 							view.onChange(of: model.card.expiration) { _ , newValue in
 								if newValue.count == 2 && !newValue.contains("/") {
@@ -92,19 +102,27 @@ struct CardView: View {
 					Picker("Card Network", selection: $model.card.network) {
 					  ForEach(CardNetwork.allCases) { pref in
 						Text(pref.rawValue)
+							.accessibilityLabel(Text(pref.rawValue))
 					  }
 					}
 
 					.disabled(!model.isEditing)
 					.bold()
+					.accessibilityLabel(Text("Card Network"))
+					.accessibilityHint(Text(model.isEditing ? "Select card network" : "Card network"))
+					.accessibilityIdentifier("cardNetworkPicker")
 				  }
 					Picker("Card Type", selection: $model.card.type) {
 						ForEach(CardType.allCases) { pref in
 							Text(pref.rawValue)
+								.accessibilityLabel(Text(pref.rawValue))
 						}
 					}
 					.disabled(!model.isEditing)
 					.bold()
+					.accessibilityLabel(Text("Card Type"))
+					.accessibilityHint(Text(model.isEditing ? "Select card type" : "Card type"))
+					.accessibilityIdentifier("cardTypePicker")
 				}
 			}
 
@@ -117,6 +135,9 @@ struct CardView: View {
 							view
 							  .blur(radius: 10, opaque: true)
 						})
+						.accessibilityLabel(Text("Card image"))
+						.accessibilityHint(Text(model.isAuthenticated ? "Card image preview" : "Card image is blurred until authenticated"))
+						.accessibilityIdentifier("cardImage")
 				}
 			}
 
@@ -127,7 +148,9 @@ struct CardView: View {
 					VStack(alignment: .leading){
 						  HStack {
 							  Image(systemName: "photo")
+								  .accessibilityHidden(true)
 							  Text(model.cardImage == nil ? "Add Card Image" : "Change Card Image")
+								  .accessibilityLabel(Text(model.cardImage == nil ? "Add Card Image" : "Change Card Image"))
 						  }
 						  .padding(.bottom)
 
@@ -163,9 +186,14 @@ struct CardView: View {
 						} label: {
 							HStack {
 								Image(systemName: "trash")
+									.accessibilityHidden(true)
 								Text("Remove Image")
+									.accessibilityLabel(Text("Remove Image"))
 							}
 						}
+						.accessibilityLabel(Text("Remove Image"))
+						.accessibilityHint(Text("Removes the selected card image"))
+						.accessibilityIdentifier("removeImageButton")
 					}
 				}
 			}
@@ -174,6 +202,9 @@ struct CardView: View {
 			ShareLink(item: model.card.toShareString()) {
 				Label("Click to share", systemImage: "square.and.arrow.up")
 			}
+			.accessibilityLabel(Text("Share card details"))
+			.accessibilityHint(Text("Shares your card details"))
+			.accessibilityIdentifier("shareLink")
 			Button(action: {
 				model.isEditing.toggle()
 				// if user is not editing, then he is done editing when button press
@@ -183,6 +214,9 @@ struct CardView: View {
 			}) {
 				Text(model.isEditing ? "Done" : "Edit")
 			}
+			.accessibilityLabel(Text(model.isEditing ? "Done editing" : "Edit card"))
+			.accessibilityHint(Text(model.isEditing ? "Finish editing card details" : "Edit card details"))
+			.accessibilityIdentifier("editDoneButton")
 		}
 		.disabled(!$model.isAuthenticated.wrappedValue)
 		.toolbar {
@@ -192,10 +226,14 @@ struct CardView: View {
 						model.isShowingScanner = true
 					}, label: {
 						Image(systemName: "camera.on.rectangle")
+							.accessibilityHidden(true)
 					})
 					.if(!model.isAddNewFlow, transform: { view in
 						view.hidden()
 					})
+					.accessibilityLabel(Text("Scan card"))
+					.accessibilityHint(Text("Opens camera to scan your card"))
+					.accessibilityIdentifier("scanCardButton")
 
 					// .screen was causing issues with camera session not closing
 					.fullScreenCover(isPresented: $model.isShowingScanner) {
diff --git a/cards/CreditCard.swift b/cards/CreditCard.swift
index e79114b..65991f7 100644
--- a/cards/CreditCard.swift
+++ b/cards/CreditCard.swift
@@ -16,6 +16,7 @@ struct CreditCard: App {
     var body: some Scene {
         WindowGroup {
             HomeView()
+                .accessibilityIdentifier("HomeView")
                 .task {
                     try? Tips.configure([
                         .displayFrequency(.immediate),
diff --git a/cards/Home/HomeView.swift b/cards/Home/HomeView.swift
index 86d5dd2..a3f5926 100644
--- a/cards/Home/HomeView.swift
+++ b/cards/Home/HomeView.swift
@@ -19,6 +19,7 @@ struct HomeView: View {
 					Section(header: Text("\(type.rawValue)s")){
 						ForEach(model.cardDataStore.cardsByType[type] ?? [], id: \.id) { card in
 							getRowforCards(with: card)
+								.accessibilityIdentifier("CardRow_\(card.id.uuidString)")
 						}
 						.onDelete { offsets in
 							model.deleteCard(at: offsets, inSection: type)
@@ -26,6 +27,9 @@ struct HomeView: View {
 						Button("Add a new \(type.rawValue)") {
 							model.showingPopover.toggle()
 						}
+						.accessibilityLabel(Text("Add a new \(type.rawValue) card"))
+						.accessibilityHint(Text("Adds a new \(type.rawValue) card"))
+						.accessibilityIdentifier("AddCardButton_\(type.rawValue)")
 						.sheet(isPresented: $model.showingPopover) {
 							NavigationView {
 								CardView(model: CardViewModel(
@@ -50,6 +54,7 @@ struct HomeView: View {
 					}
 				}
 			.navigationTitle("Cards")
+			.accessibilityLabel(Text("Cards"))
 			.onAppear {
 				model.cardDataStore.loadCards()
 			}
@@ -57,14 +62,23 @@ struct HomeView: View {
                 NavigationLink(destination: SettingsView(model: SettingsViewModel())){
 					Image(systemName: "gear")
 				}
+				.accessibilityLabel(Text("Settings"))
+				.accessibilityHint(Text("Opens settings"))
+				.accessibilityIdentifier("SettingsButton")
 			}
 			.alert("Enable Biometrics",isPresented: model.$isFirstLaunch, actions: {
 				Button("Yes", role: .cancel) { 
 					UserSettings.shared.isAuthEnabled = true
 				}
+				.accessibilityLabel(Text("Enable biometrics"))
+				.accessibilityHint(Text("Enables biometric authentication"))
+				.accessibilityIdentifier("EnableBiometricsYesButton")
 				Button("No", role: .destructive) { 
 					UserSettings.shared.isAuthEnabled = false
 				}
+				.accessibilityLabel(Text("Do not enable biometrics"))
+				.accessibilityHint(Text("Disables biometric authentication"))
+				.accessibilityIdentifier("EnableBiometricsNoButton")
 			})
 		} detail: {
 			if let card = model.selectedCard {
@@ -76,6 +90,8 @@ struct HomeView: View {
 			} 
 			else {
 				Text("Tap on a Card to view details")
+					.accessibilityLabel(Text("No card selected. Tap on a card to view details."))
+					.accessibilityIdentifier("NoCardSelectedText")
 			}
 		}
 		.whatsNewSheet()
@@ -88,16 +104,31 @@ struct HomeView: View {
 					.resizable()
 					.scaledToFit()
 					.frame(width: 36,height: 36)
+					.accessibilityLabel(Text("\(card.network.rawValue) logo"))
+					.accessibilityIdentifier("CardNetworkImage_\(card.id.uuidString)")
 
 				VStack(alignment: .leading){
 					if card.description != "" {
 						Text(card.description)
+							.accessibilityLabel(Text(card.description))
+							.accessibilityIdentifier("CardDescription_\(card.id.uuidString)")
+							.minimumScaleFactor(0.8)
 					} else {
 						Text(card.name)
+							.accessibilityLabel(Text(card.name))
+							.accessibilityIdentifier("CardName_\(card.id.uuidString)")
+							.minimumScaleFactor(0.8)
 					}
 					Text(card.number.toSecureCard())
+						.accessibilityLabel(Text("Card number ending in \(card.number.suffix(4))"))
+						.accessibilityIdentifier("CardNumber_\(card.id.uuidString)")
+						.minimumScaleFactor(0.8)
 				}
 			}
+			.accessibilityElement(children: .combine)
+			.accessibilityLabel(Text("\(card.description != "" ? card.description : card.name), card ending in \(card.number.suffix(4)), \(card.network.rawValue)"))
+			.accessibilityHint(Text("Double tap to view card details"))
+			.accessibilityIdentifier("CardRow_\(card.id.uuidString)")
 		}
 	}
 }
diff --git a/cards/Settings/AppSettingsView.swift b/cards/Settings/AppSettingsView.swift
index 7e8c646..df92ff4 100644
--- a/cards/Settings/AppSettingsView.swift
+++ b/cards/Settings/AppSettingsView.swift
@@ -12,15 +12,28 @@ struct AppSettingsView: View {
         AnyView (
             Section {
                 Toggle("Toggle Biometrics", isOn: UserSettings.shared.$isAuthEnabled)
+                    .accessibilityLabel("Enable biometric authentication")
+                    .accessibilityHint("Double tap to enable or disable biometric authentication for app security")
+                    .accessibilityIdentifier("toggleBiometrics")
+                    .focusable(true)
                 HStack(alignment: .center){
                     Text("Timeout (in seconds)")
+                        .accessibilityLabel("Authentication timeout in seconds")
+                        .accessibilityIdentifier("timeoutLabel")
                     Spacer()
                     TextField("", value: UserSettings.shared.$authTimeout, format: .number)
                         .keyboardType(.numberPad)
                         .fixedSize()
+                        .accessibilityLabel("Timeout value")
+                        .accessibilityHint("Enter the number of seconds before authentication times out")
+                        .accessibilityIdentifier("timeoutTextField")
+                        .focusable(true)
                 }
+                .accessibilityElement(children: .combine)
                 VStack(alignment: .leading){
                     Text("Number of card digits visible on home (Restart Required)")
+                        .accessibilityLabel("Number of card digits visible on home. Restart required.")
+                        .accessibilityIdentifier("cardDigitsLabel")
                     Slider(value: UserSettings.shared.$showNumber, in: 1...10,step: 1) {
                         Text("Steps")
                     } minimumValueLabel: {
@@ -28,9 +41,16 @@ struct AppSettingsView: View {
                     } maximumValueLabel:  {
                         Text("10")
                     }
+                    .accessibilityLabel("Number of visible card digits")
+                    .accessibilityHint("Adjust to set how many card digits are visible on the home screen. Restart required.")
+                    .accessibilityIdentifier("cardDigitsSlider")
+                    .focusable(true)
                 }
+                .accessibilityElement(children: .combine)
             } header: {
                 Text("App Settings")
+                    .accessibilityAddTraits(.isHeader)
+                    .accessibilityIdentifier("appSettingsHeader")
             }
         )
     }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants