diff --git a/LoopKitUI/Views/CardList/CardList.swift b/LoopKitUI/Views/CardList/CardList.swift index 14ed0aeee..3ca095cd2 100644 --- a/LoopKitUI/Views/CardList/CardList.swift +++ b/LoopKitUI/Views/CardList/CardList.swift @@ -63,6 +63,7 @@ public struct CardList: View { VStack(spacing: 4) { titleText .fixedSize(horizontal: false, vertical: true) + .accessibilityIdentifier("titleText_TherapySettings") cards if let trailer = trailer { diff --git a/LoopKitUI/Views/ChartTableViewCell.swift b/LoopKitUI/Views/ChartTableViewCell.swift index 6576fbbcb..e0ea8895f 100644 --- a/LoopKitUI/Views/ChartTableViewCell.swift +++ b/LoopKitUI/Views/ChartTableViewCell.swift @@ -26,6 +26,8 @@ public final class ChartTableViewCell: UITableViewCell { public var doesNavigate: Bool = true { didSet { rightArrowHint?.isHidden = !doesNavigate + rightArrowHint?.accessibilityIdentifier = + "image_navigateToGlucoseDetails_\(doesNavigate)" } } diff --git a/LoopKitUI/Views/ConfigurationPage.swift b/LoopKitUI/Views/ConfigurationPage.swift index 13611ce8c..e51b1b80a 100644 --- a/LoopKitUI/Views/ConfigurationPage.swift +++ b/LoopKitUI/Views/ConfigurationPage.swift @@ -52,6 +52,7 @@ public struct ConfigurationPage: View { .buttonStyle(ActionButtonStyle(.primary)) .disabled(actionButtonState != .enabled) .padding() + .accessibilityIdentifier("button_confirmSave") } .padding(.bottom) // FIXME: unnecessary on iPhone 8 size devices .background(Color(.secondarySystemGroupedBackground).shadow(radius: 5)) diff --git a/LoopKitUI/Views/GuardrailConstraintedQuantityView.swift b/LoopKitUI/Views/GuardrailConstraintedQuantityView.swift index 9fd33d7ad..c25931290 100644 --- a/LoopKitUI/Views/GuardrailConstraintedQuantityView.swift +++ b/LoopKitUI/Views/GuardrailConstraintedQuantityView.swift @@ -57,11 +57,13 @@ public struct GuardrailConstrainedQuantityView: View { Image(systemName: "exclamationmark.triangle.fill") .foregroundColor(warningColor) .transition(.springInDisappear) + .accessibilityIdentifier(accessibilityIdentifier) } Text(formatter.string(from: value!.doubleValue(for: unit)) ?? "\(value!.doubleValue(for: unit))") .foregroundColor(warningColor) .fixedSize(horizontal: true, vertical: false) + .accessibilityIdentifier("text_setGlucoseValue") } else { Text("–") .foregroundColor(.secondary) @@ -109,6 +111,25 @@ public struct GuardrailConstrainedQuantityView: View { } } } + + private var accessibilityIdentifier: String { + guard let value = value else { + return "noWarningImage" + } + + + switch guardrail.classification(for: value) { + case .withinRecommendedRange: + return "noWarningImage" + case .outsideRecommendedRange(let threshold): + switch threshold { + case .minimum, .maximum: + return "imageNextToText_warningTriangleRed" + case .belowRecommended, .aboveRecommended: + return "imageNextToText_warningTriangleOrange" + } + } + } } fileprivate extension AnyTransition { diff --git a/LoopKitUI/Views/Information Screens/GlucoseTherapySettingInformationView.swift b/LoopKitUI/Views/Information Screens/GlucoseTherapySettingInformationView.swift index 66f2d8ec3..ae619e1cd 100644 --- a/LoopKitUI/Views/Information Screens/GlucoseTherapySettingInformationView.swift +++ b/LoopKitUI/Views/Information Screens/GlucoseTherapySettingInformationView.swift @@ -82,6 +82,9 @@ public struct GlucoseTherapySettingInformationView: View { Text(therapySetting.guardrailInformationText) } .fixedSize(horizontal: false, vertical: true) + .accessibilityIdentifier( + "text_\(self.therapySetting.title.replacing(" ", with: ""))Information" + ) } private var illustrationImageName: String { diff --git a/LoopKitUI/Views/Information Screens/InformationView.swift b/LoopKitUI/Views/Information Screens/InformationView.swift index 71458e2ae..b08cbe418 100644 --- a/LoopKitUI/Views/Information Screens/InformationView.swift +++ b/LoopKitUI/Views/Information Screens/InformationView.swift @@ -93,16 +93,18 @@ struct InformationView : View { .font(.largeTitle) .bold() .fixedSize(horizontal: false, vertical: true) + .accessibilityIdentifier("titleText_therapySettingsEducationTitle") } private var cancelButton: some View { Button(action: onExit, label: { Text(LocalizedString("Close", comment: "Text to close informational page")) }) + .accessibilityIdentifier("button_close") } private var nextPageButton: some View { Button(action: onExit) { buttonText .actionButtonStyle(.primary) - } + }.accessibilityIdentifier("button_continue") } } diff --git a/LoopKitUI/Views/NewScheduleItemEditor.swift b/LoopKitUI/Views/NewScheduleItemEditor.swift index 776f4019c..4ce90e674 100644 --- a/LoopKitUI/Views/NewScheduleItemEditor.swift +++ b/LoopKitUI/Views/NewScheduleItemEditor.swift @@ -41,12 +41,12 @@ struct NewScheduleItemEditor: View { var body: some View { VStack(spacing: 0) { ModalHeaderButtonBar( - leading: { cancelButton }, + leading: { cancelButton.accessibilityIdentifier("button_cancelNewEntry") }, center: { Text(LocalizedString("New Entry", comment: "Title for mini-modal to add a new schedule entry")) .font(.headline) }, - trailing: { addButton } + trailing: { addButton.accessibilityIdentifier("button_addNewEntry") } ) ScheduleItemPicker( diff --git a/LoopKitUI/Views/ScheduleEditor.swift b/LoopKitUI/Views/ScheduleEditor.swift index 4f0c12615..6eb42b1b1 100644 --- a/LoopKitUI/Views/ScheduleEditor.swift +++ b/LoopKitUI/Views/ScheduleEditor.swift @@ -285,8 +285,7 @@ struct ScheduleEditor Binding { @@ -365,7 +364,7 @@ struct ScheduleEditor= scheduleItemLimit) + .accessibilityIdentifier("button_add") } private func startSaving() { diff --git a/LoopKitUI/Views/Settings Editors/InsulinModelSelection.swift b/LoopKitUI/Views/Settings Editors/InsulinModelSelection.swift index eb0ff2e7f..6245d0d86 100644 --- a/LoopKitUI/Views/Settings Editors/InsulinModelSelection.swift +++ b/LoopKitUI/Views/Settings Editors/InsulinModelSelection.swift @@ -125,6 +125,7 @@ public struct InsulinModelSelection: View { // Styling to mimic the floating button of a ConfigurationPage .padding(.bottom) .background(Color(.secondarySystemGroupedBackground).shadow(radius: 5)) + .accessibilityIdentifier("button_confirmSave") } .supportedInterfaceOrientations(.portrait) .edgesIgnoringSafeArea(.bottom) diff --git a/LoopKitUI/Views/Settings Editors/TherapySettingsView.swift b/LoopKitUI/Views/Settings Editors/TherapySettingsView.swift index 175039780..7c35332a5 100644 --- a/LoopKitUI/Views/Settings Editors/TherapySettingsView.swift +++ b/LoopKitUI/Views/Settings Editors/TherapySettingsView.swift @@ -142,6 +142,7 @@ public struct TherapySettingsView: View { } .buttonStyle(ActionButtonStyle(.primary)) .padding() + .accessibilityIdentifier("button_\(actionButton.localizedString.lowercased())") } } } @@ -156,8 +157,10 @@ extension TherapySettingsView { VStack(alignment: .leading) { Text(LocalizedString("Prescription", comment: "title for prescription section")) .bold() + .accessibilityIdentifier("titleText_Prescription") Spacer() DescriptiveText(label: prescriptionDescriptiveText) + .accessibilityIdentifier("descriptiveText_Prescription") } Spacer() } @@ -211,7 +214,7 @@ extension TherapySettingsView { isEditing: false, // Workaround for strange animation behavior on appearance forceDisableAnimations: true - ) + ).accessibilityIdentifier("glucoseSafetyLimitValue") } } } @@ -229,6 +232,7 @@ extension TherapySettingsView { range: items[index].value, unit: glucoseUnit, guardrail: .correctionRange) + .accessibilityIdentifier("correctionRangeValue") } } } @@ -245,7 +249,7 @@ extension TherapySettingsView { preset: CorrectionRangeOverrides.Preset.preMeal, suspendThreshold: viewModel.suspendThreshold, correctionRangeScheduleRange: schedule.scheduleRange() - ) + ).accessibilityIdentifier("preMealPresetValue") } } } @@ -261,7 +265,7 @@ extension TherapySettingsView { preset: CorrectionRangeOverrides.Preset.workout, suspendThreshold: self.viewModel.suspendThreshold, correctionRangeScheduleRange: schedule.scheduleRange() - ) + ).accessibilityIdentifier("workoutPresetValue") } } } @@ -282,6 +286,7 @@ extension TherapySettingsView { value: items[index].value, unit: .internationalUnitsPerHour, guardrail: .basalRate(supportedBasalRates: supportedBasalRates)) + .accessibilityIdentifier("basalRateValue") } SectionDivider() HStack { @@ -289,10 +294,11 @@ extension TherapySettingsView { .bold() .foregroundColor(.primary) Spacer() - Text(String(format: "%.2f ",total)) + (Text(String(format: "%.2f ",total)) .foregroundColor(.primary) + Text(NSLocalizedString("U/day", comment: "The text indicating U/day for Daily Schedule Basal")) - .foregroundColor(.secondary) + .foregroundColor(.secondary)) + .accessibilityIdentifier("basalRateTotalValue") } } } @@ -322,7 +328,7 @@ extension TherapySettingsView { isEditing: false, // Workaround for strange animation behavior on appearance forceDisableAnimations: true - ) + ).accessibilityIdentifier("maxBasalRateValue") } } .accessibilityElement(children: .combine) @@ -340,7 +346,7 @@ extension TherapySettingsView { isEditing: false, // Workaround for strange animation behavior on appearance forceDisableAnimations: true - ) + ).accessibilityIdentifier("maxBolusValue") } } .accessibilityElement(children: .combine) @@ -385,6 +391,7 @@ extension TherapySettingsView { value: items[index].value, unit: .gramsPerUnit, guardrail: .carbRatio) + .accessibilityIdentifier("carbRatioValue") } } } @@ -402,6 +409,7 @@ extension TherapySettingsView { value: items[index].value, unit: sensitivityUnit, guardrail: .insulinSensitivity) + .accessibilityIdentifier("insulinSensitivityValue") } } } @@ -577,10 +585,12 @@ struct SectionWithTapToEdit: View where Content: VStack(alignment: .leading) { Text(title) .bold() + .accessibilityIdentifier("titleText_\(title.replacingOccurrences(of: " ", with: ""))") Spacer() HStack { DescriptiveText(label: descriptiveText) .fixedSize(horizontal: false, vertical: true) + .accessibilityIdentifier("descriptiveText_\(title.replacingOccurrences(of: " ", with: ""))") Spacer() if isEnabled { NavigationLink(destination: destination(onFinish), isActive: $isActive) { diff --git a/LoopKitUI/Views/WarningView.swift b/LoopKitUI/Views/WarningView.swift index ff0c5526a..1f39e7dc3 100644 --- a/LoopKitUI/Views/WarningView.swift +++ b/LoopKitUI/Views/WarningView.swift @@ -36,11 +36,13 @@ public struct WarningView: View { HStack(alignment: .center) { Image(systemName: "exclamationmark.triangle.fill") .foregroundColor(warningColor) + .accessibilityIdentifier(accessibilityIdentifier) title .font(Font(UIFont.preferredFont(forTextStyle: .title3))) .bold() .fixedSize(horizontal: false, vertical: true) + .accessibilityIdentifier("text_guardrailWarning") } .padding(.bottom, 2) @@ -63,4 +65,13 @@ public struct WarningView: View { return guidanceColors.critical } } + + private var accessibilityIdentifier: String { + switch severity { + case .default: + return "image_warningTriangleOrange" + case .critical: + return "image_warningTriangleRed" + } + } }