Skip to content

Commit 47327bb

Browse files
authored
feat: improve voiceover posts for countdown / instructions (#15)
1 parent e1785d5 commit 47327bb

9 files changed

+76
-15
lines changed

Sources/FaceLiveness/Utilities/LocalizedStringKey+Liveness.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ extension LocalizedStringKey {
6868
"amplify_ui_liveness_get_ready_begin_check"
6969
)
7070

71+
/// en = "Illustration demonstrating good fit of face in oval."
72+
static let get_ready_illustration_good_fit_a11y = LocalizedStringKey(
73+
"amplify_ui_liveness_get_ready_illustration_good_fit_a11y"
74+
)
75+
76+
/// en = "Illustration demonstrating face too far from screen."
77+
static let get_ready_illustration_too_far_a11y = LocalizedStringKey(
78+
"amplify_ui_liveness_get_ready_illustration_too_far_a11y"
79+
)
80+
7181
/// en = "REC"
7282
static let challenge_recording_indicator_label = LocalizedStringKey(
7383
"amplify_ui_liveness_challenge_recording_indicator_label"
@@ -85,7 +95,7 @@ extension LocalizedStringKey {
8595

8696
/// en = "Move back"
8797
static let challenge_instruction_move_face_back = LocalizedStringKey(
88-
"amplify_ui_liveness_challenge_instruction_move_face_bqck"
98+
"amplify_ui_liveness_challenge_instruction_move_face_back"
8999
)
90100

91101
/// en = "Move closer"

Sources/FaceLiveness/Views/Countdown/CountdownInstructionContainerView.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ struct CountdownInstructionContainerView: View {
3535
text: .challenge_verifying,
3636
backgroundColor: .livenessBackground
3737
)
38+
.onAppear {
39+
UIAccessibility.post(
40+
notification: .announcement,
41+
argument: NSLocalizedString(
42+
"amplify_ui_liveness_challenge_verifying",
43+
bundle: .module,
44+
comment: ""
45+
)
46+
)
47+
}
3848
default:
3949
EmptyView()
4050
}

Sources/FaceLiveness/Views/Countdown/CountdownView+ViewModel.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,16 @@ extension CountdownView {
4242

4343
deinit { timerCancellable?.cancel() }
4444

45-
func timerInvoked() {
45+
private func setAccessibilityValue() {
46+
guard remaining >= 1 else { return }
4647
if remaining != initialDuration
4748
&& Int(floor(remaining)) != Int(floor(remaining - tickRate)) {
4849
timerAccessibilityValue = String(Int(remaining))
4950
}
51+
}
52+
53+
func timerInvoked() {
54+
setAccessibilityValue()
5055
remaining -= tickRate
5156
percentage -= rate
5257
if remaining <= 0 {

Sources/FaceLiveness/Views/Countdown/CountdownView.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ struct CountdownView: View {
3838
.animation(.linear, value: viewModel.percentage)
3939

4040
Text(viewModel.formatted(remaining: viewModel.remaining))
41-
.accessibilityValue(viewModel.formatted(remaining: viewModel.remaining))
41+
.accessibilityHidden(true)
4242
.font(.system(size: 24, weight: .semibold))
4343
}
4444
.onReceive(viewModel.timer) { _ in
4545
viewModel.timerInvoked()
4646
}
47+
.onReceive(viewModel.$timerAccessibilityValue) { value in
48+
UIAccessibility.post(notification: .announcement, argument: value)
49+
}
4750
}
4851
}
4952

Sources/FaceLiveness/Views/GetReadyPage/GetReadyPageView.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct GetReadyPageView: View {
2828
VStack(alignment: .leading) {
2929
Text(.get_ready_page_title, bundle: .module)
3030
.font(.system(size: 34, weight: .semibold))
31+
.accessibilityAddTraits(.isHeader)
3132
.padding(.bottom, 8)
3233

3334
Text(.get_ready_page_description, bundle: .module)
@@ -38,13 +39,15 @@ struct GetReadyPageView: View {
3839
bodyText: .get_ready_photosensitivity_description,
3940
popoverContent: { photosensitivityWarningPopoverContent }
4041
)
41-
.padding(.bottom, 8)
42+
.accessibilityElement(children: .combine)
43+
.padding(.bottom, 8)
4244

4345
Text(.get_ready_steps_title, bundle: .module)
4446
.fontWeight(.semibold)
4547
.padding(.bottom, 16)
4648

4749
OvalIllustrationExamples()
50+
.accessibilityHidden(true)
4851
.padding(.bottom)
4952

5053
steps()
@@ -118,8 +121,13 @@ struct GetReadyPageView: View {
118121
spacing: 16
119122
) {
120123
step(number: 1, text: .get_ready_fit_face)
124+
.accessibilityElement(children: .combine)
125+
121126
step(number: 2, text: .get_ready_face_not_covered)
127+
.accessibilityElement(children: .combine)
128+
122129
step(number: 3, text: .get_ready_lighting)
130+
.accessibilityElement(children: .combine)
123131
}
124132
}
125133
}

Sources/FaceLiveness/Views/GetReadyPage/OvalIllustrationExamples.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ struct OvalIllustrationExamples: View {
1717
secondaryColor: .hex("#D6F5DB"),
1818
illustration: { Image("illustration_face_good_fit", bundle: .module) }
1919
)
20+
.accessibilityElement(children: .ignore)
21+
.accessibilityLabel(Text(.get_ready_illustration_good_fit_a11y, bundle: .module))
2022

2123
OvalIllustrationView(
2224
icon: .xmark(backgroundColor: .hex("#660000")),
@@ -25,6 +27,8 @@ struct OvalIllustrationExamples: View {
2527
secondaryColor: .hex("#F5BCBC"),
2628
illustration: { Image("illustration_face_too_far", bundle: .module) }
2729
)
30+
.accessibilityElement(children: .ignore)
31+
.accessibilityLabel(Text(.get_ready_illustration_too_far_a11y, bundle: .module))
2832

2933
Spacer()
3034
}

Sources/FaceLiveness/Views/Instruction/InstructionContainerView.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
import SwiftUI
9+
import Combine
910

1011
struct InstructionContainerView: View {
1112
@ObservedObject var viewModel: FaceLivenessDetectionViewModel
@@ -19,6 +20,16 @@ struct InstructionContainerView: View {
1920
textColor: .livenessPrimaryLabel,
2021
font: .title
2122
)
23+
.onAppear {
24+
UIAccessibility.post(
25+
notification: .announcement,
26+
argument: NSLocalizedString(
27+
"amplify_ui_liveness_challenge_instruction_hold_still",
28+
bundle: .module,
29+
comment: ""
30+
)
31+
)
32+
}
2233

2334
case .awaitingFaceInOvalMatch(.faceTooClose, _):
2435
InstructionView(
@@ -27,6 +38,16 @@ struct InstructionContainerView: View {
2738
textColor: .livenessErrorLabel,
2839
font: .title
2940
)
41+
.onAppear {
42+
UIAccessibility.post(
43+
notification: .announcement,
44+
argument: NSLocalizedString(
45+
"amplify_ui_liveness_challenge_instruction_move_face_back",
46+
bundle: .module,
47+
comment: ""
48+
)
49+
)
50+
}
3051

3152
case .awaitingFaceInOvalMatch(let reason, let percentage):
3253
InstructionView(
@@ -51,6 +72,16 @@ struct InstructionContainerView: View {
5172
textColor: .livenessPrimaryLabel,
5273
font: .title
5374
)
75+
.onAppear {
76+
UIAccessibility.post(
77+
notification: .announcement,
78+
argument: NSLocalizedString(
79+
"amplify_ui_liveness_challenge_instruction_move_face_closer",
80+
bundle: .module,
81+
comment: ""
82+
)
83+
)
84+
}
5485

5586
ProgressBarView(
5687
emptyColor: .white,

Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ public struct FaceLivenessDetectorView: View {
178178
requestCameraPermission()
179179
case .authorized:
180180
displayState = .displayingLiveness
181-
UIScreen.main.brightness = 1.0
182181
case .restricted, .denied:
183182
alertCameraAccessNeeded()
184183
@unknown default:

Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel+FaceDetectionResultHandler.swift

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,10 @@ extension FaceLivenessDetectionViewModel: FaceDetectionResultHandler {
1616
func process(newResult: FaceDetectionResult) {
1717
switch newResult {
1818
case .noFace:
19-
switch livenessState.state {
20-
case .pendingFacePreparedConfirmation:
19+
if case .pendingFacePreparedConfirmation = livenessState.state {
2120
DispatchQueue.main.async {
2221
self.livenessState.faceNotPrepared(reason: .noFace)
2322
}
24-
return
25-
case .countingDown:
26-
DispatchQueue.main.async {
27-
self.livenessState.unrecoverableStateEncountered(
28-
.invalidFaceMovementDuringCountdown
29-
)
30-
}
31-
default: return
3223
}
3324
case .multipleFaces:
3425
if case .pendingFacePreparedConfirmation = livenessState.state {

0 commit comments

Comments
 (0)