diff --git a/ResearchKit/ActiveTasks/ORKAccelerometerRecorder.h b/ResearchKit/ActiveTasks/ORKAccelerometerRecorder.h index 2f9df1f4..72b4dabe 100644 --- a/ResearchKit/ActiveTasks/ORKAccelerometerRecorder.h +++ b/ResearchKit/ActiveTasks/ORKAccelerometerRecorder.h @@ -59,7 +59,7 @@ ORK_CLASS_AVAILABLE @return An initialized accelerometer recorder. */ -- (instancetype)initWithIdentifier:(NSString *)identifer +- (instancetype)initWithIdentifier:(NSString *)identifier frequency:(double)frequency step:(nullable ORKStep *)step outputDirectory:(nullable NSURL *)outputDirectory; diff --git a/ResearchKit/Common/ORKInstructionStep.h b/ResearchKit/Common/ORKInstructionStep.h index 44cd361c..a90789ab 100644 --- a/ResearchKit/Common/ORKInstructionStep.h +++ b/ResearchKit/Common/ORKInstructionStep.h @@ -82,6 +82,11 @@ ORK_CLASS_AVAILABLE */ @property (nonatomic, copy, nullable) UIImage *auxiliaryImage; +/** + Optional icon image to show above the title and text. + */ +@property (nonatomic, copy, nullable) UIImage *iconImage; + @end NS_ASSUME_NONNULL_END diff --git a/ResearchKit/Common/ORKInstructionStep.m b/ResearchKit/Common/ORKInstructionStep.m index eb8d6860..b920816b 100644 --- a/ResearchKit/Common/ORKInstructionStep.m +++ b/ResearchKit/Common/ORKInstructionStep.m @@ -58,6 +58,7 @@ ORK_DECODE_OBJ_CLASS(aDecoder, footnote, NSString); ORK_DECODE_IMAGE(aDecoder, image); ORK_DECODE_IMAGE(aDecoder, auxiliaryImage); + ORK_DECODE_IMAGE(aDecoder, iconImage); } return self; } @@ -68,6 +69,7 @@ ORK_ENCODE_OBJ(aCoder, footnote); ORK_ENCODE_IMAGE(aCoder, image); ORK_ENCODE_IMAGE(aCoder, auxiliaryImage); + ORK_ENCODE_IMAGE(aCoder, iconImage); } + (BOOL)supportsSecureCoding { @@ -80,6 +82,7 @@ step.footnote = self.footnote; step.image = self.image; step.auxiliaryImage = self.auxiliaryImage; + step.iconImage = self.iconImage; return step; } @@ -91,7 +94,8 @@ ORKEqualObjects(self.detailText, castObject.detailText) && ORKEqualObjects(self.footnote, castObject.footnote) && ORKEqualObjects(self.image, castObject.image) && - ORKEqualObjects(self.auxiliaryImage, castObject.auxiliaryImage); + ORKEqualObjects(self.auxiliaryImage, castObject.auxiliaryImage) && + ORKEqualObjects(self.iconImage, castObject.iconImage); } - (NSUInteger)hash { diff --git a/ResearchKit/Common/ORKInstructionStepView.m b/ResearchKit/Common/ORKInstructionStepView.m index 51095469..cd496440 100644 --- a/ResearchKit/Common/ORKInstructionStepView.m +++ b/ResearchKit/Common/ORKInstructionStepView.m @@ -141,6 +141,7 @@ _instructionImageView.isAccessibilityElement = NO; } + self.headerView.iconImageView.image = _instructionStep.iconImage; self.headerView.captionLabel.text = _instructionStep.title; diff --git a/ResearchKit/Common/ORKResultPredicate.h b/ResearchKit/Common/ORKResultPredicate.h index bc114239..0bfd903a 100644 --- a/ResearchKit/Common/ORKResultPredicate.h +++ b/ResearchKit/Common/ORKResultPredicate.h @@ -189,7 +189,7 @@ ORK_CLASS_AVAILABLE object can contain one or more `ORKQuestionResult` objects that have the identifiers of the `ORKFormItem` objects that generated them. - For matching a single-question step result, you only need to set the `resultIdentifer` when + For matching a single-question step result, you only need to set the `resultIdentifier` when building the result selector object. The `stepIdentifier` will take the same value. For matching a form item result, you need to build a result selector with a `stepIdentifier` (the diff --git a/ResearchKit/Common/ORKStepHeaderView.m b/ResearchKit/Common/ORKStepHeaderView.m index 37470b90..59e26bfe 100644 --- a/ResearchKit/Common/ORKStepHeaderView.m +++ b/ResearchKit/Common/ORKStepHeaderView.m @@ -165,12 +165,14 @@ _learnMoreButton.titleLabel.preferredMaxLayoutWidth = insetBounds.size.width - sideMargin * 2; } +const CGFloat IconHeight = 60; + - (void)updateConstraintConstantsForWindow:(UIWindow *)window { static const CGFloat AssumedNavBarHeight = 44; static const CGFloat AssumedStatusBarHeight = 20; const CGFloat IconBottomToCaptionBaseline = ORKGetMetricForWindow(ORKScreenMetricIconImageViewToCaptionBaseline, window);; - const CGFloat IconHeight = 60; + const CGFloat TopToIconTop = ORKGetMetricForWindow(ORKScreenMetricTopToIconImageViewTop, window); BOOL hasIconView = _iconImageView.image != nil; @@ -183,7 +185,7 @@ const CGFloat LearnMoreBaselineToStepViewTop = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTop, window); const CGFloat InstructionBaselineToStepViewTopWithNoLearnMore = ORKGetMetricForWindow(ORKScreenMetricLearnMoreBaselineToStepViewTopWithNoLearnMore, window); - BOOL hasCaptionLabel = _captionLabel.text.length > 0; + BOOL hasCaptionLabel = _captionLabel.text.length > 0 || hasIconView; BOOL hasInstructionLabel = _instructionLabel.text.length > 0; BOOL hasLearnMoreButton = (_learnMoreButton.alpha > 0); @@ -285,6 +287,14 @@ attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; + + [constraints addObject:[NSLayoutConstraint constraintWithItem:_iconImageView + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationLessThanOrEqual + toItem:nil + attribute:nil + multiplier:1.0 + constant:IconHeight]]; } { diff --git a/ResearchKit/Common/ORKStepViewController.m b/ResearchKit/Common/ORKStepViewController.m index 5ffa31a7..48c8f852 100644 --- a/ResearchKit/Common/ORKStepViewController.m +++ b/ResearchKit/Common/ORKStepViewController.m @@ -271,7 +271,7 @@ - (ORKStepResult *)result { ORKStepResult *stepResult = [[ORKStepResult alloc] initWithStepIdentifier:self.step.identifier results:@[]]; - stepResult.startDate = self.presentedDate; + stepResult.startDate = self.presentedDate ? : [NSDate date]; stepResult.endDate = self.dismissedDate ? : [NSDate date]; return stepResult; diff --git a/ResearchKit/Common/ORKTaskViewController.h b/ResearchKit/Common/ORKTaskViewController.h index 47a2b90b..0332d7ff 100644 --- a/ResearchKit/Common/ORKTaskViewController.h +++ b/ResearchKit/Common/ORKTaskViewController.h @@ -234,7 +234,7 @@ task view controller and pass that data to `initWithTask:restorationData:` when after saving the result of the step to the task view controller and before navigating to the next/previous step. @param taskViewController The calling `ORKTaskViewController` instance. - @param step The `ORKStepViewController` that has just finished. + @param stepViewController The `ORKStepViewController` that has just finished. @param direction The `ORKStepViewControllerNavigationDirection` of navigation. */ - (void)taskViewController:(ORKTaskViewController *)taskViewController stepViewControllerWillDisappear:(ORKStepViewController *)stepViewController navigationDirection:(ORKStepViewControllerNavigationDirection)direction; diff --git a/Testing/ORKTest/ORKTest/MainViewController.m b/Testing/ORKTest/ORKTest/MainViewController.m index 368416e9..b2c9e7ad 100644 --- a/Testing/ORKTest/ORKTest/MainViewController.m +++ b/Testing/ORKTest/ORKTest/MainViewController.m @@ -65,6 +65,7 @@ DefineStringKey(ColorScalesTaskIdentifier); DefineStringKey(MiniFormTaskIdentifier); DefineStringKey(OptionalFormTaskIdentifier); DefineStringKey(SelectionSurveyTaskIdentifier); +DefineStringKey(PredicateTestsTaskIdentifier); DefineStringKey(ActiveStepTaskIdentifier); DefineStringKey(AudioTaskIdentifier); @@ -72,6 +73,7 @@ DefineStringKey(AuxillaryImageTaskIdentifier); DefineStringKey(FitnessTaskIdentifier); DefineStringKey(FootnoteTaskIdentifier); DefineStringKey(GaitTaskIdentifier); +DefineStringKey(IconImageTaskIdentifier); DefineStringKey(HolePegTestTaskIdentifier); DefineStringKey(MemoryTaskIdentifier); DefineStringKey(PSATTaskIdentifier); @@ -386,6 +388,7 @@ static const CGFloat HeaderSideLayoutMargin = 16.0; @"Interruptible Task", @"Navigable Ordered Task", @"Navigable Loop Task", + @"Predicate Tests", @"Test Charts", @"Test Charts Performance", @"Toggle Tint Color", @@ -397,6 +400,7 @@ static const CGFloat HeaderSideLayoutMargin = 16.0; @"Table Step", @"Signature Step", @"Auxillary Image", + @"Icon Image", @"Footnote", ], ]; @@ -504,6 +508,8 @@ static const CGFloat HeaderSideLayoutMargin = 16.0; return [self makeMiniFormTask]; } else if ([identifier isEqualToString:OptionalFormTaskIdentifier]) { return [self makeOptionalFormTask]; + } else if ([identifier isEqualToString:PredicateTestsTaskIdentifier]) { + return [self makePredicateTestsTask]; } else if ([identifier isEqualToString:FitnessTaskIdentifier]) { return [ORKOrderedTask fitnessCheckTaskWithIdentifier:FitnessTaskIdentifier intendedUseDescription:nil @@ -642,6 +648,8 @@ static const CGFloat HeaderSideLayoutMargin = 16.0; options:ORKPredefinedTaskOptionNone]; } else if ([identifier isEqualToString:AuxillaryImageTaskIdentifier]) { return [self makeAuxillaryImageTask]; + } else if ([identifier isEqualToString:IconImageTaskIdentifier]) { + return [self makeIconImageTask]; } else if ([identifier isEqualToString:FootnoteTaskIdentifier]) { return [self makeFootnoteTask]; } @@ -2304,6 +2312,349 @@ static const CGFloat HeaderSideLayoutMargin = 16.0; [self beginTaskWithIdentifier:OptionalFormTaskIdentifier]; } +#pragma mark - Predicate Tests +/* + This is intended to test the predicate functions and APIs + */ +- (id)makePredicateTestsTask { + NSMutableArray *steps = [NSMutableArray new]; + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"intro_step"]; + step.title = @"Predicate Tests"; + [steps addObject:step]; + } + + // Test Expected Boolean value + { + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_01" + title:@"Pass the Boolean question?" + answer:[ORKAnswerFormat booleanAnswerFormat]]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_01_fail"]; + step.title = @"You failed the Boolean question."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_01_pass"]; + step.title = @"You passed the Boolean question."; + [steps addObject:step]; + } + + // Test expected Single Choice + { + ORKAnswerFormat *answer = [ORKAnswerFormat choiceAnswerFormatWithStyle:ORKChoiceAnswerStyleSingleChoice textChoices:[NSArray arrayWithObjects:@"Choose Yes", @"Choose No", nil]]; + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_02" + title:@"Pass the single choice question?" + answer:answer]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_02_fail"]; + step.title = @"You failed the single choice question."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_02_pass"]; + step.title = @"You passed the single choice question."; + [steps addObject:step]; + } + + // Test expected multiple choices + { + ORKAnswerFormat *answer = [ORKAnswerFormat choiceAnswerFormatWithStyle:ORKChoiceAnswerStyleMultipleChoice textChoices:[NSArray arrayWithObjects:@"Cat", @"Dog", @"Rock", nil]]; + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_03" + title:@"Select all the animals" + answer:answer]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_03_fail"]; + step.title = @"You failed the multiple choice animals question."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_03_pass"]; + step.title = @"You passed the multiple choice animals question."; + [steps addObject:step]; + } + + // Test expected multiple choices + { + ORKAnswerFormat *answer = [ORKAnswerFormat choiceAnswerFormatWithStyle:ORKChoiceAnswerStyleSingleChoice textChoices:[NSArray arrayWithObjects:@"Cat", @"Catheter", @"Cathedral", @"Dog", nil]]; + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_04" + title:@"Choose any word containing the word 'Cat'" + answer:answer]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_04_fail"]; + step.title = @"You failed the 'Cat' pattern match question."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_04_pass"]; + step.title = @"You passed the 'Cat' pattern match question."; + [steps addObject:step]; + } + + // Test expected text + { + ORKAnswerFormat *answer = [ORKAnswerFormat textAnswerFormat]; + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_05" + title:@"Write the word 'Dog'" + answer:answer]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_05_fail"]; + step.title = @"You didn't write 'Dog'."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_05_pass"]; + step.title = @"You wrote 'Dog'."; + [steps addObject:step]; + } + + // Test matching text + { + ORKAnswerFormat *answer = [ORKAnswerFormat textAnswerFormat]; + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_06" + title:@"Write a word matching '*og'" + answer:answer]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_06_fail"]; + step.title = @"You didn't write a word matching '*og'."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_06_pass"]; + step.title = @"You wrote a word matching '*og'."; + [steps addObject:step]; + } + + // Numeric test - any number over 10 + { + ORKAnswerFormat *answer = [ORKAnswerFormat integerAnswerFormatWithUnit:nil]; + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_07" + title:@"Enter a number over 10" + answer:answer]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_07_fail"]; + step.title = @"Your number was less then 10."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_07_pass"]; + step.title = @"Your number was over 10."; + [steps addObject:step]; + } + + { + /* + Vertical continuous scale with three decimal places and a default. + */ + ORKContinuousScaleAnswerFormat *scaleAnswerFormat = [ORKAnswerFormat continuousScaleAnswerFormatWithMaximumValue:10 + minimumValue:1 + defaultValue:8.725 + maximumFractionDigits:3 + vertical:YES + maximumValueDescription:nil + minimumValueDescription:nil]; + + ORKQuestionStep *step = [ORKQuestionStep questionStepWithIdentifier:@"question_08" + title:@"Choose a value under 5" + answer:scaleAnswerFormat]; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_08_fail"]; + step.title = @"Your number was more than 5."; + [steps addObject:step]; + } + + { + ORKInstructionStep *step = [[ORKInstructionStep alloc] initWithIdentifier:@"question_08_pass"]; + step.title = @"Your number was less than 5."; + [steps addObject:step]; + } + + + { + ORKCompletionStep *step = [[ORKCompletionStep alloc] initWithIdentifier:@"all_passed"]; + step.title = @"All validation tests now completed."; + [steps addObject:step]; + } + + ORKNavigableOrderedTask *task = [[ORKNavigableOrderedTask alloc] initWithIdentifier:EligibilitySurveyTaskIdentifier steps:steps]; + + // Build navigation rules. + { + // If we answer 'Yes' to Question 1, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_01"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForBooleanQuestionResultWithResultSelector:resultSelector expectedAnswer:YES]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_01_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_01"]; + } + + { + // If we arrived at question_01_fail then fall through to question 2 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"question_02"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_01_fail"]; + } + + { + // If we answer 'Yes' to Question 2, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_02"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector expectedAnswerValue:@"Choose Yes"]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_02_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_02"]; + } + + { + // If we arrived at question_02_fail then fall through to question 3 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"question_03"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_02_fail"]; + } + + { + // If we answer 'Yes' to Question 3, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_03"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector expectedAnswerValues:[NSArray arrayWithObjects: @"Cat",@"Dog", nil]]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_03_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_03"]; + } + + { + // If we arrived at question_03_fail then fall through to question 4 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"question_04"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_03_fail"]; + } + + { + // If we answer 'Yes' to Question 4, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_04"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector matchingPattern:@"Cat.*"]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_04_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_04"]; + } + + { + // If we arrived at question_04_fail then fall through to question 5 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"question_05"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_04_fail"]; + } + + { + // If we answer 'Dog' to Question 5, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_05"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector expectedString:@"Dog"]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_05_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_05"]; + } + + { + // If we arrived at question_05_fail then fall through to question 6 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"question_06"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_05_fail"]; + } + + + { + // If we answer '*og' to Question 6, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_06"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector matchingPattern:@".*og"]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_06_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_06"]; + } + + { + // If we arrived at question_06_fail then fall through to question 7 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"question_07"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_06_fail"]; + } + + { + // If we answer '*og' to Question 7, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_07"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector minimumExpectedAnswerValue:10]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_07_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_07"]; + } + + { + // If we arrived at question_05_fail then fall through to question 6 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"question_08"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_07_fail"]; + } + + { + // If we answer '*og' to Question 7, then proceed to the pass screen + ORKResultSelector *resultSelector = [ORKResultSelector selectorWithResultIdentifier:@"question_08"]; + NSPredicate *predicateQuestion = [ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector maximumExpectedAnswerValue:5]; + + ORKPredicateStepNavigationRule *predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[predicateQuestion] + destinationStepIdentifiers:@[@"question_08_pass"]]; + [task setNavigationRule:predicateRule forTriggerStepIdentifier:@"question_08"]; + } + + { + // If we arrived at question_05_fail then fall through to question 6 + ORKDirectStepNavigationRule *directRule = nil; + directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:@"all_passed"]; + [task setNavigationRule:directRule forTriggerStepIdentifier:@"question_08_fail"]; + } + + return task; +} + +- (void)predicateTestsButtonTapped:(id)sender { + [self beginTaskWithIdentifier:PredicateTestsTaskIdentifier]; +} + #pragma mark - Active tasks - (void)fitnessTaskButtonTapped:(id)sender { @@ -4166,7 +4517,35 @@ stepViewControllerWillAppear:(ORKStepViewController *)stepViewController { return [[ORKOrderedTask alloc] initWithIdentifier:SignatureStepTaskIdentifier steps:@[step]]; } -#pragma mark - Auxillary Image +#pragma mark - Icon Image + +- (IBAction)iconImageButtonTapped:(id)sender { + [self beginTaskWithIdentifier:IconImageTaskIdentifier]; +} + +- (ORKOrderedTask *)makeIconImageTask { + + ORKInstructionStep *step1 = [[ORKInstructionStep alloc] initWithIdentifier:@"step1"]; + step1.title = @"Title"; + step1.text = @"This is an example of a step with an icon image."; + + NSDictionary *infoPlist = [[NSBundle mainBundle] infoDictionary]; + NSString *icon = [[infoPlist valueForKeyPath:@"CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles"] lastObject]; + step1.iconImage = [UIImage imageNamed:icon]; + + ORKInstructionStep *step2 = [[ORKInstructionStep alloc] initWithIdentifier:@"step2"]; + step2.text = @"This is an example of a step with an icon image and no title."; + step2.iconImage = [UIImage imageNamed:icon]; + + ORKInstructionStep *step3 = [[ORKInstructionStep alloc] initWithIdentifier:@"step3"]; + step3.title = @"Title"; + step3.text = @"This is an example of a step with an icon image that is very big."; + step3.iconImage = [UIImage imageNamed:@"Poppies"]; + + return [[ORKOrderedTask alloc] initWithIdentifier:IconImageTaskIdentifier steps:@[step1, step2, step3]]; +} + +#pragma mark - Footnote - (IBAction)footnoteButtonTapped:(id)sender { [self beginTaskWithIdentifier:FootnoteTaskIdentifier]; diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/AppIcon.appiconset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/AppIcon.appiconset/Contents.json index 1a9a7a78..bd8bb911 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", @@ -34,6 +44,16 @@ "filename" : "icon_60@3x.png", "scale" : "3x" }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, { "idiom" : "ipad", "size" : "29x29", diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Poppies.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Poppies.imageset/Contents.json new file mode 100644 index 00000000..8ce48c36 --- /dev/null +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Poppies.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Poppies.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Poppies.imageset/Poppies.jpg b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Poppies.imageset/Poppies.jpg new file mode 100644 index 00000000..e9569b8d Binary files /dev/null and b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/Poppies.imageset/Poppies.jpg differ diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/hands_solid.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/hands_solid.imageset/Contents.json index d637a519..81e51480 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/hands_solid.imageset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/hands_solid.imageset/Contents.json @@ -6,8 +6,13 @@ }, { "idiom" : "iphone", - "scale" : "2x", - "filename" : "hands_solid@2x.png" + "subtype" : "retina4", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "hands_solid@2x.png", + "scale" : "2x" }, { "idiom" : "iphone", @@ -16,8 +21,13 @@ }, { "idiom" : "iphone", - "scale" : "3x", - "filename" : "hands_solid@3x.png" + "filename" : "hands_solid@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "subtype" : "retina4", + "scale" : "3x" }, { "idiom" : "ipad", @@ -25,8 +35,8 @@ }, { "idiom" : "ipad", - "scale" : "2x", - "filename" : "hands_solid@2x~ipad.png" + "filename" : "hands_solid@2x~ipad.png", + "scale" : "2x" } ], "info" : { diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline.imageset/Contents.json index 5ee0f5cc..c45f4313 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline.imageset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline.imageset/Contents.json @@ -6,8 +6,13 @@ }, { "idiom" : "iphone", - "scale" : "2x", - "filename" : "left_hand_outline@2x.png" + "subtype" : "retina4", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "left_hand_outline@2x.png", + "scale" : "2x" }, { "idiom" : "iphone", @@ -16,8 +21,13 @@ }, { "idiom" : "iphone", - "scale" : "3x", - "filename" : "left_hand_outline@3x.png" + "filename" : "left_hand_outline@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "subtype" : "retina4", + "scale" : "3x" }, { "idiom" : "ipad", @@ -25,8 +35,8 @@ }, { "idiom" : "ipad", - "scale" : "2x", - "filename" : "left_hand_outline@2x~ipad.png" + "filename" : "left_hand_outline@2x~ipad.png", + "scale" : "2x" } ], "info" : { diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline_big.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline_big.imageset/Contents.json index 0e022251..8d57a337 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline_big.imageset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_outline_big.imageset/Contents.json @@ -6,8 +6,13 @@ }, { "idiom" : "iphone", - "scale" : "2x", - "filename" : "left_hand_outline_big@2x.png" + "subtype" : "retina4", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "left_hand_outline_big@2x.png", + "scale" : "2x" }, { "idiom" : "iphone", @@ -16,8 +21,13 @@ }, { "idiom" : "iphone", - "scale" : "3x", - "filename" : "left_hand_outline_big@3x.png" + "filename" : "left_hand_outline_big@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "subtype" : "retina4", + "scale" : "3x" }, { "idiom" : "ipad", @@ -25,8 +35,8 @@ }, { "idiom" : "ipad", - "scale" : "2x", - "filename" : "left_hand_outline_big@2x~ipad.png" + "filename" : "left_hand_outline_big@2x~ipad.png", + "scale" : "2x" } ], "info" : { diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_solid.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_solid.imageset/Contents.json index 34f0812e..72a56937 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_solid.imageset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/left_hand_solid.imageset/Contents.json @@ -6,8 +6,13 @@ }, { "idiom" : "iphone", - "scale" : "2x", - "filename" : "left_hand_solid@2x.png" + "subtype" : "retina4", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "left_hand_solid@2x.png", + "scale" : "2x" }, { "idiom" : "iphone", @@ -16,8 +21,13 @@ }, { "idiom" : "iphone", - "scale" : "3x", - "filename" : "left_hand_solid@3x.png" + "filename" : "left_hand_solid@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "subtype" : "retina4", + "scale" : "3x" }, { "idiom" : "ipad", @@ -25,8 +35,8 @@ }, { "idiom" : "ipad", - "scale" : "2x", - "filename" : "left_hand_solid@2x~ipad.png" + "filename" : "left_hand_solid@2x~ipad.png", + "scale" : "2x" } ], "info" : { diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline.imageset/Contents.json index 57a7564b..811a34fc 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline.imageset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline.imageset/Contents.json @@ -6,8 +6,13 @@ }, { "idiom" : "iphone", - "scale" : "2x", - "filename" : "right_hand_outline@2x.png" + "subtype" : "retina4", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "right_hand_outline@2x.png", + "scale" : "2x" }, { "idiom" : "iphone", @@ -16,8 +21,13 @@ }, { "idiom" : "iphone", - "scale" : "3x", - "filename" : "right_hand_outline@3x.png" + "filename" : "right_hand_outline@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "subtype" : "retina4", + "scale" : "3x" }, { "idiom" : "ipad", @@ -25,8 +35,8 @@ }, { "idiom" : "ipad", - "scale" : "2x", - "filename" : "right_hand_outline@2x~ipad.png" + "filename" : "right_hand_outline@2x~ipad.png", + "scale" : "2x" } ], "info" : { diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline_big.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline_big.imageset/Contents.json index 9d96de4c..de2ffc33 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline_big.imageset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_outline_big.imageset/Contents.json @@ -6,8 +6,13 @@ }, { "idiom" : "iphone", - "scale" : "2x", - "filename" : "right_hand_outline_big@2x.png" + "subtype" : "retina4", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "right_hand_outline_big@2x.png", + "scale" : "2x" }, { "idiom" : "iphone", @@ -16,8 +21,13 @@ }, { "idiom" : "iphone", - "scale" : "3x", - "filename" : "right_hand_outline_big@3x.png" + "filename" : "right_hand_outline_big@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "subtype" : "retina4", + "scale" : "3x" }, { "idiom" : "ipad", @@ -25,8 +35,8 @@ }, { "idiom" : "ipad", - "scale" : "2x", - "filename" : "right_hand_outline_big@2x~ipad.png" + "filename" : "right_hand_outline_big@2x~ipad.png", + "scale" : "2x" } ], "info" : { diff --git a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_solid.imageset/Contents.json b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_solid.imageset/Contents.json index 20b2f8aa..d0c48696 100644 --- a/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_solid.imageset/Contents.json +++ b/Testing/ORKTest/ORKTest/Resources/Images.xcassets/right_hand_solid.imageset/Contents.json @@ -6,8 +6,13 @@ }, { "idiom" : "iphone", - "scale" : "2x", - "filename" : "right_hand_solid@2x.png" + "subtype" : "retina4", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "filename" : "right_hand_solid@2x.png", + "scale" : "2x" }, { "idiom" : "iphone", @@ -16,8 +21,13 @@ }, { "idiom" : "iphone", - "scale" : "3x", - "filename" : "right_hand_solid@3x.png" + "filename" : "right_hand_solid@3x.png", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "subtype" : "retina4", + "scale" : "3x" }, { "idiom" : "ipad", @@ -25,8 +35,8 @@ }, { "idiom" : "ipad", - "scale" : "2x", - "filename" : "right_hand_solid@2x~ipad.png" + "filename" : "right_hand_solid@2x~ipad.png", + "scale" : "2x" } ], "info" : { diff --git a/Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m b/Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m index 9f25c5fa..d9b1cb63 100644 --- a/Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m +++ b/Testing/ORKTest/ORKTestTests/ORKJSONSerializationTests.m @@ -376,6 +376,7 @@ ORK_MAKE_TEST_INIT(CLCircularRegion, (^{ @"ORKTextAnswerFormat.spellCheckingType", @"ORKInstructionStep.image", @"ORKInstructionStep.auxiliaryImage", + @"ORKInstructionStep.iconImage", @"ORKImageChoice.normalStateImage", @"ORKImageChoice.selectedStateImage", @"ORKImageCaptureStep.templateImage", @@ -617,6 +618,7 @@ ORK_MAKE_TEST_INIT(CLCircularRegion, (^{ @"ORKConsentSection.customImage", @"ORKInstructionStep.image", @"ORKInstructionStep.auxiliaryImage", + @"ORKInstructionStep.iconImage", @"ORKActiveStep.image", @"ORKSpatialSpanMemoryStep.customTargetImage", @"ORKScaleAnswerFormat.minimumImage",