Skip to content

Commit ac77da9

Browse files
authored
Merge pull request #270 from apptentive/branch_5.2.11
Release 5.2.11
2 parents e2ad5c7 + ec80ada commit ac77da9

11 files changed

+183
-58
lines changed

Apptentive/Apptentive.xcodeproj/project.pbxproj

+4-4
Original file line numberDiff line numberDiff line change
@@ -2405,7 +2405,7 @@
24052405
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
24062406
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
24072407
COPY_PHASE_STRIP = NO;
2408-
CURRENT_PROJECT_VERSION = 38;
2408+
CURRENT_PROJECT_VERSION = 39;
24092409
DEBUG_INFORMATION_FORMAT = dwarf;
24102410
ENABLE_STRICT_OBJC_MSGSEND = YES;
24112411
ENABLE_TESTABILITY = YES;
@@ -2463,7 +2463,7 @@
24632463
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
24642464
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
24652465
COPY_PHASE_STRIP = NO;
2466-
CURRENT_PROJECT_VERSION = 38;
2466+
CURRENT_PROJECT_VERSION = 39;
24672467
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
24682468
ENABLE_NS_ASSERTIONS = NO;
24692469
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -2495,7 +2495,7 @@
24952495
DEFINES_MODULE = YES;
24962496
DEVELOPMENT_TEAM = 86WML2UN43;
24972497
DYLIB_COMPATIBILITY_VERSION = 1;
2498-
DYLIB_CURRENT_VERSION = 38;
2498+
DYLIB_CURRENT_VERSION = 39;
24992499
DYLIB_INSTALL_NAME_BASE = "@rpath";
25002500
GCC_PREFIX_HEADER = "Apptentive/Misc/ApptentiveConnect-Prefix.pch";
25012501
GCC_PREPROCESSOR_DEFINITIONS = "APPTENTIVE_DEBUG=1";
@@ -2515,7 +2515,7 @@
25152515
DEFINES_MODULE = YES;
25162516
DEVELOPMENT_TEAM = 86WML2UN43;
25172517
DYLIB_COMPATIBILITY_VERSION = 1;
2518-
DYLIB_CURRENT_VERSION = 38;
2518+
DYLIB_CURRENT_VERSION = 39;
25192519
DYLIB_INSTALL_NAME_BASE = "@rpath";
25202520
GCC_PREFIX_HEADER = "Apptentive/Misc/ApptentiveConnect-Prefix.pch";
25212521
INFOPLIST_FILE = Apptentive/Info.plist;

Apptentive/Apptentive/Apptentive.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ FOUNDATION_EXPORT double ApptentiveVersionNumber;
2020
FOUNDATION_EXPORT const unsigned char ApptentiveVersionString[];
2121

2222
/** The version number of the Apptentive SDK. */
23-
#define kApptentiveVersionString @"5.2.10"
23+
#define kApptentiveVersionString @"5.2.11"
2424

2525
/** The version number of the Apptentive API platform. */
2626
#define kApptentiveAPIVersionString @"9"

Apptentive/Apptentive/Info.plist

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>FMWK</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>5.2.10</string>
18+
<string>5.2.11</string>
1919
<key>CFBundleVersion</key>
2020
<string>$(CURRENT_PROJECT_VERSION)</string>
2121
<key>NSPrincipalClass</key>

Apptentive/Apptentive/Surveys/View Controllers/ApptentiveSurveyViewController.m

+37-22
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ @interface ApptentiveSurveyViewController ()
6161
@property (assign, nonatomic) CGFloat toolbarInset;
6262
@property (assign, nonatomic) BOOL keyboardVisible;
6363

64+
@property (assign, nonatomic) BOOL shouldPostAccessibiltyNotificationOnScrollViewDidEndScrollingAnimation;
65+
6466
@end
6567

6668

@@ -177,15 +179,28 @@ - (IBAction)submit:(id)sender {
177179
HUD.imageView.image = [ApptentiveUtilities imageNamed:@"at_thanks"];
178180
}
179181
} else {
180-
NSIndexPath *firstInvalidQuestionIndex = self.viewModel.firstInvalidAnswerIndexPath;
181-
ApptentiveAssertNotNil(firstInvalidQuestionIndex, @"Expected non-nil index");
182-
if (firstInvalidQuestionIndex) {
183-
[self.collectionView scrollToItemAtIndexPath:firstInvalidQuestionIndex atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
184-
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [self.viewModel errorMessageAtIndex:firstInvalidQuestionIndex.section]);
182+
NSIndexPath *firstInvalidQuestionIndexPath = self.viewModel.firstInvalidAnswerIndexPath;
183+
ApptentiveAssertNotNil(firstInvalidQuestionIndexPath, @"Expected non-nil index");
184+
if (firstInvalidQuestionIndexPath) {
185+
// Defer moving VoiceOver focus to first invalid question until after scrolling completes
186+
self.shouldPostAccessibiltyNotificationOnScrollViewDidEndScrollingAnimation = YES;
187+
188+
[self.collectionView scrollToItemAtIndexPath:firstInvalidQuestionIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
185189
}
186190
}
187191
}
188192

193+
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
194+
if (self.shouldPostAccessibiltyNotificationOnScrollViewDidEndScrollingAnimation) {
195+
NSIndexPath *firstInvalidQuestionIndexPath = self.viewModel.firstInvalidAnswerIndexPath;
196+
197+
UIView *firstInvalidQuestionView = [self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:firstInvalidQuestionIndexPath];
198+
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, firstInvalidQuestionView);
199+
200+
self.shouldPostAccessibiltyNotificationOnScrollViewDidEndScrollingAnimation = NO;
201+
}
202+
}
203+
189204
- (IBAction)close:(id)sender {
190205
UIViewController *presentingViewController = self.presentingViewController;
191206
[self dismissViewControllerAnimated:YES
@@ -238,6 +253,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell
238253
cell.textView.text = [self.viewModel textOfAnswerAtIndexPath:indexPath];
239254
cell.placeholderLabel.attributedText = [self.viewModel placeholderTextOfAnswerAtIndexPath:indexPath];
240255
cell.placeholderLabel.hidden = cell.textView.text.length > 0;
256+
cell.placeholderLabel.isAccessibilityElement = NO;
241257
cell.textView.delegate = self;
242258
cell.textView.tag = [self.viewModel textFieldTagForIndexPath:indexPath];
243259
cell.textView.accessibilityLabel = cell.placeholderLabel.text;
@@ -254,7 +270,6 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell
254270
cell.textField.delegate = self;
255271
cell.textField.tag = [self.viewModel textFieldTagForIndexPath:indexPath];
256272
cell.textField.font = [self.viewModel.styleSheet fontForStyle:ApptentiveTextStyleTextInput];
257-
cell.textField.accessibilityLabel = cell.textField.placeholder;
258273
cell.textField.textColor = [self.viewModel.styleSheet colorForStyle:ApptentiveTextStyleTextInput];
259274

260275
return cell;
@@ -263,30 +278,33 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell
263278
case ATSurveyQuestionTypeSingleSelect:
264279
case ATSurveyQuestionTypeMultipleSelect: {
265280
NSString *reuseIdentifier, *buttonImageName, *detailText;
266-
NSString *accessibilityHintDetails = nil;
281+
NSString *accessibilityLabel = nil;
282+
NSString *accessibilityHint = nil;
267283

268284
switch ([self.viewModel typeOfQuestionAtIndex:indexPath.section]) {
269285
case ATSurveyQuestionTypeRange:
270286
if (indexPath.item == 0) {
271287
reuseIdentifier = @"RangeMinimum";
272288
detailText = [self.viewModel minimumLabelForQuestionAtIndex:indexPath.section];
273-
accessibilityHintDetails = [self.viewModel minimumLabelForQuestionAtIndex:indexPath.section];
274289
} else if (indexPath.item == [self.viewModel numberOfAnswersForQuestionAtIndex:indexPath.section] - 1) {
275290
reuseIdentifier = @"RangeMaximum";
276291
detailText = [self.viewModel maximumLabelForQuestionAtIndex:indexPath.section];
277-
accessibilityHintDetails = [self.viewModel maximumLabelForQuestionAtIndex:indexPath.section];
278292
} else {
279293
reuseIdentifier = @"Range";
280294
}
281295
buttonImageName = @"at_circle";
296+
accessibilityLabel = [self.viewModel rangeOptionAccessibilityLabelForQuestionAtIndexPath:indexPath];
297+
accessibilityHint = [self.viewModel rangeOptionAccessibilityHintForQuestionAtIndexPath:indexPath];
282298
break;
283299
case ATSurveyQuestionTypeMultipleSelect:
284300
reuseIdentifier = @"Checkbox";
285301
buttonImageName = @"at_checkmark";
302+
accessibilityLabel = [self.viewModel textOfChoiceAtIndexPath:indexPath];
286303
break;
287304
default:
288305
reuseIdentifier = @"Radio";
289306
buttonImageName = @"at_circle";
307+
accessibilityLabel = [self.viewModel textOfChoiceAtIndexPath:indexPath];
290308
break;
291309
}
292310

@@ -306,17 +324,11 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell
306324
cell.detailTextLabel.text = detailText;
307325
cell.detailTextLabel.font = [self.viewModel.styleSheet fontForStyle:ApptentiveTextStyleSurveyInstructions];
308326
cell.detailTextLabel.textColor = [self.viewModel.styleSheet colorForStyle:ApptentiveTextStyleSurveyInstructions];
309-
310-
if (detailText) {
311-
cell.accessibilityHint = detailText;
312-
}
313-
314-
if (accessibilityHintDetails.length > 0) {
315-
cell.accessibilityLabel = [NSString stringWithFormat:@"%@, %@", accessibilityHintDetails, [self.viewModel textOfChoiceAtIndexPath:indexPath]];
316-
} else {
317-
cell.accessibilityLabel = [self.viewModel textOfChoiceAtIndexPath:indexPath];
318-
}
327+
328+
cell.accessibilityLabel = accessibilityLabel;
329+
cell.accessibilityHint = accessibilityHint;
319330
cell.accessibilityTraits |= UIAccessibilityTraitButton;
331+
320332
cell.button.image = buttonImage;
321333
cell.button.highlightedImage = highlightedButtonImage;
322334
[cell.button sizeToFit];
@@ -352,12 +364,15 @@ - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
352364
view.textLabel.text = [self.viewModel textOfQuestionAtIndex:indexPath.section];
353365
view.textLabel.font = [self.viewModel.styleSheet fontForStyle:UIFontTextStyleBody];
354366
view.textLabel.textColor = [self.viewModel.styleSheet colorForStyle:UIFontTextStyleBody];
355-
view.textLabel.accessibilityHint = [self.viewModel accessibilityHintForQuestionAtIndexPath:indexPath];
356367
view.instructionsTextLabel.attributedText = [self.viewModel instructionTextOfQuestionAtIndex:indexPath.section];
357368
view.instructionsTextLabel.font = [self.viewModel.styleSheet fontForStyle:ApptentiveTextStyleSurveyInstructions];
358369

359370
view.separatorView.backgroundColor = [self.viewModel.styleSheet colorForStyle:ApptentiveColorSeparator];
360371

372+
view.isAccessibilityElement = YES;
373+
view.accessibilityLabel = [self.viewModel accessibilityLabelForQuestionAtIndexPath:indexPath];
374+
view.accessibilityHint = [self.viewModel accessibilityHintForQuestionAtIndexPath:indexPath];
375+
361376
return view;
362377
} else {
363378
ApptentiveSurveyQuestionFooterView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"Footer" forIndexPath:indexPath];
@@ -611,7 +626,7 @@ - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRan
611626
return NO;
612627
}
613628

614-
if([UIApplication.sharedApplication canOpenURL:URL]) {
629+
if ([UIApplication.sharedApplication canOpenURL:URL]) {
615630
[ApptentiveURLOpener openURL:URL completionHandler: NULL];
616631
}
617632

@@ -652,7 +667,7 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio
652667
#pragma mark - View model delegate
653668

654669
- (void)viewModelValidationChanged:(ApptentiveSurveyViewModel *)viewModel isValid:(BOOL)valid {
655-
[self.collectionViewLayout invalidateLayout];
670+
[self.collectionView reloadData];
656671

657672
[self setToolbarHidden:valid];
658673

Apptentive/Apptentive/Surveys/View Controllers/ApptentiveSurveyViewModel.h

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ NS_ASSUME_NONNULL_BEGIN
4747
- (NSString *)textOfQuestionAtIndex:(NSInteger)index;
4848
- (nullable NSAttributedString *)instructionTextOfQuestionAtIndex:(NSInteger)index;
4949
- (NSAttributedString *)placeholderTextOfAnswerAtIndexPath:(NSIndexPath *)indexPath;
50+
- (nullable NSString *)rangeOptionAccessibilityLabelForQuestionAtIndexPath:(NSIndexPath *)indexPath;
51+
- (nullable NSString *)rangeOptionAccessibilityHintForQuestionAtIndexPath:(NSIndexPath *)indexPath;
52+
- (nullable NSString *)accessibilityLabelForQuestionAtIndexPath:(NSIndexPath *)indexPath;
5053
- (nullable NSString *)accessibilityHintForQuestionAtIndexPath:(NSIndexPath *)indexPath;
5154
- (ATSurveyQuestionType)typeOfQuestionAtIndex:(NSInteger)index;
5255
- (ApptentiveSurveyAnswerType)typeOfAnswerAtIndexPath:(NSIndexPath *)indexPath;

Apptentive/Apptentive/Surveys/View Controllers/ApptentiveSurveyViewModel.m

+73-25
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,59 @@ - (BOOL)answerIsSelectedAtIndexPath:(NSIndexPath *)indexPath {
161161
return [self.selectedIndexPaths containsObject:indexPath];
162162
}
163163

164-
- (nullable NSString *)accessibilityHintForQuestionAtIndexPath:(NSIndexPath *)indexPath {
164+
- (nullable NSString *)rangeOptionAccessibilityLabelForQuestionAtIndexPath:(NSIndexPath *)indexPath {
165+
NSString *result = [self textOfChoiceAtIndexPath:indexPath];
166+
167+
return result;
168+
}
169+
170+
- (nullable NSString *)rangeOptionAccessibilityHintForQuestionAtIndexPath:(NSIndexPath *)indexPath {
171+
NSInteger questionIndex = indexPath.section;
172+
173+
NSIndexPath *minValueIndexPath = [NSIndexPath indexPathForRow:0 inSection: questionIndex];
174+
NSString *minValueLabel = [self textOfChoiceAtIndexPath:minValueIndexPath];
175+
NSString *minLabel = [self minimumLabelForQuestionAtIndex:questionIndex];
176+
177+
NSInteger numberOfAnswers = [self numberOfAnswersForQuestionAtIndex:questionIndex];
178+
NSIndexPath *maxValueIndexPath = [NSIndexPath indexPathForRow:numberOfAnswers - 1 inSection: questionIndex];
179+
NSString *maxValueLabel = [self textOfChoiceAtIndexPath:maxValueIndexPath];
180+
NSString *maxLabel = [self maximumLabelForQuestionAtIndex:questionIndex];
181+
182+
NSString *result = [NSString stringWithFormat:@"where %@ is %@ and %@ is %@", minValueLabel, minLabel, maxValueLabel, maxLabel];
183+
184+
return result;
185+
}
186+
187+
- (nullable NSString *)accessibilityLabelForQuestionAtIndexPath:(NSIndexPath *)indexPath {
165188
ApptentiveSurveyQuestion *question = [self questionAtIndex:indexPath.section];
189+
190+
NSMutableArray *resultParts = [[NSMutableArray alloc] init];
191+
192+
if ([self.invalidQuestionIndexes containsIndex:indexPath.section] && question.errorMessage != nil) {
193+
[resultParts addObject:question.errorMessage];
194+
}
195+
196+
if (question.value) {
197+
[resultParts addObject:question.value];
198+
}
199+
166200
if (question.required) {
167-
return ApptentiveLocalizedString(@"required", @"Required answer hint");
201+
NSString *requiredHint = self.survey.requiredText ?: ApptentiveLocalizedString(@"required", @"Required answer hint");
202+
203+
if (requiredHint) {
204+
[resultParts addObject:requiredHint];
205+
}
168206
}
169-
170-
return nil;
207+
208+
NSString *result = [resultParts count] > 0 ? [resultParts componentsJoinedByString:@", "] : nil;
209+
210+
return result;
211+
}
212+
213+
- (nullable NSString *)accessibilityHintForQuestionAtIndexPath:(NSIndexPath *)indexPath {
214+
ApptentiveSurveyQuestion *question = [self questionAtIndex:indexPath.section];
215+
216+
return question.instructions;
171217
}
172218

173219
- (ATSurveyQuestionType)typeOfQuestionAtIndex:(NSInteger)index {
@@ -187,7 +233,9 @@ - (NSString *)maximumLabelForQuestionAtIndex:(NSInteger)index {
187233
}
188234

189235
- (nullable NSString *)errorMessageAtIndex:(NSInteger)index {
190-
return [self questionAtIndex:index].errorMessage;
236+
ApptentiveSurveyQuestion *question = [self questionAtIndex:index];
237+
238+
return question.errorMessage;
191239
}
192240

193241
- (BOOL)answerIsValidForQuestionAtIndex:(NSInteger)index {
@@ -207,35 +255,35 @@ - (NSInteger)textFieldTagForIndexPath:(NSIndexPath *)indexPath {
207255
}
208256

209257
-(BOOL)isNonEmptyText:(NSString *)text {
210-
NSString *trimmed = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
211-
BOOL isValid = [trimmed length] > 0;
212-
213-
return isValid;
258+
NSString *trimmed = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
259+
BOOL isValid = [trimmed length] > 0;
260+
261+
return isValid;
214262
}
215263

216264
- (nullable NSAttributedString *)termsAndConditionsAttributedText:(TermsAndConditions *)termsAndConditions {
217-
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
218-
219-
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
220-
paragraphStyle.alignment = NSTextAlignmentCenter;
221-
222-
NSDictionary *attributes = @{
223-
NSParagraphStyleAttributeName: paragraphStyle,
224-
NSFontAttributeName: [self.styleSheet fontForStyle:ApptentiveTextStyleSurveyInstructions],
225-
NSForegroundColorAttributeName: [self.styleSheet colorForStyle:ApptentiveTextStyleBody],
226-
};
227-
228-
NSString *bodyText = termsAndConditions.bodyText;
229-
BOOL hasBodyText = [self isNonEmptyText:bodyText];
230-
231-
if (hasBodyText) {
265+
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
266+
267+
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
268+
paragraphStyle.alignment = NSTextAlignmentCenter;
269+
270+
NSDictionary *attributes = @{
271+
NSParagraphStyleAttributeName: paragraphStyle,
272+
NSFontAttributeName: [self.styleSheet fontForStyle:ApptentiveTextStyleSurveyInstructions],
273+
NSForegroundColorAttributeName: [self.styleSheet colorForStyle:ApptentiveTextStyleBody],
274+
};
275+
276+
NSString *bodyText = termsAndConditions.bodyText;
277+
BOOL hasBodyText = [self isNonEmptyText:bodyText];
278+
279+
if (hasBodyText) {
232280
[result appendAttributedString:[[NSAttributedString alloc] initWithString:bodyText attributes:attributes]];
233281
}
234282

235283
NSURL *linkURL = termsAndConditions.linkURL;
236284
BOOL hasValidURL = linkURL && [linkURL scheme] && [linkURL host];
237285

238-
if(hasValidURL) {
286+
if (hasValidURL) {
239287
if (hasBodyText) {
240288
[result appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n" attributes:attributes]];
241289
}

0 commit comments

Comments
 (0)