From 448a5b9bcfc8f2f0efbef84c208bdf1146273eee Mon Sep 17 00:00:00 2001 From: Andreas Bauer Date: Fri, 23 Feb 2024 23:28:49 -0800 Subject: [PATCH 1/3] Improve accessibility for tiles view --- .../xcshareddata/swiftpm/Package.resolved | 20 +++--- NAMS/Patients/CurrentPatientLabel.swift | 1 + NAMS/Patients/PatientInformation.swift | 1 + NAMS/Patients/Tasks/ScreeningTask.swift | 4 ++ NAMS/Resources/Localizable.xcstrings | 3 + NAMS/Tiles/MeasurementTile.swift | 18 ++--- NAMS/Tiles/ScreeningTile.swift | 15 ++-- NAMS/Tiles/ScreeningTileHeader.swift | 1 + NAMS/Tiles/SimpleTile.swift | 71 ++++++++++++++++--- 9 files changed, 93 insertions(+), 41 deletions(-) diff --git a/NAMS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NAMS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7de7ed8..8c3cf44 100644 --- a/NAMS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/NAMS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -113,8 +113,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/promises.git", "state" : { - "revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e", - "version" : "2.3.1" + "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac", + "version" : "2.4.0" } }, { @@ -122,8 +122,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordBDHG/ResearchKit", "state" : { - "revision" : "66f2fca769dc103de5801bb491b1d8ceafcd281e", - "version" : "2.2.23" + "revision" : "15f06cf7c1d2d22805b7b939823536bc78ad63a6", + "version" : "2.2.25" } }, { @@ -131,8 +131,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordBDHG/ResearchKitOnFHIR", "state" : { - "revision" : "ea4d9691591594177e7dfbc8c246324855d73eb5", - "version" : "1.0.1" + "revision" : "7f65fe3d94ed0bf44b681547944cc9657816edc5", + "version" : "1.1.0" } }, { @@ -140,8 +140,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordSpezi/Spezi", "state" : { - "revision" : "c8482d05efbd2ba93abefc309a86f7b77d10fca0", - "version" : "1.2.0" + "revision" : "0ced3efbc2af9513c07ac913ad762c773a00a6c8", + "version" : "1.2.1" } }, { @@ -203,8 +203,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordSpezi/SpeziQuestionnaire.git", "state" : { - "revision" : "fac0bb02f7027b4c09bd7afdad55eb7b47ec67f3", - "version" : "1.0.1" + "revision" : "f25580e95bfdad02383980dcb94406cf97b08ea8", + "version" : "1.0.2" } }, { diff --git a/NAMS/Patients/CurrentPatientLabel.swift b/NAMS/Patients/CurrentPatientLabel.swift index 7efcc60..4416996 100644 --- a/NAMS/Patients/CurrentPatientLabel.swift +++ b/NAMS/Patients/CurrentPatientLabel.swift @@ -31,6 +31,7 @@ struct CurrentPatientLabel: View { .accessibilityHidden(true) } .foregroundColor(.primary) + .accessibilityAddTraits(.isHeader) } @ViewBuilder private var selectPatientText: some View { diff --git a/NAMS/Patients/PatientInformation.swift b/NAMS/Patients/PatientInformation.swift index 89fd9d3..ea19f2d 100644 --- a/NAMS/Patients/PatientInformation.swift +++ b/NAMS/Patients/PatientInformation.swift @@ -42,6 +42,7 @@ struct PatientInformation: View { .listRowBackground(Color.clear) .accessibilityRepresentation { Text(verbatim: name) + .accessibilityAddTraits(.isHeader) } if let note = patient.note { diff --git a/NAMS/Patients/Tasks/ScreeningTask.swift b/NAMS/Patients/Tasks/ScreeningTask.swift index acb6ef7..b21c35c 100644 --- a/NAMS/Patients/Tasks/ScreeningTask.swift +++ b/NAMS/Patients/Tasks/ScreeningTask.swift @@ -21,6 +21,10 @@ struct ScreeningTask: PatientTask { let tileType: TileType = .questionnaire let expectedCompletionMinutes: String + var expectedCompletionMinutesSpoken: String { + expectedCompletionMinutes.replacingOccurrences(of: "-", with: " to ") + } + init( id: String, title: LocalizedStringResource, diff --git a/NAMS/Resources/Localizable.xcstrings b/NAMS/Resources/Localizable.xcstrings index f2887c4..5e07724 100644 --- a/NAMS/Resources/Localizable.xcstrings +++ b/NAMS/Resources/Localizable.xcstrings @@ -1090,6 +1090,9 @@ } } } + }, + "takes %@ min" : { + }, "The Modified Checklist for Autism in Toddlers, Revised with Follow-Up." : { "localizations" : { diff --git a/NAMS/Tiles/MeasurementTile.swift b/NAMS/Tiles/MeasurementTile.swift index db2e542..11d39f2 100644 --- a/NAMS/Tiles/MeasurementTile.swift +++ b/NAMS/Tiles/MeasurementTile.swift @@ -44,9 +44,16 @@ struct MeasurementTile: View { .foregroundColor(.secondary) .font(.subheadline) .multilineTextAlignment(.center) + .accessibilityLabel("takes \(task.expectedCompletionMinutes) min") } footer: { tileDescription + } action: { + presentingEEGRecording = true + } actionLabel: { + Text("Start \(task.tileType.localizedStringResource)") } + .tint(.pink) + .disabled(task.requiresConnectedDevice && !deviceConnected) } } @@ -68,17 +75,6 @@ struct MeasurementTile: View { .padding([.leading, .trailing]) .accessibilityLabel(Text(label)) } - - Button(action: { - presentingEEGRecording = true - }) { - Text("Start \(task.tileType.localizedStringResource)") - .frame(maxWidth: .infinity, minHeight: 30) - } - .buttonStyle(.borderedProminent) - .padding(.top, 8) - .tint(.pink) - .disabled(task.requiresConnectedDevice && !deviceConnected) } diff --git a/NAMS/Tiles/ScreeningTile.swift b/NAMS/Tiles/ScreeningTile.swift index d46550b..0570b78 100644 --- a/NAMS/Tiles/ScreeningTile.swift +++ b/NAMS/Tiles/ScreeningTile.swift @@ -39,17 +39,12 @@ struct ScreeningTile: View { } footer: { Text(task.description) .font(.callout) - - Button(action: { - presentingItem = task.questionnaire - }) { - Text("Start \(task.tileType.localizedStringResource)") - .frame(maxWidth: .infinity, minHeight: 30) - } - .buttonStyle(.borderedProminent) - .padding(.top, 8) - .tint(.mint) + } action: { + presentingItem = task.questionnaire + } actionLabel: { + Text("Start \(task.tileType.localizedStringResource)") } + .tint(.mint) } } diff --git a/NAMS/Tiles/ScreeningTileHeader.swift b/NAMS/Tiles/ScreeningTileHeader.swift index 1266ef2..d4c4f59 100644 --- a/NAMS/Tiles/ScreeningTileHeader.swift +++ b/NAMS/Tiles/ScreeningTileHeader.swift @@ -63,6 +63,7 @@ struct ScreeningTileHeader: View { } Text("\(task.expectedCompletionMinutes) min", comment: "Expected task completion in minutes.") + .accessibilityLabel("takes \(task.expectedCompletionMinutesSpoken) min") } .font(.subheadline) .foregroundColor(.secondary) diff --git a/NAMS/Tiles/SimpleTile.swift b/NAMS/Tiles/SimpleTile.swift index a4add9e..4c0483b 100644 --- a/NAMS/Tiles/SimpleTile.swift +++ b/NAMS/Tiles/SimpleTile.swift @@ -9,33 +9,84 @@ import SwiftUI -struct SimpleTile: View { +struct SimpleTile: View { + private struct Action { + let action: () -> Void + let label: ActionLabel + } + private let alignment: HorizontalAlignment private let header: Header private let footer: Footer + private let action: Action? var body: some View { VStack(alignment: alignment) { - header + tileLabel - if Footer.self != EmptyView.self { - Divider() - .padding(.bottom, 4) - - footer + if let action { + Button(action: action.action) { + action.label + .frame(maxWidth: .infinity, minHeight: 30) + } + .buttonStyle(.borderedProminent) + .padding(.top, 8) } } .containerShape(Rectangle()) + .accessibilityRepresentation { + if let action { + Button(action: action.action) { + tileLabel + } + } else { + tileLabel + .accessibilityElement(children: .combine) + } + } } - init( - alignment: HorizontalAlignment = .leading, + + @ViewBuilder var tileLabel: some View { + header + + if Footer.self != EmptyView.self || Action.self != EmptyView.self { + Divider() + .padding(.bottom, 4) + } + + footer + } + + private init( + alignment: HorizontalAlignment, @ViewBuilder header: () -> Header, - @ViewBuilder footer: () -> Footer = { EmptyView() } + @ViewBuilder footer: () -> Footer, + action: Action? ) { self.alignment = alignment self.header = header() self.footer = footer() + self.action = action + } + + + init( + alignment: HorizontalAlignment = .leading, + @ViewBuilder header: () -> Header, + @ViewBuilder footer: () -> Footer = { EmptyView() }, + action: @escaping () -> Void, + @ViewBuilder actionLabel: () -> ActionLabel + ) { + self.init(alignment: alignment, header: header, footer: footer, action: Action(action: action, label: actionLabel())) + } + + init( + alignment: HorizontalAlignment = .leading, + @ViewBuilder header: () -> Header, + @ViewBuilder footer: () -> Footer = { EmptyView() } + ) where ActionLabel == EmptyView { + self.init(alignment: alignment, header: header, footer: footer, action: nil) } } From d1cb2b0543754b9d8d074f8f11328a90a5a34d53 Mon Sep 17 00:00:00 2001 From: Andreas Bauer Date: Fri, 23 Feb 2024 23:40:00 -0800 Subject: [PATCH 2/3] Make it easier to test --- NAMS/Tiles/SimpleTile.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NAMS/Tiles/SimpleTile.swift b/NAMS/Tiles/SimpleTile.swift index 4c0483b..a971f65 100644 --- a/NAMS/Tiles/SimpleTile.swift +++ b/NAMS/Tiles/SimpleTile.swift @@ -34,6 +34,7 @@ struct SimpleTile: View { } } .containerShape(Rectangle()) + #if !TEST // it's easier to UI test for us without the accessibility representation .accessibilityRepresentation { if let action { Button(action: action.action) { @@ -44,6 +45,7 @@ struct SimpleTile: View { .accessibilityElement(children: .combine) } } + #endif } From cd78e401b92e600fe172fbe435f3de4e969f620a Mon Sep 17 00:00:00 2001 From: Andreas Bauer Date: Fri, 23 Feb 2024 23:41:11 -0800 Subject: [PATCH 3/3] Fix ui tests --- NAMSUITests/QuestionnaireTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NAMSUITests/QuestionnaireTests.swift b/NAMSUITests/QuestionnaireTests.swift index 4465f70..16f56aa 100644 --- a/NAMSUITests/QuestionnaireTests.swift +++ b/NAMSUITests/QuestionnaireTests.swift @@ -30,7 +30,7 @@ class QuestionnaireTests: XCTestCase { XCTAssertTrue(app.staticTexts["SCREENING"].waitForExistence(timeout: 2.0)) XCTAssertTrue(app.staticTexts["M-CHAT R/F"].waitForExistence(timeout: 0.5)) - XCTAssertTrue(app.staticTexts["Questionnaire, 5-10 min"].waitForExistence(timeout: 0.5)) + XCTAssertTrue(app.staticTexts["Questionnaire, takes 5 to 10 min"].waitForExistence(timeout: 0.5)) XCTAssertTrue(app.buttons["Start Questionnaire"].waitForExistence(timeout: 0.5)) app.buttons["Start Questionnaire"].tap()